diff --git a/HISTORY.txt b/HISTORY.txt index f1c9e4b7..af0d8df8 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,3 +1,6 @@ +3.5.2: + - Vendor all the things! + - get-pipenv.py. 3.5.1: - Basic Windows support! 3.5.0 diff --git a/NOTICES b/NOTICES new file mode 100644 index 00000000..3e4f766f --- /dev/null +++ b/NOTICES @@ -0,0 +1,3 @@ +The contents of the vendor directory are subject to different licenses +than the rest of this project. Their respective licenses can be looked +up at pypi.python.org. \ No newline at end of file diff --git a/Pipfile b/Pipfile index e07bbfda..69fbbdf8 100644 --- a/Pipfile +++ b/Pipfile @@ -4,19 +4,7 @@ mock = "*" Sphinx = "*" [packages] -click = "*" -crayons = "*" -toml = "*" -"delegator.py" = ">=0.0.6" -requests = ">=2.4.0" -requirements-parser = "*" -parse = "*" -pipfile = "==0.0.2" -click-completion = "*" -psutil = "*" pew = ">=0.1.26" -blindspin = "*" -"backports.shutil_get_terminal_size" = "*" [requires] python_version = "2.7" diff --git a/Pipfile.lock b/Pipfile.lock index 2d0da571..f96d0e57 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,80 +1,20 @@ { "default": { - "crayons": { - "version": "==0.1.2", - "hash": "sha256:6f51241d0c4faec1c04c1c0ac6a68f1d66a4655476ce1570b3f37e5166a599cc" - }, - "requirements-parser": { - "version": "==0.1.0", - "hash": "sha256:fee2380a469ffe4067bc7f0096a6fcfb27539da7496fae12b74b8d5d0f33a4ee" - }, - "requests": { - "version": "==2.13.0", - "hash": "sha256:1a720e8862a41aa22e339373b526f508ef0c8988baf48b84d3fc891a8e237efb" - }, - "blindspin": { - "version": "==2.0.1", - "hash": "sha256:31c4e93d4ae2ef6765e3c42460456814c17addd5add8298dced21fe9dc50f496" - }, - "Jinja2": { - "version": "==2.9.5", - "hash": "sha256:a7b7438120dbe76a8e735ef7eba6048eaf4e0b7dbc530e100812f8ec462a4d50" - }, - "packaging": { - "version": "==16.8", - "hash": "sha256:99276dc6e3a7851f32027a68f1095cd3f77c148091b092ea867a351811cfe388" - }, - "MarkupSafe": { - "version": "==1.0", - "hash": "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" - }, - "colorama": { - "version": "==0.3.7", - "hash": "sha256:a4c0f5bc358a62849653471e309dcc991223cf86abafbec17cd8f41327279e89" - }, - "pyparsing": { - "version": "==2.2.0", - "hash": "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010" - }, - "click-completion": { - "version": "==0.2.1", - "hash": "sha256:079fb138887d4de12a0b7fbebf8d92d396b7c1a9c49f63475d9f3909d2588976" - }, - "click": { - "version": "==6.7", - "hash": "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d" - }, - "appdirs": { - "version": "==1.4.3", - "hash": "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" - }, "virtualenv": { "version": "==15.1.0", "hash": "sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0" }, - "parse": { - "version": "==1.8.0", - "hash": "sha256:8b4f28bbe7c0f24981669ea92b2ba704ee63b5346027e82be30118bb5788ff10" - }, - "pexpect": { - "version": "==4.2.1", - "hash": "sha256:f853b52afaf3b064d29854771e2db509ef80392509bde2dd7a6ecf2dfc3f0018" - }, - "delegator.py": { - "version": "==0.0.8", - "hash": "sha256:603c1c1c76b1340520d95a1e768cf2d3a8df7b3c15a1eb9df83aac29b8d025a4" - }, - "pythonz-bd": { - "version": "==1.11.4", - "hash": "sha256:30fa48c5b542e1ebfca167f10699b149768dd18a90185d98b8a766636b6343b9" + "pew": { + "version": "==0.1.26", + "hash": "sha256:259ac7a4603fe41b1fa950f30b2e4ccf4a23f7c89be2c34e0a4cec176c3ec581" }, "virtualenv-clone": { "version": "==0.2.6", "hash": "sha256:6b3be5cab59e455f08c9eda573d23006b7d6fb41fae974ddaa2b275c93cc4405" }, - "pew": { - "version": "==0.1.26", - "hash": "sha256:259ac7a4603fe41b1fa950f30b2e4ccf4a23f7c89be2c34e0a4cec176c3ec581" + "six": { + "version": "==1.10.0", + "hash": "sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1" }, "backports.shutil_get_terminal_size": { "version": "==1.0.0", @@ -84,33 +24,29 @@ "version": "==1.0.1", "hash": "sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f" }, - "ptyprocess": { - "version": "==0.5.1", - "hash": "sha256:464cb76f7a7122743dd25507650db89cd447c51f38e4671602b3eaa2e38e05ae" + "packaging": { + "version": "==16.8", + "hash": "sha256:99276dc6e3a7851f32027a68f1095cd3f77c148091b092ea867a351811cfe388" }, - "six": { - "version": "==1.10.0", - "hash": "sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1" - }, - "psutil": { - "version": "==5.2.0", - "hash": "sha256:2fc91d068faa5613c093335f0e758673ef8c722ad4bfa4aded64c13ae69089eb" + "pythonz-bd": { + "version": "==1.11.4", + "hash": "sha256:30fa48c5b542e1ebfca167f10699b149768dd18a90185d98b8a766636b6343b9" }, "shutilwhich": { "version": "==1.1.0", "hash": "sha256:db1f39c6461e42f630fa617bb8c79090f7711c9ca493e615e43d0610ecb64dc6" }, - "toml": { - "version": "==0.9.2", - "hash": "sha256:b3953bffe848ad9a6d554114d82f2dcb3e23945e90b4d9addc9956f37f336594" - }, "setuptools": { - "version": "==34.3.1", - "hash": "sha256:9349b47bcdef2e695065791260f9416b7aae8739fd30c6849f807bce5281d046" + "version": "==34.3.2", + "hash": "sha256:6483f8412313ec787fa71379147a4605d3b1cc303c3648d02542a9160d3db72b" }, - "pipfile": { - "version": "==0.0.2", - "hash": "sha256:f7d9f15de8b660986557eb3cc5391aa1a16207ac41bc378d03f414762d36c984" + "pyparsing": { + "version": "==2.2.0", + "hash": "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010" + }, + "appdirs": { + "version": "==1.4.3", + "hash": "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" } }, "develop": { @@ -187,8 +123,8 @@ "hash": "sha256:a7b7438120dbe76a8e735ef7eba6048eaf4e0b7dbc530e100812f8ec462a4d50" }, "setuptools": { - "version": "==34.3.1", - "hash": "sha256:9349b47bcdef2e695065791260f9416b7aae8739fd30c6849f807bce5281d046" + "version": "==34.3.2", + "hash": "sha256:6483f8412313ec787fa71379147a4605d3b1cc303c3648d02542a9160d3db72b" }, "requests": { "version": "==2.13.0", @@ -210,7 +146,7 @@ "python_version": "2.7" }, "hash": { - "sha256": "4e215f83ada415726a064a01ad5bdd5daf169d1ef41623b1c05e6cd8fe1f0fc5" + "sha256": "a1ebdaccf29fc67e8b827cd7a04d0cf7a453baeae55508b930b4e4af2e4c47c5" } } } \ No newline at end of file diff --git a/get-pipenv.py b/get-pipenv.py new file mode 100755 index 00000000..75e31d29 --- /dev/null +++ b/get-pipenv.py @@ -0,0 +1,20068 @@ +#!/usr/bin/env python + +# Note, this script is based off of https://bootstrap.pypa.io/get-pip.py +# +# Hi There! +# You may be wondering what this giant blob of binary data here is, you might +# even be worried that we're up to something nefarious (good for you for being +# paranoid!). This is a base85 encoding of a zip file, this zip file contains +# an entire copy of pip. +# +# Pip is a thing that installs packages, pip itself is a package that someone +# might want to install, especially if they're looking to run this get-pip.py +# script. Pip has a lot of code to deal with the security of installing +# packages, various edge cases on various platforms, and other such sort of +# "tribal knowledge" that has been encoded in its code base. Because of this +# we basically include an entire copy of pip inside this blob. We do this +# because the alternatives are attempt to implement a "minipip" that probably +# doesn't do things correctly and has weird edge cases, or compress pip itself +# down into a single file. +# +# If you're wondering how this is created, it is using an invoke task located +# in tasks/generate.py called "installer". It can be invoked by using +# ``invoke generate.installer``. + +# Note, this get-pip.py installer is modified to meet pipenv's needs. + +import os.path +import pkgutil +import shutil +import sys +import struct +import tempfile + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY3: + iterbytes = iter +else: + def iterbytes(buf): + return (ord(byte) for byte in buf) + +try: + from base64 import b85decode +except ImportError: + _b85alphabet = (b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + b"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~") + + def b85decode(b): + _b85dec = [None] * 256 + for i, c in enumerate(iterbytes(_b85alphabet)): + _b85dec[c] = i + + padding = (-len(b)) % 5 + b = b + b'~' * padding + out = [] + packI = struct.Struct('!I').pack + for i in range(0, len(b), 5): + chunk = b[i:i + 5] + acc = 0 + try: + for c in iterbytes(chunk): + acc = acc * 85 + _b85dec[c] + except TypeError: + for j, c in enumerate(iterbytes(chunk)): + if _b85dec[c] is None: + raise ValueError( + 'bad base85 character at position %d' % (i + j) + ) + raise + try: + out.append(packI(acc)) + except struct.error: + raise ValueError('base85 overflow in hunk starting at byte %d' + % i) + + result = b''.join(out) + if padding: + result = result[:-padding] + return result + + +def bootstrap(tmpdir=None): + # Import pip so we can use it to install pip and maybe setuptools too + import pip + from pip.commands.install import InstallCommand + from pip.req import InstallRequirement + + # Wrapper to provide default certificate with the lowest priority + class CertInstallCommand(InstallCommand): + def parse_args(self, args): + # If cert isn't specified in config or environment, we provide our + # own certificate through defaults. + # This allows user to specify custom cert anywhere one likes: + # config, environment variable or argv. + if not self.parser.get_default_values().cert: + self.parser.defaults["cert"] = cert_path # calculated below + return super(CertInstallCommand, self).parse_args(args) + + pip.commands_dict["install"] = CertInstallCommand + + implicit_pip = True + implicit_setuptools = True + implicit_wheel = True + + # Check if the user has requested us not to install setuptools + if "--no-setuptools" in sys.argv or os.environ.get("PIP_NO_SETUPTOOLS"): + args = [x for x in sys.argv[1:] if x != "--no-setuptools"] + implicit_setuptools = False + else: + args = sys.argv[1:] + + # Check if the user has requested us not to install wheel + if "--no-wheel" in args or os.environ.get("PIP_NO_WHEEL"): + args = [x for x in args if x != "--no-wheel"] + implicit_wheel = False + + # We only want to implicitly install setuptools and wheel if they don't + # already exist on the target platform. + if implicit_setuptools: + try: + import setuptools # noqa + implicit_setuptools = False + except ImportError: + pass + if implicit_wheel: + try: + import wheel # noqa + implicit_wheel = False + except ImportError: + pass + + # We want to support people passing things like 'pip<8' to get-pip.py which + # will let them install a specific version. However because of the dreaded + # DoubleRequirement error if any of the args look like they might be a + # specific for one of our packages, then we'll turn off the implicit + # install of them. + for arg in args: + try: + req = InstallRequirement.from_line(arg) + except: + continue + + if implicit_pip and req.name == "pip": + implicit_pip = False + elif implicit_setuptools and req.name == "setuptools": + implicit_setuptools = False + elif implicit_wheel and req.name == "wheel": + implicit_wheel = False + + # Add any implicit installations to the end of our args + if implicit_pip: + args += ["pip"] + if implicit_setuptools: + args += ["setuptools"] + if implicit_wheel: + args += ["wheel"] + + # Pipenv modifications here. + args += ["pipenv"] + + delete_tmpdir = False + try: + # Create a temporary directory to act as a working directory if we were + # not given one. + if tmpdir is None: + tmpdir = tempfile.mkdtemp() + delete_tmpdir = True + + # We need to extract the SSL certificates from requests so that they + # can be passed to --cert + cert_path = os.path.join(tmpdir, "cacert.pem") + with open(cert_path, "wb") as cert: + cert.write(pkgutil.get_data("pip._vendor.requests", "cacert.pem")) + + # Execute the included pip and use it to install the latest pip and + # setuptools from PyPI + sys.exit(pip.main(["install", "--upgrade"] + args)) + finally: + # Remove our temporary directory + if delete_tmpdir and tmpdir: + shutil.rmtree(tmpdir, ignore_errors=True) + + +def main(): + tmpdir = None + try: + # Create a temporary working directory + tmpdir = tempfile.mkdtemp() + + # Unpack the zipfile into the temporary directory + pip_zip = os.path.join(tmpdir, "pip.zip") + with open(pip_zip, "wb") as fp: + fp.write(b85decode(DATA.replace(b"\n", b""))) + + # Add the zipfile to sys.path so that we can import it + sys.path.insert(0, pip_zip) + + # Run the bootstrap + bootstrap(tmpdir=tmpdir) + finally: + # Clean up our temporary working directory + if tmpdir: + shutil.rmtree(tmpdir, ignore_errors=True) + + +DATA = b""" +P)h>@6aWAK2mm&gW=RK-r8gW8002}h000jF003}la4%n9X>MtBUtcb8d8JxybK5o&{;pqv$n}tHC^l~ +I+Mavrq?0()%%qLSNv=2JXgHJzNr)+u1xVRS+y8#M3xEJc+D&`xG$ILLcd^)g_Juxq^hK-W7fVro!OK +0X56!kJCu>>lSemZerjK`FeKt4O?bX9-iiWDY7!DYHK31t|U{{> +PE#tZP_+VteGhH)eTGzMZy!aHJ(Q?6Cjc(3MQ0lIm@hktf`o4axNvVCTc)Ts4@VJ>@!hh%K`|2$iKE+ +HHx+6sw#7#MJW!3g|Y$%N)ur)tC3;}#CBEQ7CdI~xY=+?Ot(T=34r+9E$`%6N}j>;=NFf=Z&^bu!zEv +3t>Ua&1Gxq!8;Ps7soN%ES($^#>_e*>Ru`El;Z0c`kR05XmE3{WT9s{ZCofrE;qGp;vO#hcs@DjeDR$ +tn@v;IglI6VSWzNghfplGqI!0gHwP<*5k}E|s-0tgq2{VgAu^rc%*@ +7HRg@?*fSPs9ypVK;PZfg`L*{@Wh4H}=)J&0S$#2!{sXR907wMxwCB>Zm0$&8dG^t{{SFIu9BwcKPai +iS)37*53oHqWOqTV)O3RPrz%ERGmE0Tun4O(ssPA=8(oYCvxpzPymKk}-Q$?RIdE=IK(@bmxe)jVQYH +8{VWs)8KiU3x%fE5{sAyYgujXSqq0M!Jcq(%y4NcRLa4k(bC--&}_#|G%=iwT(weU1)OKQ+;gdjz%u) +oWwP6Kw|to?PIw?Km1kAC7Ms_kh)WuY*}FOiLCVc@zRudBQ9tsceu3uNfZ`pomDWvf`>KU^QgE|jC3f +JeGPP6hUu>U2ZL8-0vz>6l;DW>Cpc;OqR~k!*C(#5^E>jBZX2(m7SL-6X;oqX)fNgKHx<25fw`lciam +T?0Sq;<*0efo>>~_mb!wtQ8FET)G{S3%GLx;TuGy_0I*8^0_3ZXQ@aNJf0K2y8VP7S+U1FD)Lc1YZU5 +_=?sZ~~HXI3ze#a`M|s-Y_t#noGnybn*-wS~M*gQeu&v6y8yuxLY!d!A +F!&;`Rs^bRcsWT^vka6lXVZTrPm;4Ks2igbSlrx(sRT^p6}=17w9Ix8?jmITqsTRyjGrANWtnsTD|j$ +Y4h<5(QWgT)wb!BhII2*G}|zk1yNsG$GkHLdlf5Gzaat{Tc>$@p` +a+TwY7Wli;y;&R%LORzm+XNlE7>Vmn1j*;EP+Vbf#*@tWz5o0+$?;>TN2)pj76eCD51u1o>jxO7Rd+T +^~TVJZ5V=f+fUt3~2+X?Q3%F77oSob@jkBylRQqf|H}cxNlq|euM|+Co9)Srn2x(&;r3@IQS4AF!H7F +o8r-xn-D4>d|PI6qlSXmJ;9W|=O@}p6HPuvOHX05>OET{SlFW?YMVB^bOj7$3}o2vCc*b=Na9ht-RL`cQj!G22J9&fIo^m$3 +29+HJ>nF|s8yA0n&;d{IKJHp=j(V~BT0>~4G)GPEMc(VQAuvRl`;M6?1>952}1Ot5I~#MYk0Kxxi3Ah +q0z)s{+ML0+{{$39}{osGDzV+%G3gnJXTS9DXfMe;)R!F^lZ>b%Fq4=Wdfk4}wCzJh`hBBYO~_dq4)E +TcmM7`3(}e7h%A3)V?v$2PKRYqb~CG)@>9bn8D8{C!mRaF*M5$oJ*5h{7A4fUSurLlk|Ge9Dj35F+Yz8R+C*ftDqF;u_LZHS<>zfUP3#rrKI%~GDOrn(Geb3oa;V;xkn21A-6!o~;5)IrK3&>Lg$n +YELmLl9n0XsGIFkW7P7W+cQbn<5G`uwYfk^6+2P*{9yc*!NCRzAqXJB#nGfJ}B!NvFOOhTfndqX%NMl +ise-9(t=Sm&iY#gz#t1Fx4SUsz^%mm(E_;OVNHrzq3|yB|Hrue#yvyr>(@~yJ^SpJ4 +OF^(;kKyNZ_T@JUlux=BG5cWr9_}dO9aCTQY^g^RyvVq;_ugniS6F79aaVdkZH1IkocB$7G|e~a`MGK +!XEswYXIAV1vyQFCC0F2wxgx`n?t@Ug!osc^vn#KqIIKVLe-1_p#*HV3aVasg00W +>1$}ndUjF>@ZB-R2u;rQ+EVZ$_M+hh_d^Rb?NSN{|#E +&S)jskXLv=z{g*0oLz4Y%3MIH@hdj)++w_Ub=yY}Mo-b#g03!^1v$ME6ew7%D``6|eh~C_r=)A@uzIJ +N=ON&A!*ch(O)=3CM}bncF8OaorQ9gI$?Nhg|T|4M#Y5=A{BwMaNvm<)f~Zvmpdn?c=+yAoeAhSb@87 +TMqdtzY}KDV&{B5+UyK14KGjFsSQCzTOv4hWZCpoO%X5b5|_B(AtRH1E(COJCKK$k!;-T@)v_JO?!To +)%RJsP6QFy)qYW9u%;pS0F>J1x>2t;K8GzcH^9$#>PBA1lHjmwg*|^KH_x<*S +=isHyhr3Ego`XEQrC#p5F9cRF;-Fkfs^?iV@3$}~Bb~8GHljaVSWu|(Mo1&i*{s&u@{2 +vB>ipRBhNi?@MIwmShkyR`VyPj6zz!LsnP`&@S*HQQ=7(&M}FoqXi;>q5?XVgA32$|3zK777d8C`@`` +Q>eL*?-`xmZezko^TratE%IrW;s|5rr@c=|$CA9;DDD_s0Y6IRO)eAR$E8qZkc2N%#@nudxO>zHZlhN +2jBVZNHhBtEQG^Dy!P2rftr_IL518vqjU9{%mWwnSm9`zqI)V0jtcq>J>%|@n$Up{%CyZ>kbt$0eh+HnBqyweJn0Mr=_SB26a5@YX!F%-Jxjf(olZ*omrcHoC;?4Se^vyEI1TC~oScxJA +ydY*9ir{^bUp|3fq&=IMai&S)*AlSmHC7Z!cjNpdQ`)7^W##r$<8wz4V*m_)V>32#VR*ohWuXOIH= +sMUKJ;SFsX7PGyqBJzH9agmUcR4tm!(8=?0d&g_`7e6Mm)jWmUWC$m06TLbvadj&v +W2y^Z;Zu-6cO2gdsaIxnc_KJlF8^$0_h`_YKC!7uSl|V7|pGHx0EY)4x)chSpS2a^%2D$kE08mQ<1QY +-O00;m!mS#yyNu*^n0RR9<0ssIH0001RX>c!JUu|J&ZeL$6aCu#kPfx=z48`yL6qa^qhepR4X$Ov65% +(yx$r_O+A$C>v?Xk0z4RXq#_nz%vY>qQ1WfxkqQ3~9gVkXcZ82v&-nOOFrzI{72-zy%~$-fkObx$UHf +Pxf%%rxUd8a|66~GLQ3R8vL7cRBF~PDAlJ+)moR4V01a?*}x!0kg`h%(L#G~Xb*s9h+(`5M8UCb&3ZG +qcoGOQp;VW#N-&4rFgQZvZ8g0VLYnU307k(&=&*eVS1J1Pdg6a5y1w?^{XcI6_WR=6a(m`zGIdXf614 +yQS7FS(g!rYKD_V)ETsH=luY{RzM;)7bdFi;y4^T@31QY-O00;m!mS#zU7>o5o4FCX!E&u=$0001RX> +c!MVRL0;Z*6U1Ze%WSdCeMYkJ~o#`~C_-MPNDSC{2p%hXssYvX9niy1Up%+rwf(&=PH{ktLOsyz49S- +*1KwiJ~NLdg$W}Br8!f!{NM#WDo@JndIc8*lt;#kT_#f&ImpVp0SF<-=eP4oXa2xj#i@B5=vKfRSQlj +Nw;MoD#Dhs$m)ty{eE<0#WEu?*t`{uDItC9)H?fWAWIpD}6Jz1HSc9wXX0B~C5viTIHdBUG +8z!i%>vNb=)LD9lwMa&eMg%fp-Q_vdW=q?pi%`%?vT9l-C%(H?e4dt}F;Zg#T7KT5?yzI~o-?PLBaz+ +-ptXP(*na_kM#Ejg*tp4B;Iq);Y4EmMeyR@j~`#Q~%(^RP8X)C8FF197BNLTnYN#p9I$XDsQg87Jbcsty96bJg;U%%|k^yG|c|#i^F%)%Dqri_5zk`u=Y5 +;gp^(t_{x7w4E0$I%_6OcqzCxkr`R@ik6~S&q$6d&C>sH3PRm@xRH@=yYK{71_J}~(Fov0iSj3d0bl5 +j3$!U3Z+QIi=;(-25FWVIoZL^0?k5j0j+23^=2oW>aQQ)vg_P!O3$6%uaHO2q8ckR%f8lX8JyuddAi% +#Ua<1NM36A0pY|;c)03+utlX?gyqp}j5Z6%C{0e`BFU%v*|1+^uxoM1+}V_b*;_(0r*uOLpOd0J5#N} +jD|B!w7(0+_2A3}5)uhDbj?!Ysda{9&TloE#IR5UH20!%R?B@O|<^k{5D9UXai#Fr3ab8ZLe6p{=Zz0 +QaDkhdw4t61o8hszVXrtL1o5IHzSBpS{mu?XgHL0R=^AQpA*cfL3MzWglCJPe;w8B4HeQKH$sY%a@Im +r!CqS)>tHwo1)GV0?Q*N$dalc)h3nZova}dlnp8jssU;&3pJo;RBC8e9>uIoE9FPww97BVbCe<)mrVk +ZCh;v&4xL5Ky7P6G@D5n6HXJ-R=YnOH{RRTY?KEu$iMH$`H#($>aM+Q&18L}LsIGoo4x10tA+1DcH=X +G$Tdu<_F|t#sGmUW@!^RBqaV1hN=jgICQl(oCKB(RtUoyC`);48%D`OCC=3y`Ibi-X($O!*NzZ7X6T2 +UxmNGPC>U{h6PFrD`3q$|<`CmdX)jWvy=y3(`@G=Gs&^C*G8N>R|X>=Xu|O9-+okFh}66ta?Y3tNd=f +&=MMS6_}XeFx5vaS{V0MDLirTGluqiHhcEW;JNDL2wt#MRn|1hZ27TQ9fPmwUsxZ1C!p|e1Q5Zg*-wK +B3-4Bl=$FW3W|3=2jIeBy3(__YWJcGG{pWaEqtGbI2NKJi8wWB^_URR<3Y +k(YH2p-{dA+jYpulE)CMz&?UkuYgp5g@feKK_+}zuaUZ{B^X(y8IM|vfvKtGPW>HHD`0om(?PS#Zy@? +jPuTVEz|`E}wr{$w8YHP?%ZyY0luC3ds^x+nK2YNYu$oGL9f%;%9AONxv50hT?>TaIT~w;=1pnsG2ms?IwmnX%0kp6#2wo?A_d2h$Yz#Ny +8QTNmt*H4QDJQy$#J|$z_V$T*hsPPNrA~ZrF|!Wldfl)Wj?SumPZ%M3}gxDi_JJs5WYkiS8ibV(FOcW_Za2SDQ +Z4Bc|%N4c4B3{?DD!NUIm}C3Zet!gi{Y?=28}>3im9d;*k`35k+2 +;R1ySivda|oxZ7Mj^&?cpG%G6cWQ@_*Ce#SKK5e#eX|QM)LLHAkDsArvJQr~)5x3l%DFiO;pjVDu}Gb +%%>j-6|P(=Fg!iT=>gR6bDfwtsr^tJBez(8|VKh`DgY(gQp+$$S1 +fH5==&@-?t@ZG0YW*kkiF4ux3ob1u|G-5>F5q;7?4C|y=sRMz>G|Pr)C88)T8%nG#s{{V;?E6L<@a@; +9?buIR4CAfn?d9p^F{#8JtJ^hKO&qMGgusvPif0Jzwn3~n+P-n{wXjo|82T!~B`}S6K&+4v&v&T+*5P +eaWQnF74R$`Z*XwGrrEx#GT3peKOS-tYy1Sh`;BMWU$sj3J`br87AG{u>clPt*=JtlZJGot4UTC6Z(% +mlVP#f;r%&`C({O;HbRf`q$4EO=f%m5}t?Uf^mv{DT;R03JHhv*6lhw$b1ZrBu$o%e*(fv!x2wq+Jy5YzVOwQZXP{$~?U54d`oj!W%3HE&P +^ABgo1mtGTvf2MNZ9FUp88L)Cbj&f3IdaqhXeLoPI+f~dE04L|+{rmlILcdXk<~b +p0&lacu7YiI*jeB7ESzJyOnPWV>QM3M~+au!<*UOR%y(Jf;;bxgmbyz}9{z}H56R +Dl9dT#o@hb?KJ9Js +nxpgPK-f8rw`apPk{oN~e_?b@<1L3;L}yU7GhCE4YSlfv2WeHI_pXzSb5gZZ7cdTAZBRe6gqdy+Fsbm +2s#7CJad_{o<(gFL*l^gMTae*Tt$Nvuqw3uG#1>=5efWP2?nHOR{@BiZaCxvHyM +VF#?l{_Ks%H2Nh_|ok(%Xbe$ecUVJtCH8im~DKH)U;-Rv51SEMZvs;{qA{km&mhbQiZrp3c}X(%&RgsKik=5 +UnXXOXu2&h8Xrz*Z2NpH+{w{dmi|EL^a@*Lo&he@V~jQ1y)Vet5@dxs|}OTMnZ!xAzZ5XiEizZlu9Zy +XxFpMq2k!+4afU_>JZl{M0~DnUuR~V_ZmL^q07v`Fx +0iVsk2kZ>AISVhm30$Ds&jM8VH{4SBodsn-__A5s2JF^sPO1k{Q_a;}$-_o$lj0GCGejTjf#l(%M6Dg +>7LH)cwG@snz2^)JpG^w9QKLfpgZ++46J)sB#@xy-ejXGpMRYOvF7nJJ;DTHn8=;}#?*f+<^0D`z{mdb^RlwdZ-?#AkkffWC`D@l}Z;Yr#9i{xu@Y*t~u0f^@DFJ$KPaSxA-@kLs3 +ZDY)Qj@3TdOu`W26Kn&JP6JByWn2Gn^a>oGtduj)ARb%(|q5HXU0M8-3b%Eu>KTm*NC+NPq7qI>dP)h +>@6aWAK2mm&gW=X57{yU}&007}A000pH003}la4%wEb7gR0a&u*JE^v9BT5WIKxDo#DUqP%9NJ`i0C5 +L`7>O<4K+!-h?!J+9F#}&8|cbBy!3M94by`ulUGklRqNozZ21kSEB9L@~q<(Z*ZtJUABVnlSBiuC_A{)0gN)M*(x{6D+COf7J&1Az{S{I +7{&Mq!43Sh{kXp2s=Eq^Q|BR62rycA6bTvNIF_m|r*#cGWYZ!=g?)>J9-MKY~Vzp%RdBxFN1@J;;z<+ +mVlt63Gj&aREz-~;bShpRc0e+Ib~IWV~q;4yn3CtFXCpN2Ef(RIxFifzGtc*}KBq>9zsHF-_t4%B=7` +r(M5+(!6wX?b=6tcA|l^h%QrBedqbmR01)^?u-%o1I`sl~+uak{bsecvhg9qNi!-6;M-2!7QYP&?jQ+vyj +`6(6%BC(-d}6`NhEI8kaSW_?i&NRW-xqsoJ~LvnI7@claq=6PE9;Nt#@3QM9Wos~qS%;pY^(_FFo$J8 +9rx*@4!*k(Vk@O3(VH4NU1t~MK5+AwEs5N^7zLhS}6Mz;VYOmUEc!6Y5wE)>N;HgAq8zg19`(dZ!fEY~8|sLoY +ZDzY2-UxdjN=#DM8h4rN;SU&G@p}S1|Zq6@xr64T5 +Kd0t=VwYPA^CdtsKkzXpOr4wom=iwZ*e@?~ZA&`$YWsX~cl+x5q>Suqg+wc_-HSj}@C{3b70$keOlR^ +D;zjd;w`O&&x|(b2efQH$u=>`nY>pl{j^OrdR{?5ocOTf6_O(_q%w2%KBes1H2opf~0+j8Qk?g&J>^7 +%=F(L18$Upax8{uD%n}dFsOe-e<HS7=*(Q(v{8Un*0idAwK1RC@-u|p0x@SUhW^xlJzrK_bG9QleEVXT6^qL!l$5M; +EaejJXGCD(RYqJuO6T3Ho%&tLrgMLqg?>EuIPQ75A7YwAD339HBITZy4=$Vy8{5$L(hL +oV>FZ4ubX_{Okx(E3dvdygcSHPgC2G@0+>lQcGVUMfm5mMU{=g+1XXL-pqqT*z!o}|g)&|ZGutN@K9%(kqOXm4PDzeLR3BWWR3CHzt;261sLi3h8%GodOv}Ynu0_M`8X +4KO9AXo@oLt{CBMq@8j!f(qCJsg=a^e`;vl2?#Pkvm#kIx>tO4NgX7 +6)*}9oNTGuhtMNX2-_+MF6*CoKxu*lqxYYG{dD_t@#*#-ACuX^!dXQe42y~#TEHKRSRw3XFEO2>&2Um +ij?5xQ+Mdiv?CQuX7KhQ8E}Sc&UDDb7EDN`QoOjiu=5au_kVHZ)u=GW~J%jk6o*2lWXh-!PvJnWO(%| +(1;x}^n_A?}X0r0;Z00r904ji2{#10&f#!iZ(CvlC)0ViX`G_?!tI?09P8atItYPm77n&6_MYJFOa4k1f+<$vQnPJpV%Kk5U5Wp$ci@4ZzW%7hS!B2F%civg`r +>SETCAurYE09H^|I{RA$tW$}Q(q&odE9NsR$_w@i|V)XYlXkRSk9RQChS4L??%vA-_1kr7v&S*k->B| +cFAn+|@Zmq%1RL4pjO+ZLjH7bWdu!QnWvD3i|8$h060XH`=Ddv5ZMHmya4T!iCCOOwaJQ!ZMw+RcPL@ +!IjZ(_koEda66EISihm*j1J4r+c!*^4E9Qb2$Eg!A|`%R*7!fde-^vd7_mSF=a&NeEYTkh~2y=T|pl*qDHEd(E3n +WL)6<-C#?dW>cSlht?0A`#7+LZHwJ2I#VCTc&JW)02qy$rp!yicdcpVn+~edgi~N&cr(voIGf>Z&*HK +vqFEK1)jq-0G97>2+TFcUxDzB~g<}*mC4jo?KtK7I?{Xk$udIv0i(XH40cd95-Xp5SYKM^z0PRRyJxn +AZ=|Vli4}fFw3op^9Cd^7V*375oaQcC0^D)DDtBiL8Gzd3n(IhLN_A$J=vER0cPVs9g`c^NEUY(oxi{ +ms(*Z9Ng*>*U(x78*&#}IzIA=SL3TZ%i|yF|q&E<2fVzXNIqOYUDHRSCziq2P{jL1A;15g|L1doez +zK+5wR@x($gSQC>iV<-_^?wU$kadY-mo@_E6_*5tpw$D50Va=Zu1m*v@XQq;4E;nRHyoWLnV#{qe9hA +JW;GqKy$vo~MLj(~B5kY`yQ84<&*2c5A!QZ)LT}?}tCWX0BPG)cy^E47d<&#>W_Gxl;wUnwXQ+WAG;R +OSJh4?X-cZj^f5dI!JE<2+h{_xRvCTBSkEe<$FoPj4g!7{^S(8C`b4#uD=w5y-zxMI4eYGA(rlEObxh +{~^_ovPu-310jNh0F(<)(;VX?pVvr#k+MtEN3&go@6YWh2;MUWeJl+rx#d&CN>|`D}+tW^yS=19{nwINd07g#2`ib0*&6fJt-e&OO5T@w~J +XO7RVL`m?ShBbD&?BG8gT5)kqspZLrGO*<(7x2uURQ!w_quGV-|SJ-1c0BZjW*|0r5aDe^!l7~HmE{7 +$91za{?z5?;zz-PM?;9nD}y^Nuyhd=%=aPWk{^Bl;Vd5j0iH-ijjDtES)gVDIMCj=SDtyxEZ{fNnJCY@Y^+6;dL$c%gE^B|4>T<1 +QY-O00;m!mS#yynKB`M5&!^NKmY&{0001RX>c!NZDen7bZKvHb1ras%{yyv<2aJv{VNCs4cU9PdS(}W +hYL1`%O;ub;AXmmBr`X--iAQSw9SnyX+sEE+8vC7QL`j8= +I$mwCQT#0QvGD{0C?%#|)y&@Y<~(35V~LT31J7R#zq#Ud7&Ea1Po-U@))sL@U +KPn`6ag8Rb-58~x@?=aR%t5qrYh@3$hj%=woxg6k9gd&EwZL8bK`~q{y?srdtpJ^kL&zE2)sq6OvT;L +H#fIecX#Q#s~>Nswr^xdKFPWOq8hslP$tpELVb3S#v=iLKa}-GHWy{l)MY*u%T1GJO`fiSHn~bSumhQ +=>T{O23)OcQWjfb|thZAF;x)HMrB7?6@=3q!rd+6gdpFyg>%K29Gsz^i-9O)5-KH1k7w@jp%j?^zFm; +wzHOScKep1`$+$3vh)~cI#cYpig{oC~2`Q5v#yU}O_VktKAL8Z*Hl;n84V!{zg>&Yo$j~v5)Zxyhs0I +BeaEXw&`RMyY{nk>X@CO}l$4IGq)gk+(!hQ&25+d&hHShiN#LrMxK&(nFU^F_+q#^E)!W9;YI`?65I6kKW}=b+pOxIye +IRnH6%qDrbQ=p9c1fSwf40|y=_p8{Lt#&w1DV8>TTS($AzG~;|1>xDZ5e)O4_)X^pmWBK$mQqdK|!*iegG@uq@$Rg!?gKrr1%@R7 +A`lzs2#-HGOiMki~Yqk#L3?nJI&vOukK;tl)N{h!k=gH-5M+){!C&(NrPqp;a;Su@((QrcK?dZVH` +%vmaz`l!sK$t?0Hb$S2UG*Bx|$(BVX_in2y7s^U@CWw8M>FCJyBQ46s5)8gTcdUzlvOTB7qvRMgtOr| +5)daeH2YQPU5q0I!4hxUIW5VNw#w;Y?|eyns~;6G4)ku>HdWgsc12WYV8wI;{p{1BlQ^g22 +Mnz6H2y&}8gxYxj~IW0^A6(wONT#>9pdk`JxfmSe7F@6IrUjLbXI^dsyU3rUl|D+8KB^|yp(`rrXWbR +`5FrPS}SI93ecK0cmq{gEXaK?#ebjQzQ2C|b}FuJZ$I2Ju#4O4`|FGIA4OiSRxmDvMEcB3kR(797;;2 +yzzDPw^kcTvxpH4%p1IRgC;j&Z%oH5$v#65II`YU8-9Q7PE`<|p4mNN{Fdq&%;01<47eKPZXZjMP0^E +G_K)x7Fa3{AYXY?Jg(Lw#KPG(h?pSOoaYDQxMEc}*cTPZ}K9;_VuLLJ>zD$~m?kc?LZ?TYpejji~ID) +SVBsi(z%exm*aS{|_x{PZLuUD?!{Jc2`*+ED|2=C?7ndPnTv_{jbwKkH4q5kp6e9+nN*jvd8E+Cu3Y10ju#%7Sf&!+6`vyp+R@fBz=XJ)mEZ +FQ&{M6l08N?(PMagCop`aAX_P$Lt`3PRLDl5S)f{9+=re(7d5zpg^&ZL7fVftP&BM$0Bw_add#if(?5 +}e2HWZ4}^KpRcdV@T6Y5O}e9P7-;sIk~02nKdvGs +(lW6qoEeW4Sl?ZHvSgb8L>@>4NXCGsO!msgvPx!w%{! +hlAeE7Wck6zm#1=M$Rr)38bKKPebHo2R(E%$63A}-Iv8=DD)^4WSS#(IJdBACSS(?nPJ?|cFtI3^Ira +x!L-u$3LR162+nK7Il30xr7w2N$VycEP$sjN+AhLM@J~VOb#=e#GrQs4ck^*zZ9?19Wrsli+BNNI|Ktw5{{QgwU* +xY4i+6^JlfKG=F)d=^zf-^z-eH1KMDUD=~Ug9sB2LooH9lF^zYY@yEkSV!R;+nE^JKA}Y1f; +mfY@@YQRSC9_eV1BQrP1IxY=Mrju$G0*N!?uCh&SK;Av9-X76?Iq=K0O_M1abcg4`*w0Ckm7PcHQWy~ +Y5FHTwp_aG&&6Gc~nLJDMHQO{8*Qg3pK@r4s-&`xHUXiGzw`pO#_nT;U?f9)tX;EMsU<#mO5(!p7b*@ +D7?hiV#&iX-dQ$GpfrJTWZxU1(@dGWE)+MtoOM%Y`2_`xfqxpH}`9O%=ns=U`PxxrqDGn%LmGWG-3w6 +c(It}x_B^5KulnOl4YlYWCBN|G~%c@EcqbzFn8pk2lllr@5Ck)HjIaMvEfZX-x;(IpE%T1-k~E>CdA?0Zi +c#(e1|(`hytK_?a6Y4X7W5;G!K4M9hKcWgLiZ&M*G!{OwgV;6ix6(H#d~9CL&Yfg>>^Zw9kz1C0I6`0 +&0q^E5!%5g%q6Olqx5(;O$g9X-R*JB0T^nU~PLqw%{BclYnlf4Vxt6Bjhq4}7tO3!$d63xgB?s8HIcZHK;-Fi?3aYioZ${n={^BbVx>C$B9aqyqN_^P_#MTi}`V=ui6pJdua^$lHD?7Y7?0a&gf8ja(e +c(_0!mL1zULz_SY($=&GPAtA=jp2{syJa9;Wq*fim}>n_Slu+2 +62+RbrGoUtYDr|ei_585}IVzh@tTO41w1zeiJfFI_&0v$mlk +S4E57dv+rw%gkIA@1IKD>Vng|7LsNYD*=PZfXRZzqdOMW&^VOZKXITH4z6uy6d**T5wu9*V8j#hS`=wvpf6QI~n{$W7mU0vaILi9(xaU$C +M$7@(O+B*?_Sibrc_PW#XWYF<7W(!~sc6!Xp`qy87Jw??9C`!oP#n=}H5R5FN(NXk0+ZZuU +!KrF&>P=pr0N*e_=|9^HKn+GG_E<2{ZqOLF0UfS8K%D<~yk4H>O2%AgFIQS=Sk*M-GY?cyDs*oy?a@} +5LoUIB3~&hM`-aq~<02r|vr|G0|94xo$RjOUhEs*r(SA81>%J=%9>l3^rvvnF{)6vXhqPvxb= +@hU`)+a7HfJ40km?p(*C;)M0Q%w^-PZSt;XcPdXM7#S?L!WvT)tt~B)4;uQ9Ix-VO?ur*LrK{h>%Fsl-FR4gWHo}w}wFAo`Ld922t+NNVS> +>j}{4o+|Be$ShbdK%Tq_EoBO{DbBk2dW1lopRJY2qK8qk@Nne^b#5&c<&qeC$*F(+b}Jy??y$-8kvOA +%j#mL9@pJkObMAw|*h;K8YJh*bv&T#AQHBg`V7zK$FIyFBn9Y-RwccIH;!$e8i|9ZZG!HW#HQt1Sb}< +k!Y>|h>loS3Bi3wBl?%&`Fsp-CDzJBhm;Lu0S|Dij@1wV8aRr*X#U`+cvx6KwO}gU)BnX8^N7npoG>` +~^Fb5Cxfb#WzvJ1Qk*Cq#&ptTlKKH~1-5SqF2YaG`wm_u2vqzpk9e)A`pX`oXn%OARq!r(19p(s6a`C +d6@uYpc7{Gm5y_LPKKxw&kOW1ohU9dVv$AyX&!$Q+zcn9^EgPXws&;ZdOqV4D(j`eS!WW8!RV&?*cP9 +Iz4+SMaF0rRiqNV5T>#;DVU=MnyIA|b0-Ft^|WJD(z%ky&LS#l9QKWxj+bgHs~#MGoSuVV@@P%kup0E`C|nm5VqnM$N(C@6>A?1P(L +}lvap`41Y{DHYvFnk{pXAo0ZSlXlIxHps!`6-`%xFSzJbg$nvK7x<)}K{bx>jf(R +?e8?Aski-5Tw&@EJF}j<0iHJF_!LP0{lumQ(3KazVE0vBm-WtK3R}nVxo^f^p;Z95b1ZU4G-xk730M0 +UbGZbNV!m}mojPlVv(L<0{{GFsp2~T)P)U-+;?;ggmTwbBF(zY4Da+u&*t5H^h!D;=y9V*z7?S;09Ei +R$&#yo31P6sT`3rD(9IQLBudVhmDgpIxPxqL)^YPOpVJR9jqfllEwZr-qhgiu!5$|w3FGP2_n5Y5WfT +G#bLkXKYzwIv%oaFG^77Hg$Q9#oa3{SP?e4x96!aFTBo+RGsWC+8ObsO^9<~{=Mk0AGSMQB()?kl-p@ +V;})IRm-_W0w`nC^%~=z~RdfcM8Wml|~pjJ8Eqx=AOjWXNh%Dr~71WiNc0Ncke2?BXzitnO|oFGzi~k +>?P03YjiBH+~MjH`4paew?IO!B<^)e0_+_>K%`QVt)5H8C*nQ~VYO57R7qKMnITqJA+*886XFG9n4~U +y7>AFTz)bLCN8+eLNNMTl>!UL*Q$5uGgvf800|GJ|z-7HtL&qU-I;Q_K85yU^- +soA3e?JKl5_cf4F-8zJ==J{iUfgy>GBJ+dDZQER60OpD8cy2Lu(n9(1pm#7jh}+W+b+Lj7Eo4dR2nQL +BgQb1n@J`84`FI;ut5-;UVwzGoO6)=9pA-CePuPl%w3aKM^{PqV(jEMV8(>w9lUU%mw~*5t#Y4((~-L +W9Zf4xcBQ_ug0hi${sDq-Hv3_v>QxR#j;}7u9l^mrL_?ov&rH-ALQEvY$3Z+AOMiZNAsid{QeM&3@b3E{$Ao7I +`5L4w`y~)@vd&=fxMl|O(RaJ@$f@l<_i3R3?gGiQ$v1IwE +z7K`W0l{=>*`vnxUGvKpP2zSX|1G4mEgw-eZPPATK=t-s&N45Cw2t@ih~YMAg@YgAe@$}NeiGMJfs;- +#fwy}e#q52ZRV@4>$=KhVY|KAzB%pQ(W;tPk=hh_BX66jsMk#`zXmK%7T;1ccx@bvAo7pFfyPoDqz-Sbyxr>|d~O~oAM-L3(JIm|dw?QB +z5bE(uMm`NgwvTPD~8a7n2X*W$(6) +Ksvd6AhOXV2fgfAjA3>z8NA*^AR3!fs3026NLEKf@;KA<^ch#dm;YQKi|Nx?0vijBisQdHC>blb7C9i +fW#E`{<^IH3u3M5`L}I`byTcKwX#Xxor#|dwV?C(y+|1>HC~uUdL&cZW>uznBS&KKILbyh2On$iI$it+RO+8Q2{X?s +!Zs#b0yWs(KU}agVyveWSclo^8(;wL*)4{<(k|2{OAd}C>NLYlMAV%JFo1!LyKmjgp{}c@*;qXJ5q`UXxuQssHB42@mKY}dl +Ac9LQl@Lr)Dviy$%SYYFea>h*+dgoUZc^7e!m5AQxB>W+kbspsumkF-w~i#{OWD +9_6f5WIZ|-A4Z4(d>FyAG>LfHrr;!ZM1ri`H5*AO`OKC0}8nYyhtSBn4VT +J2!x>gZZ1TP$;Sh>4Hh)T^KhJtbB25&PEN%5*&Bj7KDJPHbut8ie!HhfP-Jnxu|XSeoq?efs3ZWn*;? +x6<)Q)sP)HCIg}jypbzJ0SS~xxNr`HY890YfM{M!rL6GWl>OgNuJuu(jUf3ET}^2R!cJsaIl(9jUKpi +=vTcbI+}Y5y%;)d%8Pg&i6x{s_`k{U0p%XUcul5ZkS8Aq_d$2=QdO!W{kVVKaDeAY6rJIp?r +*pFm6{av^K1Q!)R!dPIt#su186Q6fn;t?I>Y1D +$U4&xJ8LE@`(Bbu2AoGWSb%M6ThHUC+;*WziF=(;0Et+V=O#u9dkCTo+`XKtiwH*8e=(>kLfCbYZ0cN ++#%iaj*qxq)wf!LM|#8W95-T>UQ6^%looWLnqbd?t7z_-=xYcYSj6P6btK=`vk@goKAN8JVs23l_2XyW~j$-x%BM*xc{IBB;YUcDP#~@jfE4fuC=%8y3LtAHFq)Le&U@7zOs&$%|)})V&sSm_p`vuIR +1W1)PNfLo}TucQxhU*O)J`A>_8orM0TUcK19$ +Mzvzv^o8^zPA=?bx1~8rla&Ogw!&+{IT+d{d0laxF(Z$TuqEiaG{fQnk=I?P$zI!zKS0M1?$@$^q3wN ++HJs2P%ss(*C0f?ruZ(JOPhSt*fn5f$N(_mBV+~Fv0MUrMl +HH&r09zc#m+t!z1_~w4_>s53y}g4i6{~FWJT+oT-b#GwNgQU}E?Pz~VSFlu3fnN3P+`X(D)TA9x0 +^y~sr5PH8l9h(zBfNKMyAnd%G2lm3G{ +cy(K-UUcS5ggXvLn|OvM*pT-~JgQcYYV_9vK6S%Bn7VJ*@b3K9>&DRMf{34|}LIBeFNv?KxabL&v;fe +=IyplMyT%N5ZZc(Y9l3(Vah_zX>;rd0{X`NVHdaNy%$8T91T=D^1pu`MeMgabtZ7gh_M+pH>~&;;Ka7 +%V*dcpwm8$=m~lI~51aEz}%u0t`_&rod1)ckF)q_C$11>Ac*upf=tcKo1pIf8wDCginXB7L_9e<@?W!s>Ok%Q ++oYlSK~QMuSBjuU2F-3noj81bM$v3c*TIueu=kMq>gcO}6X0Zc1>N_A-qux?FLKfdPTEyFU*J#4h){; +%k~OZ*6!*q*-LSXgfzr|>!R#x5vx(Svi9sfM+|3uZF>yI&{~m#do0p^h1XeQ5FmH1*l(dLG^!EAa8KZ +Fc4#pZCdl>c8f422YSuUFuw6{~G^kcun%TzUoKWK_UdqX_G>Bqo|bJhZVXiEcdOzYVwBl80}Dul`P)p)ww;wUZ|fR0y1bS1mO=m+=@h36kv9~sA=*%)+5v?|Dmqk +iMh}32UO_M&S}mxT0vj%J)PkkPoj?+}*n!8x^k7FNHWO6>DHopYz^%3p0MG#<-7ikflBHgmWGBq0vP2@^Gq3ds#fY6$ss#1X5@cWU+X|7T +EwSXQ5=h&XuB6Hv*)2bMzy15Tq?I0LWhoa`IH0fePMMEwU3kFZgJz#Ni9EDAHv->Psn~(Ej@Y|FWUI- +H{JCg1mJ2t*1|u<23B-i;TnxEb(Er@pfH+&tPDI +CFdUftVQb{;ezw($raOGEAPl=qo+oZPsQnL`Y;J&3E&duq=#VRfLXrtP*<>@<`g?#vZ>CsEM8O&wtT(_AelZlDTS70$;{xjVhv*!UHyYDy87p$?_PAS*Qy%RbsUMf47-J*5WS>Y*JYU)40YDk>bbqg#{sVh~jG13l(t~)BcfXyK5v+USg&OzQrvea-2!MeFLL7(M+Zw5RXvvlct|JbfY?Q!N*NBT)+z3Zbp?(Vt`8O%! +*BQ?n;Ucs7AZ*V%m$1_k3LnM@jl+v=q97KTd!qps^fq&uJd`YemDvYk}OhGX(vbVlixW-AVChnG>#aMePq&Czl3;Qp-B+eC9_$DwWm$D-&(=z18t+I9f4w^v?+{4-kG?Pz>EMGw!+a$}5KoO +a;}2NI|iu36Vc0_a7`x?Rgj$C$W<@`e*c@D=M&j~_h}@87-zmsmN_ZX~jpqFg+-QrHaDnMuQsuW`-mD +-;C4Vau{2_QA>(5(X|X7|vPtvPZBXGi5*FNY{`6h(-oI%4NEcCp(*S>ktz^|4+sh#oBP{pg7bZINboi +1tIpyE}4L9fF^T!XciUCKuru$~B2{#=oO2_NGP3%fLbzNQwpI`*8H}kuB=MK9ij +kLi0-_sI9NHY*tmKt;KyV##7Sd;I8qkg|5-ER$fI_%YkK~Z7a8=OSd=qYyH(D`FFY6;JFt+T^uI891o +*!l9@^Fou0174hz#GYCH#-3VIEMp-z+Nxw+|((P;EX*=Pqsrx{U@)8_jc`4yu}Os*SY*!S7$G>5H=p?h+id?`HY&3_^&+6K$~*l3ANT +*)mZ5P@kU<+WWeq`%Q09|V3gq^7^rZ@0;ysWEs6Fr{9udSn5H7MQ{cR~4R2yGTE +-YccKtdMKg}LE5i=d1^T0pv*fZ;~jeG4CMHDOexLB7enpv7qG~tNar#d|MjnUn&Hvd&zIOW#3Y{rpKq +09H6FEq#iVzXZSni`7d05zUs~~{06eLr4Div2|GE!xzqF$KTU#}97!L;NtTW7SCtC2*U{PR!@+Rt$gH +w^%WRF4dKzx7t=O3OQgDOYjk+~k|RQ%CNQO!OS_w3bO=?oQYL$s|EHnXF_l(I>ca!F5&c|Z2Q-KY#jy +(vjXEywk2JVE`x@MmD8*ok}GE?U55NwY}rNOJ)5^>7~bUc57YMlmQ#Cje4L%yevYEHD%C5R=#ufS))b +#+ka7)Ld(EaL~yc%JId(Q5%32)#Lw&kk5Z5mH8{epCE%klhet;zzz?)Kl&m%PY-{&nEdru+l`e6A6tq +j^JMO9sa2*|HcC4gvfgg0_RNiH8X^`am+RX)^;53HcXb^*U1U3l`+Xi4q?pwC +&}!3H2w;0JSbY5~u&*7JIDUv-+t`&`Z}6&uDhqjcRF_r@W@AQj$-*dF)C3#$dU0`( +*T&s-@T))uPcv7&@AC=o(j6tAf5n+C8i%Sn$-9AS9+pWJ;J!@j)_BqQyk)`aN)~Lt&*}J=6Wc?Zna*d +ZJdk;EXo8S;w&Q#1{F2oCQe>1lEPG)WVl*PNl;WlgrixuUbBN%SzISm&Z9I$MSI3`p|&1G)_N$f$I#9M|p=-(I4YPQ7>udQ(D!A-Y+s3uG-ya(&pEp@Z)7m=FMCGvL1ddFURS(-HR`+iM +>54>v~m-&7bwQO^qBV#EV?DQIsr?!a%!66ZN}oP@1o25${dBjNUd;1SVxF(bkxQGV#Jj`Kn%Y|5*+6G +diNEoXc^i}UiBY@Lw!kZQNDwr|1u +Io!^hEW{UiNvy9rkkb5@-o9nHP{HiMKyZwyIfHX*)%hdGJR5>ro(m3%p0amiEb& +t>VuUupgik{LcB>q)k-i|pm^k#Nu7^1phIplzVIxe=*P5ZrA|)$NpAHg>u*hV4s^uyrhr#wN-JScrVW +@qJdqJP1c}LIkT~d$I_c^T=<$59z_{_Xe2M2u!G-(Aoc*eN7VGIxKD^@Wqf%JDbBBC}4S-A663%e9+)Z8@-vzrgZ*+$NDE +FDgDrL##-cE_2C=5ffVQxJ36Pm67j+bt{nIgnH;809UV~xUPjdauJ +AEdyVy4kh?y9&U-?%DywhKe!n4*SsLp(R?*v=TWfQBf^+K(H8esaD(zoVMh+3RVHBcD)0DnXcQ^S~2> +3l)*;!g93UUsM5g*!f-t-4qnT^Fv#+(=JU4JX8aBSJb#g98JZ5J`tiBB!Gy(#4g%}|k&$6Z83s&>byU +TqF$%IpzHGr7={vF9|4^KvyUBeNqYtFa=S~40U+X|A=yV4dVX2jyC@Lo$5MCkmF(m!Ga7&m&INS?16x +dF3y=k^Ry8Qh!**$oH{JeFRe%CDafG|g@IFm^ktZ)j)V);wH*$IOe{+{!se2$)|Jzs-~OB{V5pk)Rj^ +qTa_gc*rSV`XVT1$TGyfG{yM&A2e`G6lIsr&&3_y0hmnRrbz)2dr87H?enJWQICRt5K(Mv}Eu&{)I2Oc^<=Y+ScP)`)t+F{+i?1y9DCpVP8a +VhD7*&HMy?BZw8ktL?kYgSy5j|9skxq9w7k))9w24pOL2?dUNQH^L6Aw;|cKDuf=pIBF$In1SUxF1mg +YULmJp|rUMnjX_$G}JZ9%vsp?J_xQm(kd5NOloN{>SW!nEab=1eh{IzzhR6I@nDP-)8Kr*8a6uL8iRl +APA@0Kn1%<9WD5K%r)nv5L9C@?M-HgnEJZ6p~l*In^&7H$7Z@5S(p5BTxD$NdH~kzGp(Jl69tcaD6s) +=Cum3C1No>z*d>oiWnoA83T_B&&oJk&=9R4k%=f?0N$S9CMUH~4!tp}Y0qQ#wg!Ro#rmLl2O9LEi +vo&~cn&)b-;KWoP&lu4g9{0^1WvHm?5;(+qk}RuXE4X{_jLDzN_UQ2$p` +EID%P6`s~3}yxhp4dq=9>eG}FcZZ}@b!R5O9#|8AcFm%|@T4+14_b<;f6WY<()o*tm&9w0B5o2FRJ^+ +^#9X7kJ6zpx*8(iQ%R?~3Mj@&-~d>*~@j{VHuW?O$|cW*YBDVTc6{?x!fh3WhuLI_Ij4bE5w#%K%BO_-mdUZN{Cf2q39_-`Uul3@SM)oF(ygI~(lrBU_^_W{v88jarbZouxG{A}byla +ZyB%fEEzES>MN-=}K3Bo<^qo3_=;9g$l+B{ls&h2SmY=#noYEWjq!Cf;@K9^pL*62ELU^&5ic9`Z*;| +=Y_KTv9QyaN@K(t^6TuLHF-Kq^-s1rNO%#`Q +K{@dO^*L2lfyS0++KFwbV~7)?UMgLDmPT1j)nZcrf;3t2j1FAWuJ+cC+}5ufVO#tMuK~ZDsi16mbV=* +k)oHT^QBRa<#mPBrp2P8`Lcl8+4qaHxE$IpoGdaB;eD|3Syt=B4R=oRD5AMCN +!5^cDI+Q@j++-&XS5kmqH5uNfmg~{^vID +OJy9Ao@WrS$z;VJS`U=PH$nT%&e*brPdJvB+Mc#e?v3=eNtT$|b1HWE!+ajNJ?Jk9XBeuBCQ*7Fu=U} +?IiLrfm+ThyWCY1azUM!y?OB;y?O?p|p9r(uqTo;CWk{Cy$63Csm{#lHIBTb1d;&q_tQn;|C4p`ZO@m +)uG@aWIfob|Q$fF-jk+tNYsS*7|EFz81vT0L0Zy=38W>N_uyZJa~>y-J$y8mbRt_lBwQu^7|+Rj@$gk +G>bvMdCgB#Gq>Q(H*+a*qi<*m~k4V6aCv>qt?Hb%V2U>nLeSZ=?_@zPXQ>d)9!AMHNYchl$+l52=?eb +9>Cjut(le`^E#*8`M@ne*k7LoeyDWPd8rfenD*-RfH7i=nsZ|s=N|XOvx!)KVBqrtzH~s>G~<0ey)yv +pM-i<3a=Oq_1$0k;e0E0P92%l#c88n7{PiCW!s>+3SR}7j+Sxdm({-s@Pk12=(*~6n*KU%zjwVik%i- +Ss_&%^-r(JAGhcg14gTBE`@vNvFhVY}iJFFl&#yi2+#={g(1$)t2Xiw=HEttj43b()KdP5^BTqQ5KTV +EK#{p(lOuce)nk^7Bvd0`!I?dOAIOda5%d+O4-@qBQ)EpcQ%B5erl9X^Su6a)7FAg;oitsAlis~S9xK?h|p&f`(ZaU#j(-e2cjEbhkr480z+BY2S27W0yOe^Hn?k^j5!|en+s +rvsi2h-7i>%9b{?@SXj{|=E%!7mDEx~%Eml3M6>nyCPB9p);TZuVC-Ij>M81h<7ytkI=DU|ZL#XpIVv +lsIxMG)T$`<5vD&*Pn1Se%!yK|DNL0ts753Tk8MlOU;O>Z2Tm#Qa7#77*x>Y*hK(`R~sxEW4=rRsKeQ +L3#S5z6m689*w>=#q^fb1=<{3MJ`oTE3y-NlrHMU!`;y1QKPlZzy~V#wa8_bQGYE`sdC>WU&iX*OYbB +V8rUH_`ARH-KlE!~OxppX9g>=d-Fd1jVg#q$_Y%d9BMD#fxeq7j03PaBT1H2?j-FDs*_C%Z>T=9t;yL +a}4ik!ns?90^}ik4VT=~?%G!E*j&!8$Zw_V5&{TLPoE{II^3-)$D2+j +!;l{bb+)GhVPzd@2K)|2i8fdJJ#}pB**iBVm`O?5R3?D{;oWno9V-|DtG0;4nQ!x#64F2pp{d<4Yf3M +kpr^&y^#P>C?gErgt_%Vn-yQgVLgV+-_*Z}Js#^x9j7n>LrWxu0s15A!JKHBhjVFH2Gl}LSF#2X|kyw +DisI*qEY)}O%y;mgwgaV~>r=JeQyuG4Pp)XwyPILAjQHcdt{I=b^^u3bEa9}RTwC~9@+1VW!z0LqRsizJ>tJPu?OWtR7^O|PQ(7K2KO3*`yxQbbZ`om0)3rb=T{i=F0DceZy2aOMrtGp;M%hkREdCH{=x*gbF^5g621FZpgfh5R3&M4G9L$R<=`Z8?Apo4I!^X5Go^w^NWz!|H~=YG`|J0 +01Efewa=f*tRaG2O0ve5n?$@uO%gf98W1@;uTjNFLRVvDjv(#i}YRrxp +vL^TN7P$fdVgRjNgJz6j%Vsa$Do=Idd}Mrtz_YgjIp`>}AUP_iCf=wiCqDwA3__4=`%Lq_l~_ZJrzNh +ZA)pL8*I&bnda@@RG;@PdP{rB`H0sQNqdx}JG!d?~X`(&xcMZR=p+oifVF>|j8omD6S|bZc_k=oh2^7 +qgW)XZWr5rPIrbKL23LYg?Igc(jGX5_eM5!R`M~Y$=vXtjLNet?)46S9^?f>aR*Wl`B)W +m%lrF?5}mEK1t_Q*xs|9Sl7FzLBb|UMN;^qqsl+x|5_W~vV^|CAg$${gCM!o9EJeYuT-KWhFCZwgOw0A_=o-6*>aOzil +{LJr_5<9l7AHiHK@b+n*3}Lb`RuXtr1QxKdH6njQ2SSz%$KPYY9`dwx>Uh*J)U-%WIlT37k0Hsh}TU`=EIi7v1nUbEExO6qUBN +JRlO4!n{JSTqZ32aW67JHE^WFWj@TDPOLu%Z%+#wevAdj8C|O1fem8^ZpH`b8kLiGCtogTc_87o8cZp +io-e+ereR*~!PiikPIu6OFB9i~V5-X`Q)Lo))Fqvldu31d3B?YN?Fm`7qYim=nfobJ~le1(i!N7E?Gj +U}oeuWP~%i~&wiTy&rEceLp)k-Hwhdn5>wW-8n{k<4wcBdT5O0dEqGlp5_UZ@BsQmecfpz>H^6tMyxv +}9vSE=gcirqIS9tKw#SAR!omYrq#W0V(Kxr6{)agA!lgd~R%{ib6=4MAO&6CRHdoJ6&$3;wpnT4=~^( +V}?}a$dxS%5E(hL)t5R6AWd7SQD6czoMOTN(KGFs0ug1l$mE_jvW4=n2-Q;K6!!wGyl+-e2X%$oQ*J= +w589+*5lxGr7S6;ywj9HtRemvE;*ZnoHCQU>4YU52e*6x7xE*4gXh8EkQ|)1y~Ln;6LLceU!jCK3NewZ4y +ve?aSsvmxHi3b=P)l3o+K7C#)`8?czWKWc4<-;5JSo*P6rGae|6YsfR)a(B}ZE8%%E3f{_XQAoZZ@o& +hd;n3Oh7Z*rGy;s|D!i0c5t3Th>BBfZ#k7sWmDw7j3NigfgJ_FZ@8fh}_cheZeL7+hw6P^}_#df~i1m +1ob$W4UF41b+pbC=X#8K8{&Rcqv${HaD(4oWEQ}kUZV#*Ya>(TOUS<`VFgYB1K1c*A*mmP%8(_4$}qj +wJT+)o{A=Qg$Xn`T*bw`H#;*d^?m%i3Ejq=vSF94FFr7eTl~5QHzegJ9lcgj@)&dO~TZJUuDUd5sDl~_+g$zUsh(yOjSui2tm`?3?;m(i6SG8Z(=d#x3B+! +*t(*AR^$>)GX~)$Bwq`Nd`bH%R{Q-yliScJ}@ErxC@FeIL!jQjw;57P09;MzFj`RfL1zfXFCy0H~dUf +Pnjnr6-H$$UV09|}hB1#dOUke$h_BoL%aHhPP1dbVUjZCgeMmqItBX_U<@H^K?xDE78;$8D>puX^^VZ(^2 +{dBNpnDu%Z!GJx|;xfevILuK^{zdl&fuxDeMqylYf7-kZrLSL0O2Q`Lr9XfBbZ-imb8YwEt=uAh0(V1 +>#EY`M!lv&WYF1z>ZVryWij~sQ8iib#cua~Tb&^uBeIjTm;qB~ +w*u>NWz_@s{cO>g&h5+xz+A=IZl}5Z{TnHU)Nxc2K`iXJJ^YK-K8Bln=dHC8OJZd<{CZWNYqhNICLAx>yDNf<`>V=<0p;hAqMm`c1<8vMyy*g3*{Av9x>Xwu*u^BsEQ`*%7Oc| +*}_(COmMUg_Z&ou`G7rQ#3F6$8qn~FvHxZ?cStvI)5s|${>8;d#72UqYw`90c;EBe|et`o0bQ3FNPo? +3EvHaM!TAl77a3JU(eeMK8GFNhwQp;e8lf-OYm2(4Z`Xx7hxGwEH;nRRF!HGRQ&v#mTjHx<`>bLJFRs +2$yw3(i(5pr@NaM^}9qbl|O=WEAy*b)%ds@8L$T*{jd#r|vo3-^@SH#iy$`|G0WL|192q6dyj`i}zRe +Z*By>6BM8L{QB$UXmbRgFXG)*;miDD?mz5B`+RQk>NiX +Od2DE0lXsmg~+@1HL5UDlm-+u9Q?^0z57%%rU^5}N}w?XBr{#QiUi8{+1D(-|LzGwO_?pkE2pBWRLhy +~QIf)iFohBHm}Si@xXcdZORRmp}gkNuQ+ZxqqI70bKCI%O8LG`MG~i8heN6h%Z`j_1r(FyLG~yVMnZ) +g>^%IpferyRo6A#M|BMagF-V^NvK^M&78%*Op*;~nM0nhFL#P{5Q=@znxxj2bDeHG(PQ#Gpa+G}Pgf= +V*5$hbB8DXY@;Usi@$--R$Isy)U_7W}ie4u!?CWlnXOEjW;fu`XC(>a%n|e^7A6e-~7(D~r`HT19BE6 +a*gQSV6WiV(MY>(j9Xmmc74)^x8^QRV#KL`vuQ(NIfw^dmA{4xz?w9uY{0|NyPdmc8h)aP(SCPzOQ9R +DiyX^-~Q#Gfgj`|DJ}lbQ<>nItH#k!zzm^^;(^u2F0Ts#l`aNfuB40Z>Z=1QY-O00;m!mS#yd_$B{fD +gXcuoB#j}0001RX>c!TZe(S6E^v9pJ^OnbH*&x0uR!SfNXF#KQZDUPjgq>K)A*~;@n<9U +heSJ&%Szi9X7u{KYQDZeQW$NdMZJMe>Kf%XFN#LCtt|lavNm`c9SQg?^2JIPvu#sv0ZIFbX +t!&?*IhReRo!gzb@_{&;m{{k{Mp;*-@g3e#q7m@zkBie;^lX*FDByR`!{dCd;9Li*Y4Y+anNj5$ZaDR +InI^t!dr<$EnZe{%I(S19~r4(JvH@aSU^KnH-oof!EL^{$=#wbvc(PIsRTUCw)<{XSGJbCTga_PI*gL +9%eHIE`3^t5uDfsQT~$oPe*mt3kWC9OpRF627yFl0+vPxh@bP8!9xzq>xRP@HO}UmxgN(56t9G|V;F7 +<3h$-sZYF+1rZvWe77qfS-0HtL+gIS&kMEtC)`49L9pNS3)h+71z>vIc&-pybRZLzJ~{`U0qF26Qoy_ +Vg~bSP6GkO0(b3Ut27~}y>|9(9zrkhGJ+G^-sn^4a7%n&6Y|*V}tGp`K +a<&1Mm*ey-*1JMtfj2Y&`3;hGGrR(L7cZWF|Mtb~ySFd@^X2Oc1WUy9NWePnYG8U3v8vmS$V?EU=O4|#@c0B?$UWI*k&=-p^WR5Y87q1a-bx2;g?m^jmOn4_|QU29a&{{S1y`0R+Tt!fh8tFk@Q3$Mi2;866%LVGgT70qn`ZFdcmCgOJt<}JN8TKMrd&S=ogsX$US@JmL@)=u{*>D +xU?FgGmJ*UHeHFq7inDm@#!bcpC{svC;XpN_|N#uLAIooFfvd=gdFVE#8mV8x60d9Z~yS)$RNS1x3&{ +kcPrV%mAM`*@dlHS&gwPF0E3m&~v~nU@iBjI +&9yG=OGQ?K-*1#CN!wZcCVOaa*p}L~kA_GcKCItt|C(Fk^g&(hIkNWNG@jTx!;Vtzp~2Mvw#fiFf<0B(-7`v5kSx-l4S;z`;;Xgi=}y0o%c +C-4sCd*E<~bnHa=yhN>S!|J&Gdkw@Y`fUXLM?b5mfs@H%4jd{}{8Fwr37vNkSY#K<*4vd`XQlOyD)}8 +XbL|o>ej%=htb=~YUaZv+v-WwZ&%QGG!Y-AOHKzNdOC8?D=Ko(AcF*_8R+B2uBp4>u$LM9vFov`4LG0 +EmVcV|jnFRxd$oM6CG`~h|e=%xc^4mc>*wtv8Zt9`dZY2d0CT +vcmeb1?XDvNGGSQWs`|R#^k_B{h;TCP*3su}V(0Joc5}^`y)OBS^lFTT=p?utdVMAG +FdZ*Rfii{1i}_xKQl+Rt{mWCWeEe@r^Xrt#D3SrJ1Xz5FlCo1ew)P)?r*D+^36kr9pe^d8>DesmG53%2wCNG +GJt5h##2|bI*T=Q3B)6W(wK<6mnMU#+)C72* +tTM9t8YmrB@J3aKXS+1A0Fx{}{ftIZdWj$<`%ubo&2C)#Je}iqg#f=Sk(6YSV;oeUhkhX^?9-{<?d-@N?q-@ia98M@c5>fO3PdV{_EdR@<9S&`g}Ur9*e5+rzgP+-e~{T)`N!Whzai{dhg_AGcYO0~HdF +)Te85vze!x|6BSf@)b$aB-;abPcosbGec2jLfm4GLsn#Ij=mzA}R6!d-JJEZz@Dj35oJ+%R^sLj}=(l +bXIxG+o$%#0EwX(MvBWkMN)%?9W+QXxnN(NP>ehq#CmYjpW_$v2_`8Vfc(;FX`@yA=iggoObZsrtxcf +?4mmR`WMrNuAXRQ*Y%`EZS?~9?Zu5M>&PBb%$_faE?9lB%j8Gc|iLxCNng+;MU=PM;HsTm4IS^FYAaN +mWwqisOCRkydY?i+J!lRO)e6eV|>xe4xE3rS)QJ_y1%it*Pai{TvZ-#Mp7{nE!isVQ9Ct!yN{@nF8ai +LIhHIC8jdWW=%&m;0pp$@j_6sj+uULji?q8srTJxIftHR5o!SP9R5Qz)avRS0Qb9Z&McF_e{^%(ElE` +z;a5ns5Mv4TR;W4^SQ(oH1(PUr%JmPiMpNQHUYG74)N7F!6}O3h5n0br>K-pVNr)D`}r$JVez6jft{_ +)smtPr>tF8=^{?k8Z7JuYfE>%wQveyQ{UhmLRF;Sd%B~4ma=t|f2ctsAg48f9H(0a0c3f2e)R7ku^Lb +oj|lNl&x5u20n_?mY2tez+u`GOh5PU07I+Be+z7IM#%RU>mxF?vuQLHHRDUWq&lDTjExd)ELE*YQbD@Bb>~?YQU7Bu!rcl(c6 +zwU<5ufWx#N!DF0-hHHfW`W6QAi}ConG7Z+OjQ1Myh(eVIZE{`~QR$OlN8j&2`F*tRw?Q;M)CTzSz2> +d?VBWN6Nm7;1xhuEUj@CFbVZx3u<0Tss*!@ko3vfiG>)e2X?LL?-SY#Orb$%mQjw)pE?9T&(h{Y&QnN +J?cG3tVUmOFv9)A_z6$VpJ=V$3A^DJ*!noM3+XT&TyV+;SN9}JGTV^ +EZ3UMI%XAOlAj)qT$6LB)WoSyg=Mt53)r)rFst({i&3OK*^GIy({-d(S-f&*)nH^rhxCtEtmX@aA_m7 +w0{=(Hvoq{Io&(NpIz@kg%Nh1`E-;CvT46u?dvE^?2m$^06GZaqm^cgK-Wz##IIa~~$^QmAo8FQMSz( +}c|lZP;bClfG)wHT#rc_M-%8kTZZ58sid8KA7Bq7o4Wy!F^WfnUAO$ +*Ag&R=sbqIsH#Z@w)a&$^eS+!7n1h$FN{F8Rv4u51Y=|6+DSkk?lU$`er0N)+=Qa7}*#53iB1l`|R|+ +*Sf;s_ke?JjMvJkt^g&GNi2YZttwsao?!*zH_o-7m$F>Ij +#!=(U#*V92wa*PZz{vPaLiB=|KuJd&G&!1JSDIhcy)qmn9%B1a+lGs@)JY+K +%yz^x*>Ih1nop9xTf6qkYhMZ2UFv+fq0F=Z?R&q6gUI#ER7zgwYSo7l98l*^606LEUL6)L$kJh&U&u{ge^YHXd-i0L+Th362B78=cG|LT{B2O#Dqs#X96o +y&j#B|aJk9v;69FYsoEknxOX)H}Kd!$dSOHgd)sgcYqc?2q!oBMal_er<%g2&2(;VXIfU*6i2(JY%Ki +8q}L|x(ZMqWb$;2AWpqa)N(&l_#sL>`U+db))R*$KYA0GWco&y>e_<^XP>4)K2@4a@SQa}~?p%jP_U2Vls30Y#lS>KW4t0}XtnLE9GEa_xYEKkk9!(O(d3;kjQ?d>A_%ZR<3H +f8Eng(najL{uD5SO221lX^m(;3?7LE(*Uy`ZrmZ*fq6EdA0>+hs0G8mj?I!dLfc6Tyas*o?8n_va5Xa +^HX_q|2biFpYC5G(O%WE1WI9E3Pkl2mH4LaqI +LG$4N597qw(zNU0H?oN3pjnq)IcesCLkCk{pTL=!Yh&#Sut#_@KSu4QTc!Brf(9UqEs(7_#jW>8}Q^+ +G}%dzq3^3pw9ikA{z}L_BK8Rw$;f8O~HMK{PuXCXOi(L|Kiz*%$}>-1n**2^>c4RSRVhx1XP)Z0MMEE +l49>urzcYpYQD9bsV9Iq@#~hsyCxVMCT-E$2~$v_&Nv9jt^dAVJ&?Y#O0BO#o3KO^Q~})@QF6!2|6sD +<{oz?b}ad^!yX7jiW3mUm&14$ccR@U0eeR1DOR=h_OvLP89y8Fv^~)QAfJGG<$;(mo>lpJ|BH?9<&(D +92oVfEWs%3171<56fVfPGV**@`o`55T-VbdlpcQgk!9P__-IGpOm2cij!|)&9YLF<&4G7cxmxoiUfx8w23d_6Oa^Rkz+t28B0O!UgT(oiIHQ$(di5hRL9kf=7N +GkFQ9|FEeWD*bC_s%7Fi%$nF1DN!pPKoC2hq}{^lBpmBUNg{(Kr1N^65b65u#Klb7smzIV<#FjC06il +##V1=F3=if+((ew`W(i$IwQ{cpQ^tB$ac4ae;|N&)XnG)KnMZ{d+I69Xv~81ew$Runsp#+ssm7RZd9) +0r*o^JpBq4leQiLL-Ma(*+riJX*er`K^1d_<)R%KD?4Du7&*cF&OfXCH;lHnuC49Aa;;PaoKoF*WW1~ +iD&4znxGc}5JJ&Vj5%`b%3KBADcVM&^6D@8ut!7l@myA^wVYC2(7BW9zQ5znfuGrrFtkm6H%iv)(P!M +>johEBtN>9^T@dtgxDzyA?nsC+!Ju0p>tZ(FyY8I8nXlQgMoyI1BZOs;d!UCYs8J{5LdsQ5t1cL1^2n ++ZX%?`nqZ*WuYMztFNQeEQqeeBwM=8{>S{1uux5dY;7{<^>qyX4M&5zr0LPEmb_JG)wUc-sAQ{H#jdL +G6?5=H_2LwfV(HeK{S|922Z&QWM70U$9SuWKu+xTnmO;SItccP)j#XcaM`qzvx+3UU`jzV-e6P4x(4;(E1(xi4DVoVyBfXN;r4=0|YvVqA +aG?Hjh9q2(Y`pbuCl`kJmQKM~cn*iRLV83b9J^-zj`6@n}kO?L+dmJYttOga}cyP#!${g{4>eFK|^?( +e&Z=Kn|4GB-kOO6{nv;{qce*S8NB!oUic|o%#*_Tms9ebP(r@hZ2=jwz1Q_6MG3Nn4M>21blDcq9nIW +yOma#L=%u9_d5O(n{g7{Jx0GiJ1S`cNOq*DpgWbB~1?6DK&O5Y&M%8uuj@&GMocCG64oBm3idVB>TO2 +fbjMXi9qWdfToBIjFjWCxDX +x=7a+2f4OqVAvB_8Iq|q+M-qD{+hiXAREw?5@PW+ +C6W7$-PZ!D`)SpO0$Bw1x!A^bOVQxys0lk_noBWy*tR(jk?6;ot5hMgTr9zD`za=U4RPXD(V2xu5zXLi!H3lPB`OR_fYCPO7(6s9599S19MM)SVRsa5q|z2YxChCFuDZ3e +=ZB0}kIiUjN*9A(Jha0D&crsb6irc(+8v4_C87A-X8rvrg8;pfT1EkWiw8EkPP*!(>IaS#qn{o;oK3! +{+q;ve1I^ay%&a?(VfIV8O`I4%ObZ$=p6mD^YB-F!r7+&9N!>L4EBtny5kCHZ|sxRH<<(8eoJpj`H_I=*t;fYH)wu0l;4|9(A_5?i +~B5K9PxsiO6qoc#fiPmZS4fw7zHxD%YHfm^uTI;h*D3NXH<&QUyR27K_c4{neMUNbyM%Qqmx)~vPF@%?Ay#V@Y&Tz*|U^y&Y7dKTGS2 +3+1$S+M4Vn9e8uIf?he3srPQ4Q%>RRzjya#%zfDV@sh!|Lzd0b5>Lih9uvq2F2haRpxt-go8aRk+FbF +7^NX_Hn%4}6k;r%`D$3xQSnkaf`Wbd3zOnj;W=PP8MP=+A&=cy0_C(2~k%1k_?=vxXu-g-nq!MSJmW9 +T7>2?)qnCfH%GGzpU<{>)V=%z_McpmdV;h&kE3^MS@;Y#3I_h_h#Z`|kIz-eA;|wRk9HgtH;L3Ggr>H +A0S9r>o$5JalHM%VK(F>NoP-vv`ay^XV^7r~f+3uAYpi_ODN#OyR{4)vxU3*k-SCj}aW3Pvka1g|~gTd+GQE)yGiwF +}DJW=*IzH?j2{ +bd)9e1~?rx8qB^wK`^A&Jp&Ivk(zCa6MKeOUTLCzSyCOy^!lWDnYWiJ}!91j5<(11J`hi$&Qe6mX)KM +p7=t(Qt-#=IKxa_hbhY%{1mV7-xzZB_vL~O2m?jB5ygE5RcVk0IfK8ab^yqJ`scIz)T;0adKbjx-m=f +5pju;#@6(I^AzJL4bP||rc&PqI^NI|qKnHPYsFe!V +GqQIPaulBIPF6x4PUMvu+JqLqW6g0~bb=lY)ql)q|!ROqkDdveLrC5FSH%`@aI)_cEC-M#2Q5V-`#ts +FpHByx?eXv(?qO!qah4ngWlHtWNm@@`0ayeAhhEAXd?G&nm*e8DSKbvG6`a&UolQ>19=g9kF@_fv6m( +KNrUyx3116!6zMlY1bJIwqa+^AwQy!o&7ES;OFb;t_XX74Q|8mP)#NMs!(E;M`Y0#7!njrRt#AE@*~6 +mDuaJkAR8h_iw`^^$_{A#P+yKRmxsX-1S&Nu6O)q9t)IP;x1+ +$DFUDa58e}i<{mr%&ks8EZPgMYm3!7^%xSrEueC}#Eu5+zT%B8C*V&GxC-RaCTX@5h~KOHGCNGUE|rL!uky~a}w;(~y+d0wE#kAsVEg6mBhs6pBjjtb6!#C|TrL#D +EB**E9D@3+a|kMmL*X}0YT5Wru5VnVc(IgO?W!O3)aPp(4FjNA9M--o1s_XlRUKkL#^XDn{7TpL{ +DgX)Ve3m_x-%R>R{=9q~kAT74sL*f6A_NMmG%e?%@wFMO)nP(Xb4s2&4x-(k9Q2k8!mrMnmZfC}2|MJ +1m2E&yik`mF(ysAZM85opB<5-pOVU;UFz1zB2F%j-c%EQ{!agPNNnR2zw*&4 +%r-errf9_MjQ*)>ExIeI3$uU#FpP095#OLYY!a}RC7upwW$ZvwVKqb~ixllNNq{9|&|12$j`&cwj5mL8ME;5pvlIaN +0mV2w?FH-!ap{?AXJChGk8V4w{QCnMU1nPQFOK+=Q +;p|=kNJ20WCt@2U}Kh>24B&oQZEuCiC2w+4BIB8)jD1)h0+{;`?fi32kn*#XA?@zIgVvxla|%W_TVi0 +7i*QrB=*us`^&sIAx^ymm5C6PPq(lhc#m;S$_$D)s*4JjzWdHGY0czN3SrUigRm_o2UeT!G1^+rD%w# +Zs@Y}A$cLO*P+KjEx!9UG>7VvnF#KU4*UokPyc3fc!TM+^!kXvJWnK7j0l%THKf0Yf4De~jJf6>QB1l +*QZ~w@@G;QaP;OBdf1)Kt8QGv*kV;p9)pw94fpH819&tz0X(Q>hc#c+pIcPeZ!VdM;Ym@PRfu{kM6qu +8`IEa6P$L)Ze(u?s!`p&&jIy4ggxuOSa^hx0fX1(GY$37TagN3Qf;bmmw<}RnvXj**-Yqj2W4{HV&c7 +ayJFwb!;mnrF+5+$;lmrhXs5cI{$9llO$cJ$@kTY-)fNaE6UBJ?F1o>-qil!>Vc;Twc;Er$jX$=$AK? +T4*^L`KBtu5oQGRrwC+Dr3?(eOBxR3MM73K*CCF{;XqqbBFwyB`M|691Zch4rGyZZAU10m@6G9GmOrP +gxp?p`LBZVc+FU2iSw%zp$vzvmEV&Yki#%W`2Z0p;3R&u!I9H@_huVGy{M*dpbPISlJTQzby7`tI(rr?!3jodmNWx*#*HR{w)uFq +7#`&V^fz=_afBQJg8R}r<8*GUIhvYX)A3)CW^samWs<9$EQ@^DOas}9!cA2$B*Jzl;P73~qA+3JReR1 +bJqlTtR-)U-08h98p6a=X`;*m%7h;%UUG_P9;AeE}10b$tc*$h;i0t63N6KYhm`xi+POIV0>k{LU?06 +}ZcYieq*!|CfDM|MZ(DljF00JOAq6vqz6-KmGKl>6Lb0S^J@bZEn_2>IJm&`}~Fy_+lm@6};J!TS6J3 +F@YS2;Uo=Dh%&?w{@1SR+ZKaBoNU0Ia`#L)0~X))(#YGU)Y0S8x0EyN_*2g`8eg}fHbw3IVeT{tqRPoDLN)adk~h$U_lyR +=j!fMtt_$&(%3)zG%{x*50a^A9!%`j*q)Z&1iAt%C(taQ}X8m_yd&TD~zzw&!2wgpG|PA&^RsXBG_Df +|N1$sma4!7)dIzP9-Qzxn4jPm3KF~MP95KTaLD)ITpV@o%(-7Em@(o={u@5H>bg+A!)uAJuE&3eWNovY=Ux8yjitPC^L43bqfC0lLP(@a`o?w$SVP8GiAKBR; +;=qkrJF?!7mTzbc~(JkuA9hy6Fyb*^p}Hv-MQ_pATyI`c_SXV(2!$p7s+^F>cz{t<}zq6ab8{|Ll<+0 +&PQ1Y*AILCh*|SG~&+KZdI}7UQ*BDg-hM^-g#(>s2;wGrGR=rrCt7C?XsCd)DC2yCswNm`sDzR#@9_t +m53PesnqOoq{8+Mnlr`8=YMiEdVw&T(e@YpZe&L$-Wt*h&AUPEZ>6<ZuqVA>DMivlfGTv} +*V5^g!}-nWl^&hj?Omkm~@f96ciWB +3ciw1;7LVw&w0BQqSp@Z}dwpx?R2&8k87Gj2_NG>ul!vdQIDUxwNy<`PB#cyu}NGyMaoj%l=NG?-k4` +3d&^oOLj38>I9EoNIq{DCeR5!V~(m>GRi4Vyzji_VE?0UDCSXlnpJFSL6-_*yu0&lNQX1^!6S4Ct7qU +@m~M}5u3#$*9%<-qYc?408F5t&4ZTj)?C9v_QYgy;S;L^K`w8Dk$Tv)Inle6!^~d2EjP-2zXZMn5UPb +W!NJVb9+F=AcWy{&W*;GLHSCF-f+RONcEQ~wl_LZ3c+B||eHH~2iS56M%Oz;g7t+}d;+{W?_=|#tlld +Pv=>5njLICo&e0j(Hu%03fao?Pp=2$5*W%I9>+Hhn~P4T{*;$#Rt+YO_Pag%z?`?+Q86H$CRfwd{PUz +LK|i1PBZ0r8-f@Shf_ZA@jX0x0aY#TBrLxorAvIMBi&XHm%^fnZnly`SJ|@(XrR6jCdkWJlDYR40DJ; +Z_G_Hw?2745(Hxi@Yf~5P(-CP$jh`7HAEH71kwI3%x>PJ_no!&8pC83gA)Q^ZV3 +;6Z}PaEPAsg`ziq=UyUdD=HOZ-cl0Pkr&CscM=6xK?g+Ok7 +~PK4f@`9O#bOet?E&^n)|($AEL__g8i-0qH|~q|Y5R^)IqQ)N<)?jtp2mOKMgQuX57`)zL}Z%}ELeiP +m?mRGV?S191nLW2A4bA5N!LJq4IkKFLhC&n2&>ckZD_R?0WgXHH6^p?E|27AessfmOQ*uVQs4P6lJY= +Z^Ze175oZPOv^dMFd>vgyHUH$1ic0)2Fd4b?T(yywyF=x7by>hc|CIc`P4M;?rD5M`zZGt%30o9l9sL +z*k#9=9aeyvpFKmbiv(Uyc()+T;81NMYpp$b<47jYD-+0bHzDrbu^cB6_BD{lvebLz-PLajq>;NCiMS +MO9KQH0000805+CpNw*JonUM$p0QwaG01yBG0B~t=FKlmPVRUJ4ZgVbhdA(TQZ{xTTe%D{YIuDY!j@- +ooeQ*&J!LGLrF1tCbQ|uLKAkY$R^CF8nl8WOl_Wt&MLsGw-&2C#1^@}BPW;p!jo8eHC$>dt)+)7m$cG +w9m*g>#TsRy=En&qn6$gP<%SsBaAk{R1Wt+w}T4WiM`&wzs_}Zwlu_E*DQ543N> +7UY?+g2#n>6E)UQ0OQOlaN +;Y_Ra>FUGVn@=n3@u`N*#t7Yuj@;pOT}TaYqce6{*QNA0vbR!;+$t@FiT<`)e$3unV*Tvx)kk*GDy3v +M%Xz*N8Qzl#tWTye^>%r^yj^DRFF*bW&G*aI>hdp3=*4mTkLY$M4co|4F#Ojg&qcvp%+^P8k6DF17vz +Uvb|;uojm{BK4(Y~51JN{!ZmOK5$P&*V_|_RUO`Z#5HceR`Tl}zy6ARXIRluYK%xe)9q7)VaNmG^3V@ +K66E%xd$m?meZX$0@1pRRt&#=CoWb-ny>`QB|0KAn4G=cIUE1Q3s@eX=otDa3{yG>DRUv24%v12Ci&l +1_TMh!}oEPWt~u3JwZ_$15_g7;vnBne((?aAbj`h^p{0kT(5A$*Ny*#$Mjo)R{O)sH<93No#Dz;zK-T +2ur((+WSqvZYXuzO}@&AX+T6bRVAx!)>H*_9;LPoFGcm3oB;7rAVn*7s~hYYK#CYt2+9;^iI{TM>(AI +bUK+s^u+s-=1PC*<2OB$XxV1V#R$@O|@G`5l*vO}N+HXep>$)*fLK7OP7iGV@U|V5(JCijxBG{SC29h +t>j0OYFTHK1gD^6{Sm@zrdJazU`Yo(3jS*f-%CtJM-X?=9Xv~ +-0Qctb9zSL)pRc229DcdLN&j(JXurn0>%s89@Oh_{OGMbf^b>e7Eg;%VmcBFm{}T1rW+_I +2BLZ=)X)n2VZMn8ke8r^==LS5Km4w(KK72k><3;zY1mGtogn#lXowx$ck^ACFu@_C>PF3>KcUA)$P(x`4sP4k0kyL^g&*Pw#3s0_`vKp +6JV8VSz8mhM+#)_RHbw0nZ_AgH?k~LV*x*Q6~jbKP=7*)p$;f^O8vPl1{CbpF6d{hNxX}LO#e50rX{8 +$h41<7HJpk^Jfri2(j)W~XbENP1xm5y`7tv{CdBEanD&-^4TNfNC8!1SUn`%T$In-ob#o`~`H5kL`j7 +DW-(W+-{|z|l{|lYAbSs^^b5ju)*}O4&PKRkpg~FvN`qZl6x(Ib?qhW+9XxqY?VCk|nRN$Pc-{#kHO+ +|iwt+r@-dydZCMVoLhE{1H38cRdEmU{C$_#EPdup)mS22O6&|%x)<2HUpYA7tC+;RitLou#8ei|t`0x_gUO}BV<0gH49i*rBlJ*wQTCN+qnRz~WeL(p +6OVkFlb*vAEc(R&jZp&P63GvSp<0_BFQLP2Gx`NHUTicJ6RPoobqJrxq)l +DGz2wANNRR?1hTBXA0&X50(Pqq`Bs6kRE!-&;uF#oU|B}Q3>KJUoscXdr^=Iw5@ZshbeUuT_bq}rzfn +CG`*P^(4C$1CcVzWW#!qmna35~B81mA)+pLA$9r~x9HhPA^diK5Y@xRDhvhvXeZP{F# +pn#3s(0+q#R12NrI>vkLs4>PsM7YtBo#>g~fu8EuhfuUpQL0|Fmz>nq?`NjCgik6bkk@^#T6jK#C*# +k#o2-j$7O_yfpB0@{l?m~U$=!Pz?l)1F70sgfShCY;FA3Nv#RuQq+=o*>dYN*^TSK@)YF~R5a)cb@Qk +lQ{_r>F613x*R5;9QIln6(Ivho{r7CVuZGHeg4*6C6S&zJKxbchY?`GaAP}^0FyJd@@WY)ajV-ripW8 +4N)+F<8JZ8{aCI)tA@9iF7q}%N5VaY&Y#6doi;!p4hk(FhaHVUM6DYf?~H!W?ie1MNx)`uKb_vaz8?c +}D)LSE=tpipKU_!d-o0L&fH56?CJE=~zW`860|XQR000O8HkM{d`Y438OAY`4fnf#gVu>SUi#iNlDjCzI%5U01 +1*O*-m?z$VU)Z>)VUsTa_I-Sf_v +0`yNZ|X*gIA(HH7OG}^Rux%Oi&#HTCT3g-`>k46_Uk=Yxy%>sbD8maUZ|CQ&WgnX-cKgAS|3jsd^#FQ +kFsHMwz%LK%>EA5*O7&%vG|Ck^BiLk+z +bV@RjFB&x6?iE$#lofCsB4shBgM7i;e0JFa~AKhPR%Rf!)ZzQW1E0+l`cmc_{=xTt)-&;yxRcO!)$h*O&g89Nbpskp$F2omAdM4%2!f+?mgdC +zanI;FvP7wvH4A@wrlT2gAUO=u$`N&%*0E52sakqfn-=?o7^QYZ!5n})1q(6N+Nncq9KB;Q +G^_a45>f!CN5i^{Zo&3FYm1xB^PeGt6WVSqXnt0uz?hTan)|IEm?k5XQ(gI3p70egKCb$YP5)6k9_?MNYc1%Q69j!XBgWH5c>Cqz!;kURuRoo>eS3NK1qR(s{wy=3w$yW==5;NU9DXhH=o^opu@TBby6PW<>;S?b`)#xi{p`^deI=1IHJy_ +5DF8sQ|9R{gBTk2K8nQHGtB^G|VqiYg`agZ^r9??dM{nD8bh8`E|J*Jqp`!3Tn1+$0PkFdduTTO~s6_ +Z)ga-aNz)ua4rQL(fSpM#*Bz6)fsy7X4x*>N8DlG`Pk<^{Z!drS>HOV?_`~VXZ_Yp9lKZ7hmNs16Lsm0uWCj65k3-yWNI{gSa4-J7H6;_bEB +?qds6i9V1hD@am|GlH{{4*|JRj3{_Y*oj5um=Ygn^U=0ZAPYn4_{QLeNp3Q+;sdaMJKJDGKYBRELu}_ +~q0m&8A!kynhCR2($6?w8Y-d;5sR+&$F)>ofF(2Au9(z%}g6}s7C2m1`htjCqASSY??zFC1T$=T5%&3 +TKogJUeRS+y*h44pi4JyPZXPgzF$0tHLl)Y2({cr9|o&k6%MI4ZnDCvwbTbYldON9Y1BNaz^`5kRyR& +(}0}FHTGY1*&!<;ugCE1~ua$afJ*sP|r5Vw8N0RTVyx~n+h&SHu@S3dyEC6eEtUxh-jVRY$+h6#ay-o +uEG8SPk+ZTTNP=OiE+2UG&8!H!)<0ok@?;0XrmH(4F%t6+=T2DG8H*%YC+FEfA|6IS1(o3ES9V;*itk +K{1nQEgv6PNthn#WWnNW%ajEap7IEwhkmvF}dx2n7nV0*~i>Oyx_nS7+lHUnOj+jP$$S+^G^@fIO>e` +6P*HxJ=BfDcc>SVACWI-!bO^NydpVR~(Am>Ter0DYt5WY0y0oqSn2oQB4??lery~wF7y5JI7Lz>bkGB +wA!35ef=UK@YR#wYChMyrrwq+zTg!3JXCP|sLzi{chJhI54M@e;r((Om~ahulvyVQgZKo&bA7CgBi+v +wtVCrkbtWI$Gq>y}XsBNF|R7wb;R@oy+&}r>%dq1MkjzUj%$eGW08CGy-Z!ZWnG+BtWhzv7 +|uDVct^YLN>t>Jh=f*6MY@A>5OR|{cyXt@;Q%8IWNhF{E4f(GoF{0}l9@o9z{U@-^r +#+FnG)|s0%?##4SS;*StHu0fOkbLj@bu1R5Og`nD1jYfV+cJ)ch9oLw#v&&biSl()9_lnYaJm}sCa*Q|@oIRi6_*V=@`P@t +Ry>80VQSw``G3)12(6&2M}g_D`@d58;sG+!Hc=*cN;GbVO!C7k +CYRUe_8JS6=`{nOOEx29X@u6L(U4p#=Z)14AF^-_v`7w0eS|w%uOc;?2jBr1mtt6fRJV7UP7LWVTK}4 +iUHTg49s0lzrToFhODBFjSOqrT0HQiyG>>5qJf$nN^L0mW!HPMx(GXdF6K-t74JikQdT59!+u09y3Kk +Vpd~i#KDcfApLxJzte{|lzeKyo1a^!z@PM74|Lexsgz6>Boo99V@)m1zP@7oj1f8zcq2$7jAsUu)J|* +S=Y!Fc`T6FpFu;1Ulp}hv9y7hPR*o9cvV#ZSs^LjTq$J=`y!7cXQcpTPTCEl?XO=ao|Q;=I$y0}XTJx +u}ZQ9NG=zqiFU_9eFW@c#kIw6rXm4DSUs%g-US5mW_uBRH`r0HV-8bKl* +nO<7caL{(kOVw*R1T0Tq%nSbV?c@ds%&w(YUXqKfa-wJNTVN)Kv@{{KwA%A@80yfs1a=94FMVVjd+^+ +&Kle43fVq(QXRP?YHYw{4Y`O|K9OiONVBZobMQ8=3tO0XX;|*ZCZ`!^mDn{XhFL~WB;Cy#3boZDoPNK +J^}{xWZS3=OgMZ!DA$QP1tBIxFZzUoc^>x56t++@^DH(()51uHRX-RJsP+B4ZPh +)K@w2LJ);ZM2E8U8F_>PVh9Vsjmp|YRPi^$}Dje{3O*X?&uaVZ_n~Vv-CF$~FL)LEdLe0%s|820c2K2qby^n=r +z?Fb9E7RNwT!|1tOpmZ)or-mM)4hJ1%|I%o#pnrP-^wnIT<;y<3{iph!Mg@&`ze^8*$8wH?GI13L)Z5 +X_Rx$6yF;|W&rAt^J62z-+XG1OkOQ$Q>otPBg+sgd#$);=^=~%86iqN4nc#8t|A@CQGUrMPNH)^~jDW +1!q{Uw8UtJ75=LzmMI7YcPj^Vh3_6i*)`kY~7g7mjT!y%hB_>;eXHxkkv^5%XzcszMz+b8|e?(D(Y^b +F!`;g3od;2FI$genr4l_#pGs%`5SowJ&?KKblt%+l!BK9p#Ts)FF#x!uh0W?e1t_m?tpPYN1LhOR@49 +LfRwm1b)Y$FIM_e&HkfGe<|#P4_o@#S>!M%Tr5aGHJiYlzg8I3c_G8A=bIaXr8GQ>GwMH^HRsJaG{$6 +>%{KAP)h>@6aWAK2mm&gW=Y$uclLb%005i-000vJ003}la4&OoVRUtKUt@1%WpgfYc|D6k3c@fDMfY= +x96?*RE@~4oSZ5^3#O0vSf?$cnRbfY6l8lhdnsMCKCf3!ROeS&c +CuHpJ_IC&Bq9)C@Q}n!^1old<^_PXH+LVZY!SdrPft%zPj^pGV=|c>U3J@SRky*is)M|2+O#P0auuXy +7R#ogByU^>_{N9 +<`t=eptfT6y>PwNtzX^yz3^R!Xlf2Vud)kTvoRWkqnJ5?^KOmQK#N%I1bs2f%5qVMTWpltJPoZP80tL +nJPA9R_kwuYuI-x+E_Ia>iqm$tgBdf38nbqLdx$g2CYsM1WAK{6z5l>nNvpeu3s@VBj?9u{ib=2h9~D +&bK8*Cq2rimxu}x~gaJ=q@et?9a#$uYf*fx>2*>Q`s;pDSi`K*hRHSJe^XQZ`xV`9<@rdWU=nb+h%qY^%{t~T(?neRhcx~yewU+b17j*T{JHgLK2mBv5i#p%7rsG$1`zF10agsWQdbg{jR!!B_K$Rh6p4WiAPtrwNR% +H$(&3{n|j`t|@#+&L+**aCZ%vW1s_9K!XiF#;*^I#g^uZ!u?(Vs3pTwT6(RH{qAn%DhaH#E30w0eyIixEq3T_ +~Dh)vyQ3vK#&V!1$yf>S`F03YJV5l?HwYu`|t!c}eVuFoairRErd-ivt6tQ~3ABW!$vf1wh%LK`Af`? +o|LH?k>-i+Zq9a7Mb$_(gqru(XtLVB~H$!D}YtjY3ty4kMD}AxI +)Q&!C9U77!_Q*m$+ui_v+)e6ccU#(llBCCFZH2~+Dp7hw9V%4X$Di486HL6(tN&F;^V=MsO0xYo@SCF +xkDUYKu&0wX;fOr9P8I%$l2*ADpUJ}8eKx7Jm0+z(6(ZIxn$12NV1rk0naR?npac)6`{juID=H +3ZK{5VX}6x_PGx&38`SdlJ|8TIAGSiG;#hpoMxR0Twm%>WaH$xRd*KefI2TCjGpAcJ`gU`R?p{d-MI- +&5iCCXz92B$P`D*B+yDXO?7X{naK)H6y~<^4jE3s(Ru*_68Z}|7xatqltosoD&|mU8DtZ&naqN3G|wI +l*7Cs$d~oeO)3Xw1niYfnWgj8AB}wufDnxTHZy2Yq0*9rcQ~5Gov|p^?_F;cvqg1n`IUj1-p|6NwB_< +bgi&X-b8=zlXh#J#`eUkbOMH=QF;KfJcE^tCf|*wuY)c&=OAx^d +)+f#1TbWWgtks(N=XmLtY;q-j$2-K%I!W55dn>jl^yo_dK~;nY6&>|@VvtE@PWkI6H`h;ZB3C5Yx$qh}((!iC??{W +HTA}cyXP^uhtLl8ptKAfqJCK;S4NSfBr@`-kA3S?vReI6pL#zx;uF4g_BtjFur0ALTs8shMf{wH;uyz +(J^OD{$BzXOVZfUVa&w?O0t>@DSr^3>b5gR2;ku@D}MFFd7Z^% +E_2Ce!&ecsz7!z*qZ8$xjdIK18Jwsd>FLJY>pjk9`A*)RrfM?f*X +4k}`r~_**E8vab_rbTe>m^RgzyH(RgUrM3%%?1Mz)tO#ox&Iam#XPmFr5x6PQ8^7$I7Aww3(xo_02bB +p?k2*9};%cFef@Z1y&I#JjcJ`3Cg2?{F_rOcG^~_{MfZ7Kh_-?R_K%jJ*Ej3>$F^fwV*leIQaSJpMwt +sNkz&jWznv~(>1TdZ?6QgsH5sEE +1%1aMZyg+|ipgeae9n-@Q0a&s@7q~2H-t;S8)l~**SXfxLB6<1-^C(}; +Mhr|BAQXV;TebcRLnlKDV$wE)Ae4vi!qX9d==6?S8S<9w1gCo%|UpgeVIGTsngF3&pmJm;BpU?wM^+t +j-)bR0EaQKWo>K~qOPz;Fx-IiUak&l#=}B11o-;hc+eNE^_*szVh77JM*r!62sn85F66M#6Xm_cdxwb +;G_Dfwxg&y`J`A2t~Tb){+ZWjuhBHZ%#R5@A8pbL)Q}FB*LEfCfZkM^0{=xDZOZ +vx(%O*8Nb+~t>o-3#2?c8mvqltYl7Ee8&|ZY^?;TQvTwSXXKBC>&*ZNzib8t14Y4`hPE|Hlp{)L}>T- +L7{_ZXMZ;}QKdjJ$prGl*Yjk|tXSXsVkL#Rn!t&uv>KIqW;7-UAO2h}U{F~a385t_@DF%|C2tk)nPEyKm2YA!u-d+iVTKdwZ`EEFJ*g$vAv#3mFdlhraDp@ +u;bF)G_E~dLJV7EY<%L_y5f62H~46ot_3HkIT0&8`c})x51`lAS&*qV#ce`yJQ4d4KV?!b(7twBWBL7 +}+UCmHeB#wxb`LU8U(oTdXC{IWHP-@=dysa8a-$YPy&-!18pzACF)O^51$jq}jzCbD73%t!veg%%Ef>vGl7ZwrQZfx(cRcdL+lf +QmdUWF2~W?Uo@lk5Lipu&EayN`|YvW@DIEZaJg$IcyHf)9KWKT@$+}X27v7j?|3!m4AT+m@jiJ%>13< +H|aJ&2TXpaw0VY2k-I&2A}qX@vAYcmYM}T=+9gB2Nsr?E;8d+sV +RLenfWjX0!R6xDpL?09En=7UH?FZB%VV-Uf-9573{;vX*?w?W_|oIJot8*y#p#F^&hqUbU;CBoSqcYI +HaSJTZ=^vz^?u^xY)7Po>{kI@k|7M}3`HTp|*v75LUib!9PQDhzTomkv$0X(pVg&e#G$z|eZTjZ_Jlu +x7UCpTbtW^5`?V-)IRX7a$Vr>Q}G7itWvA(H&^Ao@Vh;WQub1sVX;DLt{kzorL-j$X2~FLI>Wy}iW?* +3V@SI%w^+IT{ZqZMmXZexTCOU*ANoE90P%Jgf`~SIoZDJ@f$612^2+UC-x}wduu#{ND-R-8c +U>ZFBqP=b}hY21B)7h`AjTM+>G>Xw43sGL{v9--c1Fl_?S%Fh`NSNc`>K4qQuEdQ!R4cI97rCm?y$k;Kb+slpi{I?M}T#uSu*0`r1Rx94d@7rKP%qdt+qSrLWpdQs^g5F&Co=~AI~CDe#qSuAn +dX3N&HC45g`Z&sp0Lq;%;mBwl%DcvtZI8u*sg84AAJkqy2ym2`waq4J>4ILkLBq)VN&IHaW2 +jbksVQXBgNyew_=nptG~qAapU55sh!zx?+D^Bou`7s=-A+Pf +3~sZr(ym29PJ8W;b~HF>xUW=_lU=rm@Xz(x$#*x_$SC$hv$%f+%%@Mj3g`r&rG2UOB@`QVxV%HaOR~l +ts-0L;3-SBracIHi#!twOYUepHim(G2SFkdmq6jaHvhM6v--L~82?DTX69N*2+`*XV8ZPU|jzC8tj->K&G> +F=IAvDn1YBfyGxEWK8Z;_3vT?t;6t&QsibAr=y(<|c%iw{p^AQ<>1yQfVEF!tmx*wj)KX8N+>^xASgs +tJ=7#SB$=#zThsLe*4=~rvnBXb^wM`u!o|kzq175y#v9Y89XV_^*(P@Ai!DcSB>crDV(Vj?>tl|el6n +9T*LueUiW>{U*(%ENU!VBzQpwm~e1|$q?3{+|+1VqEemDL0N`M>vmHd%K~ts84%GUOJxKI> +KYh32%V2nePK${7LqU127w8}e0mTzxQ(Fz!r#4W6X49QP?IwmkN$oOBSFWG$dzIWGM&VgHi;+bKkHS) +!-c)_w!}XjQ5pC71w$cwkK75>>(e>kvUlPD0I3SLAe| +cEb)OTTHcamljdcT$oht%FKNBH!`LW_`hc}0tf!$2?Pp+;`{)1oj7n4V{NK=l1OJ>#k%6KffQ*kqBw5 +s;^W8ZhaJ5y7JS{j}8;|Run6UbXcW^)=wr~qaHdGjh5tC?ZH63qzYdMWk>Ug}V0TT|}TJp}$Y^1RWT? ++z?!sXHFiEmN=#8WYRP-|lFn0RV6Oh176EdFF9w13V85PZ +qI=$GKxkKSa$2n*x1lhJ_yLhDRrvS;Vu&7(m2~rs7ea7H2B7Ze17AeT@f59V8+FX;=<+twyt2xBh3xL +YP3m6#Iw=QixxRQzyMk(-!Z`68In}+6Lb*Zs<{T%bc?k!+%5)uzba0voY>`e@PGR&D)$RjiXkj21y)NBzX?5Wa|<1Vk!VWi5tnE(TIN{0m^OoOaG0Tf(SGj +w`kuuHXFrRZaYvGImxW{=>Y4p`$M1RRh(beA(c+*`!TNQ8F4eo&hNVe&?%aKlktJAEAG1XS4#4m~M{L +)`SBHUqZNVx|hxjLyUHnGT#S>y#sFiRmTu0-qxaGcTq_0;08UV~E`vjA?-JFr6IR3;yz#i?>&wK3w2o +=XdWvUcP&K^_RauRT!J9#6w5|jFd>^Dn6mbhqJ^#$dB~=wsv$I^jxyKmxCtH)1sBKQX~L@_YP0=0scS +7|4kzUWZh|J$O%5w^1|AYbRJGOy0^7qQ``#4(Vu6(x}g|!Ff+yQ673VckX!91ZxvXqygs1#9AFjD=&~ +wnqzhg+rw8=;>EhLkPp>~ZUHIrIyK{x7gfK+V-Ok0{=`QLHyIpnK93!_J49d5nU2wz`DrE7t+J;kj1B +*26lu}6y1u%s@4R$iVW0Ded77e +mH{J43wlO_zmbvb`U0ek$Z$@)}v;M8mAKoetq`zX6B$A{mVFiO5{u+8>mL4ei}V?Fr279 +A$GV_}bw^tJU-N@ETMu%^NbCRiEaLTglvg}7m}xvBe364(0O85!j9G~p$v_(6s9wVdS<5)QtxjODK^g +gnPnW(rA!Y!n)mE|4Y=&VQQauWO2%ennr+d$A7tkN?c(Iu){Sx5< +N7vQ*@xsDr!dcG6T=ZP-g5~$o}-ZbTncpAImPYh0ethb7u}}=8Jzb%37ud`oTxe!$yK0u6Y4NEI7G}P +e^FGL;+zko1qes)J}l46>%thN>~&gr*sPou*;YMfoPQV23dxb# +K~54f~}fHQ*AKL@3oHv}6A2JJ()k%Y?|_9IPo{P|!?X{O=7Cd~@x@d%ftIAZ_PWdDlMS=8Vg-?R5~~57NmMR(=UW~rm&QPBS;Q(izB4mgn(5Qw)rO{PdrwIrFUY95<@7RWPBD +Ryv7&~diP?}Qq9u;qA{?wI8xLZaV}ZyaHe6>XGIiYi+)pd_cf3oH3dANi3p#%R-4JZOGD1j9Uq@cdV! +G;R8W@TiG&8mT_tkWQdS-rsVaROIZVjaEKS2D6bRGR{_*(Pp-~b5!!I6t;7tJ#!A3@yQ!G;^TK`dTE) +KR@D>_jDWsA?BUcmKo8*R9iVgbI*z1tWd1~@!r6mlb!wCD=88gzy)#_05lH9E&_$2nxuQM$I5-$@$N1 +n0dG~<)H_siShkSOPcJ=hj=k#d1!}6wbI?wG5?ikaZf%6$NX8yxDR3Fi)dPlnI)AdI}Km0S2%5vlow0 +q1*&*RZ7H9VKKs;ASV=?TSoXRHgR51Oe=QIF@GchRG}xS9-pu8L!_-%$1O_=_RFBOw?p7s$yUIAXx`h +oTqs%^uGPp>7CpJ}gcJU(=pk?Np_Q&(xBDT^h1$$AJ1d4rH+6`&~3`yKA&JL`yu|gY$ORNQOQx3^fox<%X$9)mq^mP +c~xP)-!{aT5s<2dsUsN>d@4mf9RZV{p?Tg{73jIipUbMs2M(IUEq8P#97_FM+oB2Jg$pPUyqtD>5xg;&aRP(g=!4UqcbJ?TrJGLr~p{NcZp%zTokuLmcV91oo9*``A7fe>Snj)3+d$UDg`Kdk +K01oJ0(_rM?5H+}`5K6nDbf527j*a*N<+0mIvI#NDf!SRmBAR~;YVE8fH-NH;w&7YctSKy9ug=i=M^T`Z}Nl;lh72M`Mq0-#TE&qfly=`TivE^toG!7q9#8{O0w)1RCJhJ +BuvL3JxL|4N5#=N|{xQwMX><1-E6CipyH>c=CZ{irXYEZN7?Vviv87}TN3$qCmyftnL{^ltnnMuk`J3 +m>5cJ_{E2*}2PQB#uTWta~-<>RvLY=#)eWY`Xv2x#CIQ!9=094&lnkjIt`dA|^e-NFuuy4LG9D4Hl@w4aOfo8;

@#JN)PffAZ%Hk278BA1HHSi3UjBGWK45Zb7xvW9oFbaAvpI|}Xrhji#|%%z?M?1!6K<> +3iZh*({}yGy8|X@kG$f=ne;Pfb+W6`UaC!h^mH?J<}RwDP!y{m% +-pcT?$TR)3ejL;9#l3`_Gx@R +&BbPBlg99_lV+U{c?5lAg)!Nt+g_k!Py>7o0%pjTsS?AYT4)`xlG>Tt`iP|f-l90S< +95-_@-=zANoaarD)Bh`nI6}7$hU7Ld_x*xra~A~bks$VE0`li)__wf?P{RjA~EVg8rQ?8S6pS;6~^;2P#~$`mv +ur?pYBexa$(8iOa{{c`-0 +|XQR000O8HkM{dPrb}Y4+a1LJ`w-`7XSbNaA|NaUv_0~WN&gWUtei%X>?y-E^v9RS6y%0HWYo=uOQTi +*`2Gj8@d4n`miD?R-o9!KG27vP-y8|Vnc}lDny#+pX-o%5DtlO-vx7nbsT)BE01p2 +KHntQT_ajP5<<@q3aC>yuy7$I9v8`26i(1|ia9j6nsga)P? +G(k~8d5t0ZwLSzK;^`()IITa0D`wYW#Ug>-YTu}T~!rX90V3+sXVSLb+iV`a0I(T_Krk=-3hI3NTg1E +N(YznRw^CAbOHM0^6J%Jzg@n)x)d+PYve?Vrk*h)Wd(eRcQuiYU2sx4oR_L(K!);ia>=`2udd$amv4RtiUVUZu#5jL#_ +zzcl?^SxL*SI>%ViR%L>q0=q5x*^=`ATv+ZJ2|fbru6gEFWKj3U(yUXH_`(a-pTWoII>NGt+%`Agn#m(UGsb~@wp0p3kol +m%-Ul71eMY+pDu$veJZH);!SXHWv#IXzmp($0v$5?mMH%fiGLo6caS;I@?-BHD_}(Hp=qFi*^cDjpjj +bUq0F6h4&<;*BxgSsvF3FVs=JBmX#L`N$8=kr5D%NgU=(qMbCow(9P@XJKi`js1pR&py|tl{l +O*^f2g)Vo6~pb-nbo_mm78JukS!B&WXElZ1e-Qqpe#-jxtv4hc6p7Wa=yc##dvFsR$YY{#U)0cEl~XK +&I4kreQEWmWA&D?(Xp&Z_tVe@Tm7K#jYU8=uw-osw&7~RJYOF-72VCobDYfBjJ{INTng?WW^E_v)%^v +4@1Hrl7$kTDX6D5o2)Vi4g`Z%PbtNMI%NEQ(itDnZpWJkHh-8nSW5?f*Cb0AOgv=Pbz1pFnx!l8Y&i` +}9u>8V;|T2OLv*#eFLac@KxQV8f$YgZAZE$Y@Pz-qTX97qcCroBslc9)DzkJLjXVN*I5Mk-DKn8xt=3 +kCf`fHig52US4>&%&iJW2OXJ(dV9H{JI9975DI1XBt>`_DuQ;wrsg33<}-b1@i6@e&_RI?3qEbo0gup +9sz9?vQ^OMD19&+n|Qggg}1I97R%+iB@pJ6)DQ^!I~2lH!s0W#H&I!N(WZVOAkm%%1Xicr%z`VAs?P( +`9fMJ9t2J4@fc+kH5Wt!AxU)%=p)S@_mFLE%sqoB7Mve)8$fpzqd{9W*wzrz;{x`<9VD-X3HWiWKk19 +^VT51-A$u0{Tq3*!Bqe^&aPW?vRwN{KR%ovgR|T%1l8Hxf^&>i(To?0K9te;t5 +s{GV0734t~{;rC`2AhL=P0uwYrYgYLG@&9RM7o0(XGXS$qcps6#?&oG(Kp~Hf);or@?RK-I=X6HKmTg +;r!8~z6_uW?tNi~o<8ES=0~k@8zsQ-eVwXA+v3)yNiWc81lkGt0tt;M5!ddavdXmybWJse|SGD-C83x +>pv&bgmIIVXlo=4VixSz3>Gl{{m1;0|XQR000O8HkM{dg^8Amh!Fq)U{?SD761SMaA|NaUv_0~WN&gW +VQ_F{X>xNeaCz-q>vG#Tvi`59z|v<*l1rw1NhT9-oL!GE6W7F-jhsoQqLe~Wki?iGbO_S6=G5+c>>KT +4ZFd7835t@H#L4c=v412I33NC5`k@JN?N9Ag#_fI(wRv>Srn6)$qS_kUSl?j27zEL1m!-*Y;|II~*AK +*W76+qo!Ww>)ZEtQq-q_yU+GP8F5?u36;w7AQ#4x$>V$Mz?->sOlwZo1EgBiQvNgVv^pCYc+9LIT`1Y +wW_T(Y5v*?=cJo&*sHz`W@+416yMM6@BN+z*C<&jvv(-CC`~IeRuvlId={JqnU>+IM|1X&1z4!*m?{+ +|c!cP%qg+ox?LGB6c(8u#iMBnF#m*wAjE)JT?qMHIy;UU8d8ih!b}b +__2_n0up4vhh7>ct|zCrf02GL*t_cgnMWI`{PWJ%=JwM^Yi~O*FJJ6zJ$ew2tS?hC?O5CPjUR)_JN3eK21_DZ2x$14AORHGU1bU5DoaPJ5DAcQGa{*6GN +Sna$ZO4w;3myfR4O)Al+fi`GCu-L`+=~kJ^1ta?mK*!uqlig1%*PRS};KkGdYvyqmZ@Q#jiU+0xr76DepGlv%NjG1G9zz}x=<~Wfz;75)6NAKFJH`O%F&5WaKLiQqWf~2zPI0fZyG~eyK2LaUFp&4qC +e*=aPHxf9oHRkAV?Cpiq%D+8#4N+k?LA0}7ryD$6zydr$lP4cqObpBn^b9r0Y0k?aN^en +`P8!i<=NSCp$IfAy&Km3RB*8#U#(~6GaYCHC?J)QniG&3M?u9MZPr+bOIAdmg;Bp{ifeAOMi5R3IXZ#jCFOdZ*>qVQcgQaIM4D1ae%BtlnY3nswdd<35qy!FFgK&nl!Q +&n#fgbpM1Hup$zjr1g-opIgrI12n{at&c{uT=lQrc+m*aJ@5wPHv=uXvKi5gVpq$fjO0Mjhe`ky9b#V +cr3jq!3bdAu&QKGz)XINThxwLv9L6vxc+6-^q|E0Y9doUYw#80Ng;gBAy|sn55(b*W#p>>#zn{79<{E ++SC?qmPLTi7Uzrr`obVUBY~HoFZBgfh{~0+%h?n@gNsH3_97;xD4rJ@qbpPLkYjGv{5bltm{S9e)M8Mbyz$hG6uG +0|5aBbpOV=k*PXfsOhL5yJ2^twwr2-0l2q+XBKE`RpF#DqrAW=AT(eP-o7BR8N+=w&;QH`dNj`M8deH +8I?_Zc`b{O{OKbdL5XJAn&8*^G>SQ9V-#T;N$yo{j}@oW2kt_o5clwNh!l$$Zc$u$4SvmvPE-eQ@Jm7 +Jp3;xtd5(zKgc^KyAPS{R2LtTVZTTbXBjCTEvqZ5nmzqbV?Hp{b?+y_$#Fm9Tl240fcYgHmsaQew`vB +6r%uq7x0QTz+jhz`(xl)LJtHK+F{U-y?EC4{U_gl|LBLOjW->4YqLq1;<-hQQYAX8pGtB;@P^h4yrjlHF&xcy!F?-Qo%kK^t9^Vx +JPy^X~jo46h;|wkofexY+#8XRv<4Dwp{hJ-M_hqDUN9q+7A1g>+x3u?r{@>0?5Z!EKA(aPZ176gL#O8 +QerIX~bNzvdR&8$O3MdWvRhg$JCdLy3nK;9lGZ2(A;m;v~;MMrsTfy+x +mKcPHo5368JxEnte&`ZlOXb<0 +ufttwed9_p-MyA_4Yr<2R+>c3Eb1u}Z5BBNj&jn;rx1_}Q>K&zk#P_iKHoro3{GkCzW4|w(uglDr*m{ +Z@>i(ys*fJ%|y3jqi2CV1>zz)2Zg@M`uo9K~Dj%jTr*Gsrh5n7D(_953P%=C%a +?iVnrr^Rd>dqMao01vy}i&%`nbC7`YDK-uU;OW%g0PC$6(it!!DsIyf`iZ7$Q>zw-A?$uZ98|03CI%l +NKUE2kJ#ow6PQ@~Af>is57qA?f9h-2b1FGh}*?)C*a`w|MI~3#)Sw_f{ENzmA7%gc7HG*R?^2If$Bzi +NReLKLnDpu2o@8JCO^!zM?eE;vk+p?JbTF`Bcb{b~afF5HzW?>*DWy*=Pzs&MD8iI_l3LZq7r4(rWY3 +U`Oss+58OQnD&>vG=HWFm +Q12Am%!$NCFFXz&CK||BsUI!Un`25nP!=TWTXv^T#)$)&{NG&)3V1u3ntsTx@Y)J{bbnZ4TI4)?kFp! +4;cIbga0uw_(M;b{(gTwWl338+K<*&=^(2NW;c)R?(xC-+40Fw%lpUcD~t4*&CP-k3)-9B(6l$pOIq0 +31i{~Fq}yVSLS)YSxq?*rxYB})Rw-G%5ms2#;#Qbi&F`iQ_L*h)p%3;@gCA-zDeqhN!Ey|HKbs +qZHRa|x6kg|9CDsg|S9@UDayYj(Ip%zsY)#|EPAbMA2T&a;#(^Kh_Fa)UJSB! +9N)$iD?kwH{5!Cdb0vqKH#JWob<=QNjettUPacNm{U61ROt@QDuxzY=K$lvF)@S3vGY^vCR&PB%bH!- +*7rH=W2?6GS>W9bQu1>eB$d45ksR(1aa;k2Gz#U$ewKCj1Gq0eY}F;9E1}9~9<$OEYsx>ebI%l{=q@r +HjkqMSV1;;@es?eszEr^sn3tXrAbg~yu#qt642OTHIArv}Zc`~p6rjtKO|_#$BHGYfexhdiOan)lqHp +pZHYz??-GmPc?KE8m3zm7b5W#7h7}r6vQcSq|F~xcc@fWX?6ryZjWRscJWUZzB-!4_1r6%C4%>eWr-Bw+10RY1Am{p%TDUpKub9O77!dwBYAt(TqyL-AitoyZBduk-EXSyxiKkYbk0$b<~@!a{X9%Tx +<@iMtYX*)v22L`M~Jfgx#fX~U}F~W$cGq;( +Swzbj`S~m3n)PS65lu;VzOQjR+{vB4avh{1_VFpC{x8zy6R`F_=jxVycb*E_L$qneUbWX56Nw(KiRj< +S&i(6Klbgs*}a#Gsu+v;8@bNN`^5-pcTeWu*^r|CPTt{U~pHO=yP>lCH8XR%qDS(XvHC)C)fh9YHJ(tr%( +&-OU&UQnWV#^+Q^ogFg<)A-HZ7McVe@KFM~lyZ+OUav}x^mw3$*{DLnBN{4anI06=|w6$haudj6co94 +kroY*g0-#US6`jZ!a$y$$Dxmk4k8B1Q-XwMX9QG64LTLP6_91_hHP1fpJebQNW$$(8=v6L2?3nlAbWhDeyspNF-GdZ#8zsLePw5`rPD2s%xZ6QZv18JdR0>r^9Ne>on?YW +X>TfBJXTKo!Ji2Xwz^!>jTL^#-vQ;`AV$9xjMsRK3=je5Gqk*B!OVdrWP2s*e1Ou2I;J^OK?!Y%@glRZ^FIoMJ`lv``q^s+?Tk(-h)d`f_^uxLtRhRZv +;_0VFrERO)nP?IOu2knep5+NdEmKcxz_(`J09s>*;wBo!-ax%WXiRUBLDAH9e8|S$HD}{sH +0}op^T%FXdPuXDo#yPPBk6kdUL%R`HKN0uK=GyrcU*rI{3RId{qT76>C@-==6>wS9#Zci={Z!2q3q)# +LF&0yu80Ttx~AuB`|;!XE@_!Cw$bJW^<(Z`6)~_i%O+~+G@GKli+s+T26Ok7?#*o%tlvQuqw#Ues;p6 +*z;E%TNbH2@9>uYUs~W&k)(V4PE7O)nXQNgNDj#E3&c~Eqp}MUcM~yMRGGCG(x4*wTG44FRGZk+CurT +}e(;ELz4A#4k`Hn$%s9qVDZ<%Wo-u-@4&NB*0JLi>e9ngght__MR2j-D@zoG*x)#S +xQ53rJ}_l35%ncScDbA&a8}*ln+F1x?E~#udO0j@Bqg$eRWbaH(%W+TU(5B4sZ_xdGm;629`l7b6$_K*+V)BU%-i~Y+NY@KZv9Ge7if8$V; +8+E_l%H}t7xRR0TXoo&I>s;=i9USFD=Bk_WXH($J^zgj@u~g*Lz~TU;b$rpg{Pp6<;0YZT$WG-uRKl5 +uF6}0wLsg8-m!3S@q|eMAY5Z$3GP}nG5`E!pQOg&FhMwePsK#p1 +KLMB^{Zq +n91FxyGu{*vLl7V#yWoNV8tq=K(g1nc*D6Ax(gv;*YLG3Rs!dmhJJ&3a;R{XjjXbChS{CR*Yv8y%|=h +38eRPLEUC5Id!gN;aW*sd9?x3*e06cHH>-6v7~BIIwzptb_-?8`Kof9{1Jtj=SD;vV4haFkQ|iE!;h4 +%iYwoFfHNo>G&n8p@9074ByFJ_MLRtcdUT}@?4J$TQsTJw8id5bAk(eAL8fB{+|>!6XFhWzpaeI3^ZF<_eJvVk+zb1BG>~wc8$;q?`S*$5hOH%%5Hvjw02LOT~D9MSF-t9ZR*T +y7)!C<~H7z}_1;%TqKkCas{ +3`Pz$>w4wd?W%a&{dzh{l5T&+iWRj(XE(grC1gcKqQ5jB&ihgW-J$_NakXk%@%1A&Bsz)C*_oyQ9wcf +@plCxJ1-+B9YOg8JWcF!A}R^tX<06Y4&_^Wv;i$dh`AIl_ +%Zl2$YXaTs4qjSJ8jjlzOi|8Vk@U6@c*XukflljF!6xpP_j&cc5;-o0^sHcq$^m7&r(51U&1^fa%FxZs#(JiHVGfI0UKz4p&NAt>&OFhb3|eq0Hqq@F+@4pbLDxl0;Z +JlXIp8b>ziuInCxhq8qratvY+<+t<#)r?W>d>MWvVhKVrj!^bk`3w@k8C6hx89qT0fI!J{$-Z&%`w{C`EqUb}U?q1od4tzY~5<*dQ0uBCFwXE)^;<>R*L#*f}YaG +##LzZCQv~D_rb-Mt(Doek9CU~@=uEW)TCtSk@s~S0;#;&X1(=ufdbdZyE8AEmH0Qa)I6j`DF0)DH%id*yYw*s+IucxWJ(GO{M0pfOHzAeu|ez12P06if +S3t&P+f6%?WEYPF|Jrc)Wf7lW5%cBHjI-^%dhkp +YD_2d5GOR+0@4`n&-bwd(8ninZcaY>4bnl;C!(& +TqENi>!m?svhoE8_{GJOSM%IjG(H9=p!LxLy`cQL>-K7=)sz+NNfQ;z)HFN?zfcuyb_$^7-Dg!~Z(i +M`9lC1Nq*)zYEcfiG`1K0_L(@=5re85FVCJi}R80CJe-&Lh(lv(rTu?4G%S$jzrQ=LCt3;KPYmN7WBZ +3%6yT7E>wT@h9IkXG)`r2AjAW4On-|5Q-I9~0{}ZX1+2`s>ny)4*fb-Yd@56h^77|{XX5MdN#`znG$R +)XW}cw^o8;MyK9K`82h)$xz!OqMZE?L1b!cl9n~Z#oDotorluyCc{lk;fm&Y~6GGDwbxEY8i;SKRYya +2_3k(KB)&gRI-7GjDZm*_gkxZlwYYAXjO@buv56rO)QczFT{z1TZFJ$QKp=;Sg)-xdG_Y60uXKqMDi@ICyZ-|M@WpBp4KYdjrjV6AQQ +YHZ(Jf6;%vJ$f4`SpQW1Q~%!>j~{An7izdpEQVR!$(h_$^o$Gq$K#nVdPVeB+WT3pE%FaLQ8SVTF(C1mSbKqMj~iRn^^ITh|m+m9cDsMtTyBB~KhJK +N!1?at};GOKfJK#_No +-*Qv?y-%S(X^y6p^8}qh5`OlqC@5rId7QmV6RQ&E13@{Nb%1=Z?EUu9RpXg!jygrkH;tcX(D5Apv|Wr>5)Gb;Fek~oV+?YPy%GNaw2mu{#+q +jfJlIOQ47#GbncW!*lThAAkAvITwKUP{u%j_he15;P2vuToYE9E}=RDdF8^4>T`JJ&ohwcq@ +w$CdeoohG5GTO<8$?BflddczYUMNwkS7NPGb!JzEV9dm2-6 +xDO^ajw!$Z<;V#Ew}8D+4B;}kNuo`if6`|B7VRcP)u2tFDwBoHXLG5IVTyyaHppP67ivZhmcEo2mF8F +%TVr-V6)gS$6SncC%+E&JDcgFMWtYo^m?knuWxHiFjq^I=_7=mfEj4r`c~SD<0JuTtIiO#gVHyLhe1> +Xl;NZ246}4gvMxN576rhUeDoRqKGGZ{#=G$_%C~wV>gFaGh++qaCUle7WIFowo27ubDZxnHHLm|qy)& +UV4I(G_mveZq~CV1B1?m-Z#Qh+Ci?&XZ=YsTIZXJm`0D5N{!IZR`rJeLy+WYS<&qoOtWPg(_qftE&7A=+w17IPkv!*jKIK)j2FkVEJYrcum$-1@KweGnkL6$xlki4$acLR#bFAN +ZKB^|nJ==Unk>}ICN$H~ +?rI>5>o#Ut>$LkX*4xss}2$jg8+INiULnOS>;{^GQ +0>ym;EV5soVE9Q|3$6iUx+3PeUW+i5B25;etjRXz?U`96tW)(U&543QE=2O*IX>G2*9Iw?4>zE8A^=e +Te<`QCxi#V%uY%G1{}Sf%k*>7!&Urd4CJvB3-}h0xA+rV!N3STgZSCv62ceULKsD{(W>G#E``}PZp>o +e9C|P8E)AC +6+lTIW_#hpxtIEYcO$W(DJT%k@l6C#3G +|4JV-?_tQt*TdaZ7rDkY-t-F=WCRktR~0E5K8F@lCixL%Oo}VCnl-sBsHrY^w@Gf{%vT1Y~B>x54F*J +WJUjSODcBaMpApi53GJfnmjP23;2-w(^!;uknDSpiY9U3Oq`pB}NA|;VMZCJd>;62%uCp)@rO +)Vb4WWW}g>I43}qdQjII-NB7U%Wwq^5du*r#~g|RxLPRFX47rO6bDzQ4v&vUn@x4vpuFT#A2`Lapw{U +Ff>_w3aSU{AAYfTaftCvVsu|JdEv_6LbxW?#3?>TZJ!;uSF%^x#3Y-*|H$!UuKx;Yp-evZ?VW@rb3eT +3otUhw_nB|OWBb>h$!M%=Vp7pU=^jnq>1ZXh+bG}T{c*Nw~WPOZkuU%21QX|ir6t%j(I+pTPx3OIdrB +=8Wj*lxT(Ij*Y{6G{cEzrNtW-W_s!gq_en(H+hZNzn|ac574-4@nt5NI|2KHipt$CRt+gAmf+|=m +Y@eAEwdNHg!28H!;z7qAZ~qtap+W5`nd4HnER_QF7SUK*eZfGvl}Lkud&k>X!7jbbFix{VrnfkX>R9E +PaV){`-9?ng6iVdfNX+d-XgD1O4qgClX2c_%yP$Hq&|h7o?)1iLuv!MNR_Y^8=;AzL^f1=DwX{@fr?B +8aO1|tII;(|D`+bgc6dDPLC3wDRQSsO#5Z%N5(X+!}YOa^P5McoazXk}V)_uRVGX5u+r!R}kGFwnuu1 +?W^$QeHIL#X+%0u)ZmS^6EWW~>k>mK!BRdKS83&D~5?tH}~$ytzuF~y +M8mgqpXxwxY~G<^%=IAdgc-)Hn&z2A+nSJDKQ+FWm&T#)xG)V>(SSL?uINuX2r@vdmdwE!E!uh{n0tw +n7~b;!YCEcKB>ZQ%c9DOp>aWVt)#WGfj&D3s=Z@CDJ;h1l0YG@u;!PX=hF&bHp_rMOzM>$6(EAU6Z#$-|g7Cln9)*q*qanYe*JC{)ET16DiDJyqAo`nh=QX@5D#WCY$g+ZhF~(w|c&*#A5xd6Jevw +t;LKA-A4*%yCbQ?%P6X@S6R6noo2^0y*6^p7m~qj*sIOCkGI3UefMbWvdGhMk~qHpo(_FtC8+AlFJho`*4!^fB~5n%W^a7v4LDm!6u +~?3HkdUKt}&r6}Ex}rZ87^kdtW(X8hX$Wz1CbWr0+B4?0#Cc&Xmo=gpB+t%7z`k#Ph< +kN3SQjq^j5|?5s_On~`;u;Lz3#?clsAB-A~>6DdwNkXYutOP^qCEf!%vUJxmS+2+X41vKR`47Rhj<>m +`uMgIF{jF<-xbH>Hh_xE(o8|>Nf>ooJKHDA)4Fi_Ca?3n;e%8_h0BOD$V^{Q9IviI}13g7Na=}in`%y +bi7RE_C=bVM=3zYqY58;8+>%$H~$prcfmBf46q +(7eI4V!80Y>9UzQX*TCluLCa#xNE*+c7VVWHFVa(xU5ZV37ifa6W0c9P3v?F#+ +CDJC{E2McvRsMHyMehN#>vrUy7$r-AU$G*`-QQA$T4$U1^*aNiiBB_eZ0kkm;luxWFvbbQ#MLK%;Guo ++8$ujacpWJOL2bR;z+aO>I@x2FVdhwZp4U)r$yMLh4$rEw}+z#VKs&@pieQ#N1=0d2^%LMwgAnF}4y+ +A8!8p$C7u)>9Z)j4mWS)W9#RFuFx}0;2AVkAh)*D4h0OOa2%-5pnh0Iz#78~4-98#7VmJ7InS~bhKZ* +v<0SG(z8bN_n&F++4+v_^p=}FI3ndff_5srYX*YhPmPkO;ghr0WYDDE$%bkycN`XZ=qCX7A)OhP^@*!`#%2IX}r2Ed~ +oMKH6LK$(8R|Q7s4ubcx=O+SmO6XJ{emg!xY{NFQW7UQ?{lv3!2p`^JcBHw1z+4`MSdv-gGq2G=esdJ +k`~pG|859en*RPaZL-tU0=g>tMtCzIU<>xy>wgA;v*qDMIdTHNmg&2K$asH!v_7cw+ +sxuEa(aW3h@a*uIP8~WMa+>bp!(+9>jQyO(-V|X@j%X39(A!LPKvMV=cQeK>_(?Z@+A`_X+hPcZDQvD>R@*EGUo*vz?D<0%Z{V;sYUT8-r&c@Th|RaDLaDlI4LLbm +IKZd~Z-l-PBBG-SY=nv<3lA$BGFElcKseH7Hdd(=k1-k?Y1p;6ykXt>wI^IMh+p3h){MP7$Ca^lSZir +-(z()|`Vn2g*=YprrK4C{~qvnwmFNyrq$=-qp#2~R|_)=Epn5&^KwjVZs%<*s|cDoTOhbuu&7_HtTHn +Ctj=n-k)$Tg3I(-#z+M{(c}D<$NytyT|^rE?air?X(nhS+M)=%a)QJGVZ?nGZgN3^%-W3d4^B?o3oKN +nQbZQcCM|M+qJfGo{m}K;W;yc=4N93VKqcIOGH*4TH~3V>oKONmXO$YuMXK_jtZl?Kfi5J;RqQAKfo9e7fB#YE9Kd+>&jcp# +@%}pbd_k}Yns|?6DCTkaXkWPYD3nyRP=I*o3i=DbgMIICAM5)qHR#F+oMisT<^nq#Jx|WhutoWHuu){8jWdb+`xM4G78Vj?b* +7HB375{2fWy1B1tB64D+L+I$xlBRQ=Bu&O8ulP8yOq6Lxr& +Rt$(5#vFAMiqw!4nUs!H^Gys@=c_!s5MtSZqcI)t^f~Z4SDE;RkRN`PiVaRu4l_SBR&^y=fHCV1Vbf1 +g3VwZeM(-%i1rkEh)Rm6TfY#xOQc}OFEI@18@?5x?4l`?>v{$Wpj+6l?(fj2*>NJH&!*W?7e&RUIgzR +zwetvpv@VS4vfBQMYVBtO{m&9#)kA$m`>Uoh^1WfuC{yM*{Cwct4-?&D!Ahnb&hidZ3b5rymSXcav^W +(r?KKetnnB9H{tj6@Au{pXYd3Dji(aLd<|Gg?*psl#vrb0HpQ-eb0xH*YK0ehwpGdI^I%Z3Wy^r$sqqkO1Ya7Zwpr^GBb@iUMCNON$Pb +b&-L;CsH>St}k*4?}5+bs7n-E*>?Kcsg%Z|&I3rSweSeLY#Z$&3Jfbmvqy_PS1aCe0(-VbFKoVq^a|> +!R6sa}SKN62$M^AG0B1^SRsFDqcT#RV|y26!HC-xy431aGX$HJx*|E1|a0s#K-jGy2qTvyDdR7rAWJ; +8J|kH_m*eH+ikXlKQhS-(X&;$8Ehrfrphyavs+1KZbQd| ++>*Ggchga?lC9T|LTf)a^ywk@G6yJ@*TXxx9*ZD&Tw&BKv`_NXm!<$ggty7WDw_x>$P;kRd3HL!kPoF +m-qNkcyZE3*ZA;3*ZZYAeOY)&x1K8b!}4?aLYDNbT~&p{He%6>v(d34gi;;gp&wrg(3K14NFQqJd^d> +Z1lCBYLW_e(WTr#?^}SJKX#La@Tr{Upnl+)hIzD}~NIFu@_bGauh;v7dU?-;*rwqL)le;zm+nn}Kfu+ +=&R$QZDZC_ZL=Y-I^E8AVQ4;9ACA7=-6rvsLQ=~YNzsl()CJX&hD+a)Cv?&2`gH7^#Uug(qk$AvAFB= +W~uT}9Kr{3xyxyuEia}PVE=t$VS`TM08iP&I%0-r9-L$D;F7a~bWRo}c)vRRar+xi?4i{EQZ`{VmJmL +bOfB+kQScpQ`c*1#C_qHF*M;O999?;haUf6gt2JK+;fk7 +Qh}dUVI4Vp}q|fb^0g+y3U8ul{5EaZlgOBK=)Ts*CC<;8|n;1I>3{AD{$OETnSF_NB=%(^o5Enx49<$ +qv6i&}Y%%rj=Tje2*Xg{dZ`Zm##B-|{StRpkfem6rK(`7@XA56 +Yy#5w`q5hq#P6uPB6YH8pae)0Yd|z995dz=0`YR*gfUSkuz6uEW0%>bq%|}=9f+H(M3{V5EI`UmCEW# +^y^^;gEV5)?4oJg_sZ7&titQk^k%pM(cP=HKl>%mfcE31q&?}+SA60H6ZX@}}GNZjlK$i1pd|9MXF%_ +~HM+;0#!OaI_=`Q(L)#eg@LU_w*$xqBfV;q{I#!6u89#OUiN__SLQgsp-Y5M%U`fT9 ++tWm0UxU$;F(yHpI8P)%7}ddF7N9>bUYGul65_fDf+0hdKY}4-Ah`PQYY86tQkFEq2mL03iooKVR&NC69&V~ndjnu)%eEx +Do=P&zQ67^$|tOA;Et){(|nhT)oz&U5!_yNFhOP34MK~c)Wm>@Z7zt5aB6%0PQ9wwpWIR1AD6K&x6x9 +^nt3~t(ZhIwE;8;9+vBDoq3&}pl(=3kK4Uk^*pVkc_?$1u-UzoLwxZ@V_M!xsmQGBVHIGFFB*!5FA=f +SWFc)I(n+D($SvMsa@O+FMR-m +t=1p!JQ<=^JXPX^DnR>ld`(#%dQ-c6?$&VUt@v(N1YZusSDq1#uaRE4%OXHT2P8EPd-{&HuWEm1AfDV +;`$0IUyzT8u-t5SUxiZ@RwROHO%Xlr9a%FX7Qojl| +gYZCIBc!{$u77)ry)aK!@2be6HLvowaT}{_6G{I*Hq +ym@q(#bMoxqgzcXPkZlp!GYrwF#@W1As*!0bXJOd%5Is}XmJJe*Kl)*s@kv|PEQ9g62IQ=10iTBbUmZ)Vdz7uk3|W6D+OaJ +c>WZPh~Ef?Kn(wiNXTf->9}>MmBk8}2A`=2tb7XyT2v?DgPFg^brXGNpDr(SRCsYm-m2jh&6!c)YHST +GZ67>$E`e4U+2(C}Ok5Rb6{f=ya5lLY?OM0o8p#Fn+7PBs1LEjVm>z<1F`Sc5y+=#P|oQ1Iz=T(Ys(o +`?f}-zEv9-i_QE?y@m?4A^3yoa3r`D6mtmJ{Umut6 +crL1J6gW%+4X}52ILL^3dO{$Xp-uCuy1(@1__2xJ0X)4pjZugkuIaMmJFsZz(@7=0KG-jOWP_hx;dZ+ +M!#!*WZI&4+(ojz0ouS$xLXnVW-uNYqm$O9?@M#oyQXMXl@BVo}Uib(PVdrIhZnN&<+pu~^xZ +EQCz32^USM*wyjY#TE_0~?ORl7fviMN_#+H72YRV5f5U*#5zJWDP?J0kv7rWz*tW(XfDx;m;-f(L-GH +qdh4XoQM28maX@*0Rq308mQ<1QY-O00;m!mS#!a#HIylI{*MMIRO9|0001RX>c!Jc4cm4Z*nhbaA9O* +a%FRKE^vA6eS3Esxv}T}`V<)HdPv$7MN%>?E0(g3$4+$4#GX6jB)jW%c$#EW>X_{2bT{?LX76X;s>1u +x&88%KJh{Vr^z(iKAFa85zkneu^)bV!`A +66&RGPt(lSpb>oUvP%ZogYmvLJ5c6N4mcVDu3RFqw|K%&<%kv{+7>gWLe7_nuPCad)#Dw8aQB9lDIZ& +{MEA8yObECmYhFOx$5P_VUVeVWHn86T{&Pw{~w5))+>r87p=Z%=j@d@9SZMV4N4cH*09yeiq-Xc@o +G^DO7JR#8#-G=Nj6ExJ}w(=H2t(ziekdd()cB{1*}|2~bjoXu}uCG`fs}gUcjsJP^f*p6*6KKK}F#HM=!|bdWlmb;0H~}q<(~I)b@2Ss}tWm*O +y;wjQc}w{9k?ucy&*`!ktj|DB;$LT{Y{(uzW`{#tR(X^Zv6#}m7zeby3svF^uyEPBWZ4{wq!%&Cymj8 +f|1P7F;f&htxbhKnr1qVI_VM<4$#`M0Js36TdoVn{599y&pWAT`<-3Z7Gd4O>|N55oZ|2TN_D;@S&EM +OsJYTLBv@*mqnlSAST9V7Ch+rOZ%Lc<*j=5Y~LS6Q-DosHB8|yOAo@va=OX$aSmbUQE{1Z-uVec8czK +rvj%p{9%lA;WlB1Nm6_~s)q+5#>sY*Cm5N*U)4u%Z@>-ZWdMWxHb!9F8=~lqMXSQR~;*$wmX(hUt@+G +{Ha~WxP5a*i#I@V`su#BxKZ~0{!dyGJ$nH0Ud+dy5ZX-Ud&jcm61I;B{Ig3>Hvc4#KEAEqI`Ncs}6zh1s?$!^Fo7hI?8BJKo8VagFTlRq4S`}A*7-MmXW(7pM11-&VTsp(f6<4{_*{vp!vfg{(GeU4U43*STFf5;IGkQ%^kJ2{;TK+ +?NjJmMqfj7xSgP#23jexk?7IBL6ChLm&>U5bRV)QCn3n9sFT%LwAB{>)ui4>pMaATwl=s%gKay2MUhO +R5DxstEio?nNM9H;hQ3sfkLSz$!k8tZjT81#kQDv~`VL(p0gcJdGxj!PtTs_Jn&L1o2mKNg*NO#3O|C83og<^qTq2>|~)GPoCYcI1H3f7SlN&|-s8HO$;`;`@rWr?OpN- +HbU%d%n8XMxUoObYQd>FKBo9UeQ||{Ap-S|JI|N7HFE{(P|Y(xln*8l^SR1S&y}B0^flfaGR}(KlHvL +v1x7NhE~NC*s#Npx*+gpVmdzVWhLLRvFVV7A^GT2HKu!KrJHrbB1VXgSgHstfR`pe +i7rNO^CTOv5$!j|A%%jc1n?k{gZepRl;xs;zA1LKP?W<_`t;3S(ZyeDa1{a!OfE-Hv?78lbz;p(G&Ay +jABZkNe)y@<4|#r%eOP2TBkE05VEDw1imfbDREoAgPN@=!f!!35lV>WrYPM;_EhnpeR`L%VkFY3S#*X +rHUSdrWIJNt;gWt0NvR&Bhq9i)a4i{xM#`7cos}S)0MibHsQJVcNi|$#tncNiOzzxV6J5lCoinr*ayC +bVXxIPh<~`>0U9

m%W$){kE*lo^d-4s0MQ&2VpyV5ki0B)~nUYA+MU{YMfYJ6;46zE5tR(rv5wXhv +^c?{cDIWvmeW$&&)7Z%yIt7)Eo?aH|w?#i5N*U_$0n$caAW-$7aS~I%0)&RfF8NJ&`4n|*oC`W22#|1 +2e2~Wt$buho(9a!q#)g~yxZ +QUtEH+shGa$l%;bl@{!~}-#QNC+BP{!EccTyblB%R3^iU^Y{??DUW4U~c4_$UQPD3CBQI{$ChfHysOBLR;jRlu?qROMs&?Px69$U$AArlF#1eCaFVB-;3*8~P1#O_>y9dwtoV6_eGIkgjp2uHcs2U_6E?7;cKpDA$akrj^{Z?)S?PF +TWPamUSLYmSFi@0Z6PKc$u9p*ZA@Lu2Kwn{buG9284g}WWTdRyqjVCrBJ%)~8a7cOe6Er +}=s`S)vNb3Y#(3@nrUK$Ni8<>=UOw`$_=DbNio7ZrMc`hm0$42t_JP`+8;@`_8ZR2;{(9zX@2}<8GAz +8N12Az&HFU5MfjPm54u`{QPA=88KlPnCgK^j|r^mqY=EZwBsqL;64A`AfQZk?T-(d24ZF=NKlT7&1qU +cU$bYjwJcM6cIlwVxn~!66XobedCPY;TrLVRa}^*ps*Ke*E*x@6Z4D>+#?IbpHPJPd~hT^;(hoVD95J +&j-V&z%~p1I2axu91hH0Rg^pI9~=%_osS{)Ch?ybBT*AH6}E~hd6w-s^w`owv(jG0IU(liX`Gep;*M$RbEx}fByobP +5;+d-~GYf^TCNjU(V9PKVfz71*9sgDtL5tDlShp33fAa=0F_D000u!y|!9nZN@!_sa!GF+}P_7z*Q?- +I*0VyOKHE&|zIxh9E!S2wx)sG#;9>5-CZW(*cO7Ip~9{Ft`R<_CNlnhw?OT+6X?s?XLK6R}ojC)`;lu +Vn?xr!n!l)42%M8u_(Gb}c_o!{mLPeoC`z3JVFUipLc##z2!dI)+7Y3_kokxq)>>yBxU9(1paJk0KF2 +NXLS{=Q#RM|HZ+bKDj}M<$DG`pH|h4V4?%nrf|cqn2?(yc$-O938nu537pe`skEBsx13_$jhq2wI +cffeZjFE;va|j$I(a7hBIRTDi`!4wG!ip@>z?^Y`vIa&<~@M(PDx7j)do({0^OXC?meUN+P2XpU3uxk +DX0hlb7b!MDo}woTHFdQME)jtPWeJ74E7r)SJR&#>}i3{y&ec5LrBPR-!%jhHU9Fh7B&?e`jO*2O0?U +`<%^8v7UhTp%M7M|IaWSvet<+L*@6qRkmtt?I_l;yW}O{&z}6JQG!y(usf%+$=*ebUMMeVr((#ml;x1 +d_S_WJKgg;dd84|eg-PNY`q8Ga$No$b!5DTtT~lB{P_@d<;)UOuRYHjaCPVRQ>0G@yO1l2&J^ +nfaVD4LE-OAIs}+6)je)}knrd<*HhCxrwZ%kHgGb1>*=;G%D_m}hw&^us&;aWT@5Ptq9{Wio|HZeos& +krMrx2|zf@3*ha81F{cE5(UBECtny)3~?Z<1%xY>MlGtZ~K(c|Z6`e7L($(zTui{z{;><#PWUnCJns{ +YsRwf)9?5?CqvPHl%JdQt1}qr`ixhRo6s%p9VIw+NjwZhmA+PmGQ&C4n&GbZ$K(&IbmkK0YUd%obKqc +Std7V(WS?3kurm8XxTn|6n>WR4`K8^e3VI*JdkI_hs=u(PIN~L&kFJwY1k{rm-o|ESG)!I?}z=t$KKf +R$I&zK+;RE&9B#SdYt@wu8Sa*lp0skw%CPGT5!_M^tMsfaFZS2odn<|^6iLsN3Q4B=UPCnz$CjFME@D +rJq{Ko?zcMjOjvP7CI%TMloP2l#2%D#fu`yfa3J0zNe9=)AFfwhe-*PFT0ErIm@;I~#O;bcr1=gU%Qt +lFgx}A1zY*dk2C>D+!Id??R;`HL1k~;&N!+kP$L7j`#Z#4?oI-v+!0+VIH#eT^bQWPIDjk8(lKDKQ%@02z +hv|aHR;Xm!!LN!%qUTYw+=*;kk)gii`54fDyl&T{;4$#beH~EkGFir$I&>XhVJMtmcffoVOpmxuic8@ +}v&#tdELllSBb^1#3ocNs0j*p|w>@02@Sk|pgB54k!vq{X_>zcCqZBXS(YNX%8=kPCAYiCYfxC+}%8H +Jd_#6mrO<)jCbh3l7X1lqXSlC&uVHW1uDo@Zgg*N?=ma&=v8L^y+HvDTIP^33TeUzF++GyO+36k?yN0 +*$OJDOTJxmn$*IR8NqMf&Z)6^qV^>MEWiEXB16tj)8B@yF23i~oTFi}Ui9>sO51jMXBWk%3ywjZWyPM +^VWvy`aMgC%|Y#vLf`Ec_vFw4uR2Eo)Iou8^e}2=P{aOHRhG7S;UYGP38?uDx!Di(mchawyJo_ajJop +TV-V30*uiC4=y}{2~mT6_x2|yYSFB-8SJvSchR#=G9GxSN!v4W!gmM5XJ9n?y}@p$=Wt|EpgX8g42mb +|K34BV`6_BPY-ZT+4^C#27FLy1u=-Sk+D!`OQBPG9<#r*w*3Vx3cAO2^5UhqytwSRy!hXPi?%H)0${*yI>PGJNsCkWMI} +?2Ky5(-z$d^IH9?o(cWx}c4YGHFKKKdd7p~SNPv=~M@3DYsg{M>SpKmd}sR)ix36o<1rN^S^XvgMCIY|4{?XAGom_!JRaJm(l`Pz*12D}E9(b9C)1nQAPgZpf!O(tHa +(-~Yj;-RexCF)uBb!a57;xz-idK%F{0N6aWCepAEpg+^z(nH?*BS9vzzll!PjKX2QPpRwH8V1g5tan_ +zKRyfOr-+StQ7x1M>pUR<#G{;7}b@<(HSyox~`CS1yVagn{9^pyVwlarq*Gz)`CQs3$C!0#kbFdVj|=0rr^XdnF7qu%(t*RRh1{PO$pcjtdRfB#bt@5QgsMK9Y`Lx +~@nnia}w*E1~RZN*4(be5`mBBEK9gL4N?gb3PwjOb`CUW6>p{rkPm^mi6yb7Jv-1{|13>em5YL?bIEC +WLTgEY04qFsnJ`(frzHm*TWyn*9*v6#EKvZIP(EQz}!vQftMMD0Id2IK^m*fpYcNbC;VdmZWI(=6!z4 +z#*Dm;y5b}fL$-f_O3BE0Y~d#@VNi@fCo^dCzZpX+^jl1gBadL;x+@tQ(lA8EMcWwXX}D&2W%(6K<(4 +IO@UhY2VWOE7|=8*m6Q@i+ZVx7ohVIjHsFd1FSMy4(3f{OFXyDG(mTcN2(Vt-ay#fh89X^)N)yB;N%J +g5`|qc=&;6zP)L1Jx$U`2_)>8@e;72zF!UI{J@wm&{Ug)gb(Gg7}P};V`n?@+}CA)}ITDjG+wV2(MCI +eq`Y9c?rureN#l;@jZ#F<;d0#~=`rP3K{G^-CA!QT?#(T3rdfR~?IoGkp9*4RuN6EJG`ndn_qN2p +aV35)c4S`VT{z-*GnB>z1+7ZH&;?yReiJRg#iMWc*iR~^PFIce#j1oK_|R$O1U7VZ0Mz3%l`pD-!ZME +dArMAu>8387lnM$5Ms2$2Wlu@2cJSpL^v*+%+eY<*Rt`bQ_~d6#1S96`fUbOPZ0-lx#M^b1Mhx_`{V4 +B{0@_sJZ+M)6w%#-KwiwE4@@~zZaCEG7O)9BP_A)9iE9v5o?aTP4ZPzymxF>O8LTzhy^MK*KmPN^oyB +f-a-)5_!ec|DAtcnI4s$jrc_7ZLR{bLK>$7wXZjCmI3SE6k|{@~F}Q+HBRL^#+DZz5fE;)=kb-XC#D2 +w7I;h@n+m7nC +Ylx<5l=gBNb$MJ1ZYZb30w9!4K4F8drs)_op6k%7awB{hc^YWKiaH@t%PiW0F&eH*5=-eigv+%#7Abf$g4pNh+G@ +D-)jG$1l8Y9`131U#=j(Hnn{($Tek&%OAF7>cFQYt6Ak;EN3CtGpi`tf`#tXYbjr)GzJ!s{wvVJ$}is +ZCHsFhSq^M_sRP(m(zX?48wuzTCh{$-_AW`FltwoHTc%_;|Ck41~?=(b>U96eML#5@3RLEzVy3L6){8 +};r!%}gcHtHp>!wlDo +k;F(k9<+#o!SOiG~tI?f*Q%-ez~Q-gf~qkXQt>i +O^yusQH%8~u3p-HjF;I}Y=VG^oC|`Z${F1OHv$rG5I@|z3XUJFKj2wGY2XgTv9lw?;=_vK1Hw14imQ9 +VgPz+rqSOJG(zE(i_YaYJ1qjQ~gKBi1#AS0L +*HO$TCUSg>dWY(ZEU2H8EDVh|AdWu +<@7|ja@i2Dnch4Ho5ijiHEvvXvZfWG`fQ7HA&v*rn^3ks27A@`cM2vvQQ=OYjZI(4fBXVff5t-qC1$RSR<4qSi;epalWaeWT<;}QPoBz)=nl__GPfcHMZLj#Tpp`WO-5QGh%+Xb-=Y&qhhCmO>vi9#jLDJuFs0N@vo2MyHnh;n`To{lKs`EHNN +ySvv>s`oJjN69;_NYZUyy2%?yMFJg-Qv!UN!Hz{$Z2bv}zZ5wm`1e2H-&;-n9{a=^KS6iqTwT-~Af1o07FG4c~rpCod<<0A-crm*k#l)dzzJy@9z2G8(r+I|*0xDfmYp7~jb^5AHa`t +c0C1l~W{;v79Jvt4APd8Sx>gZ8A+pb4)7@%IwAl^mftO}cEbI**5A?Mj}pC#hIspzQI3QM5EW8LF;@i +fonoqTSZBf}5-y|uP{#?!a^91QMl^1In2US!v_NS$~cYIxihJcrmHY$SKK1-XISrN-x88#)*|<=dh|R +Q;?$bzNJ0(Rb3NEF6SDaFPGKPm3hNb4VNr-`X25hVc6&n306{tA$R>D7juAjiW(%50EdE3T%Qvx)dVF +E-Y +P|3`+4e8z!50s&kDZzNT>bhxC+$g141Ov0(3|DdY0ovfo6x%EuEMKWsmb_@d1&7Jysd`Qg}MaJJ_3Y +X!xTxM~Rpj!stJ6BYMhbN$3Bd0A9Iu&r+?P7^gkGUYx(Wt))5Rm`k?tv=1=E&6U&{k0}O%$u&kz +E=Zg@_`Q-P=Bpg4gB5RyB}+mM8HR>0mB80UZcV86Vjmk$)U>)h!D3Bzmm3`VS=a}7FSPrE$+OlD7df^ +oyzD_U_SA$Y7obChFNW>gfhBJ=!A5lD40Yo#5@mc!}(SV!=yl4ILwsX +SLHXwdnm;_dmzPo@$aj6!SzHg4$YSnqDkN%=da(tQLD@S*Anb2rmd$EG1VDX^PIa=ItokjxtMBx5{RfO@qPh5mQvFd>*Th|ldGtVYlWsy3wR_GiIz +faqP}~X`GJII`+`v#?I)|NqkV#kjTZZPe32B034_Oc;@6S)>m3Czd$yg_MXfrKUo5i81~sjf_Ig~@tl#=wuDzc^S*^p!gLXGiqK9((=s8s^w_8iPSt71`qzW +Of=<%~ukk@>@P=}?0F%GUpFqwje+3E-AQx`gUgnta-kE3J!qYr-!;k&_e_--(S@A@AFQx0(HsnJov^n +3Lp1hEy-)4|9Y2#j}zM=^=_u0VL?h#k=1C0cbs=^7vW!Yng-upG1j)Hg;BKE>+xR7XI*$uGj#A9Y~=; +R`BN@cTi0LyIGVHH`8L+j>yeaKzf8lnnn6RJV9+TcHk%@UuuDu%qNWrvNkMCWceLZ@dbPXn9U_wqq8Q +Fp4TGP)6tNFnSx&|Jm;FXm_jHGO{hJ8}p}cP;x@6&{v*hE+FQt!Sv#!Mk+c~+zecVA5&$alJ$Ey1vvO +h5m(Gt2*yq`O=A=$9t3QbFN5_x6ys{_SyUsBhPYz>*29zBf?HunBTr@z9|;7tPS8iFfGNZ3@=j2>LOXpaXmw?lAOB&KbMoFSEb#h$@b=JIlNcZK$cdhUB0?OsS7MvelK#^3mI4=JL~jDo3$M9$> +!rNW$OH6~n8nLgd26Ocsx?qZgC44Dw|e%4WxTh@OLj17b=0i=-PZ!(AK$g+?cm*$9B;UISf^EZ7p5&E +9YUCIT*V9jh+-M7_-t4q2rOUUyQ1li2Mg|Da^mR1mkm4j$mmTQsws`Ght<}c@o7MR^=HB>4!{c~86$R@Oab2dHtO%_eW{3W)kl8t6G4N8G`)-v_7FVbF8b9|xl~$CH)D1;=C6jua%rZ=RA5^JzU55znO~gX_DM;E#Yo#AB~a6VSq>acm%Edcz +vFUm{7v +-k@)if0^D&!$%39usake)FnQM`*?|OMLb5aUFX=Jl)yozWwbCM-*Ichb4_O%&K#l=-$XQfRNlAT2vT) +x*Se?l2>X)9|KK(m=dy%{o06shoRjbNGK)}olzzQcmiP+ODE9lYCBhR7O;z`}4|>e(g+SHWt&`tTI(Zv-m>%b${?NSQCZnP7oI +kZu7&1#*2!fHw)=aL;Y|e9!Pt$pI@Jp&?P)@%}p6*$xriS!k5(_-@F?151+Eb-qXry&e>I42roorsKA +Gl6A(?MiLhy5mT1d)4v|}4FGOuc-)gZ{tddpaDxM>>2#GQ(!fWouMYPw0LEljWD56BPur8xCS*;g%c% +}cn?eUTVu|v?T<1U7w>)XzOZegV5^vYsw +DTaHcx@d6oleEzgS-QMNmBlHI2;a!!>7-WpLX2%N(Kubxu68lj2zUoflG8%o1NfY%Bs>^2LjIL##_IE +Sb#ro?JI|`=ksKmP~=mFgYi{q+(4<_nJn!D2<7#tO+i9|BIZ4i>1AE$!uT*k4HBRU8u3c9jd~=2iuhx +W9)Sw}`O06-v-32hs&`~_KDjbY7ZH^UKaVnO>TgYe0%!*xBlE@a5;lfQ`S6YTJo6+rCLz8vEw1X>SJ( +|oe5WAZ?we9#T-sHsM~!VIW!uEdtRNH5!IW{*ub49wh-DHt||8#47*l1rKH0)l +geB@D?j^}8!+pB2IcL1fyv@u+?W8hT?Tr;(|rDl!5_2Ez#DOY +0a-h99W7PE?ogs5vXXQBH~ekX7bB}on(lHoLhW`bxcY>oCn=Sim&Qwa~1I660pc|iTDyb8)W6};CcLn +B3(SHYR4@W(h?@!haWi18F^!*G32$wv1RMup^M*Fw_YMt05QW=!dA-Uq6EjH(V1(BdNWo>1*83__w%1 +c8N5osse?nsb$~9j)qF?tDQg;3kf6Fm!0uQ3a~b%Wd^=U~W`}2Cp*g$3_`$@w3`i7?Nc8rJn( +nVmf6pINc&`C84x-BOdMKh>y4kD{;kqUTUD@TMg})V2AYHG7Y}6tKMx51y{+iVHZ3xKqrNRt)_Ev!afKfhC(GXhrsooA?CI0jt7$#j$NBDD602P* +?tfI55d%RQ7`$ug1!ZLt`N`cvQ|pD1xKjY>k~G7rnA@azkBQzNg6EHx`;(;G(Jmhpj^u=c|P%_x#lBe +S^7;I4dqecUdcI0Ip=$vgsuP)!c;vh#r+Rl*oSW=`H$`ahz%fF^P`!ETu}~69`M13Qf?V~2LcSd#C*f +E7AqTta_-qr$ue0)`Qp}{d&coegeu(} +bF$wYd?*9r8VG%hwE^thYEcuw)00bjixhnfIX^c5Q7&=85iY3ibdhwmj2?>YitkWov9-u#YaNOZwFIMUTk#>k#4Ka^w-?~S_DR+5kF +GMYmN4cvb-y=@d3-w%>3Qgbaz1u^%mx1;W+Xek}CZT6Y$X&`voJZ?LDMpY2aD^R&r_a4kI(__99}d2xSGI_T746?xRDziD>Z87}|%jyp{{em=jPIvOnqDJe)S*8rq7#9bgDGVeIh6b<8OMk*q1U4e8pbG?F +HzNH*yT+DP8Dg#TZbdz&YV{zCR{qn+I^4K(VZt7vATFZ286pY^*sE+Iyw}C3+L00s~Ze$P4#?3N5kpe +i7<3d;S1GwmSkDE0Lg5lj9b$^T17&)u_;2>eAv8j-yKHIyN)9CvI%^g5U +!~4ZQvQnZ%)OpzVs3~Kf@P#f=^!H^G+I|y@*TPBJg`_ZvF6(HI%RHQO(Yx_7ixV((2nUn<*eJaD@^Ew +ux^xkYnv}KWeZ28j75yv|aV;QR^A6r3uJwKZ_@@2=CO!64T3 +W1IO=^u5FCu8W9uE+dew%{_=f1`T0NhH$;gP7M-X(BTFWh +Eq@yI$(iU?*;E1_BS`F|tS%*D4}E%cZ$qKMv%d4pU(IV8HH8MF;BZ5+qrO&}sxo$vgujVMMa8{bFCWWOO|unICy=<|SbM2oSY^jLH +c{vPJj8CyPzM%cR1J$Ux&ti6=nKGNjQAHJe2bBXZ}F$s|MUIp_v2UZ{_^%clss17Za}ST= +I#?mxw)u@^?Msw>RAsYf%xvC4+m00NqZQlmy<(r-@l-k#h0g-f1&fot%7QQqQvmg_mpgRb278$uThpnj|s4Ok@JQ06)pZ#=IT})woJ0C_+S#xGx4CM)kjHeku@SlZ^<3#lU<8e! +(otb!_Kocok<}LTFX-b+QAQX>7aX>;Wouq=ALi4P!^{~OMMPhl2 +8VZCpP-xTl!f3(z&i6N3n_zY!2^oY>WIV>ocsE^EN<6b4mie>y +-A?Ba7*D5{`VT}JF#ctuk7_rxNB4!P3yb1=Qvm$cHVWSJ4JH3x?qg ++en=sehU?-}9Zla4(j=DLEJ5S1)7RK6~w}m@tdC{2E3l$OcOO!OUHdu^LOrV^{t3@=GJ)tK{3;yg%l3 +F-*1*~Q#ND-3p5et3J~^cbW)g15e4^0}(>AbglsWFn(p+O{TgqGAoPgj^s>1q$kr~gj +^<)uK2xlzc5;a~v_sZ}y0=Yh(N_|8fh{1&7o5*q7*HQc=QYC{hhM^{(RP5gZoFnU1F_fQ +5;m$>t>SB1Pa8vlJMdNSR1KjXuXhWi}V(z^G4xzMPzG+rfcGmmOju;0|qUsc;POz +YJrqvI2$IAuvO7S;x+Z8=}66}5xNxJE<_%tgY6W>||lbu6dB4$sG1uk?JDD4N#f)B0M$B^y$5bo|ts6 +jlC^XLTnV_4)Zd!?pgzq&J=2lhmMp@&{9lGgWk0s9QS0xS?eoox>HW{uOAFNODMd&4FJA!wvHM7F`R@ +jNo){PHsRAk3NzgrU5YdPO;x*heL!b`?wPzN4@dfGdYu8jc%Q^Y_G( +)@V3QMATThmZ&v(r1b;|3mCwF4@m6Y%vhSp|G4WE(fvZP48G_%xz-syyr_X5s(z51(^hH$@>JClgMoj +Dwf1#_aXDYs&7nOO{?%7!bWmaIVuKw1jZk_zw=H(byR$%~E0~SK*G>=$$`PtQzK!mvT6nJpp)sQxB0l +a$n^!bQhuc`-L#jU2wWERtS#(`FQd?yv7l)9|d@`d3duM#l7&u~-tAulW{akqy3{@`RbIX*dQRb3oZg^z|$kNVF>qoV;V`opKshsRGx&-;hZkB^=|9gLnH9uG%P +M}7A^x5@2B)r7d)80N3?YGb(gU2Zm3-fP^nCjAEEdJh;^j9i&@e#3G74ac<+j_c?SIIdqAsAXgj3~r4 +jyrp;s^Vt`MxXeET?Cn?fbhQcUYP?QQbjLwOAvPV&{fqw{NL0wUxYYJ8JEfLKz3uzeL!Go17UQXf}#$S0+XlwH`W3n!aw@pR_w))dWLO54I0JldZ9$Vc +kBC{;!TWt_-l#AU}B)O2|)t1HhnGiaH78Tm|pB#W#o5}zANXQ>6_Tkfb3@oe%i{|L4V-JRpP-xcuukZ +*~4q=hpl-WF6Z-{7;s*cL+NRMd4dGg+@z3{-M|e7Lp^fCJIx%6-f +_R<&LATwX+fFGAk&wIGMDY%5z1Viiaa!w`Gy`=AenFI%-4=&-cZy^3cqq7^SaTphU)IJ*hUT&V-&zV- +%e`AbpCb1m>c8t8;tqCC5*W-!oR_o+hl%&F|UR(R|jJo1LMEJm|G}iwG91IFyq0(XRk$hrT;tN)H0lF4^0(iE?4uC5zR$7xKvGGvr=qMPfWL$eFd6s|i}jrFS4k!-I3z;|G +d$>;a&wpD7?w^+$bG?-G9#X!j9aXSMLt9V!}4eOvr=mmQ6!4*hsg5N>5f8s)Ue!k;mxMK&RGT7vvl=d +=Wi+X54Kq&mDyAm|wD@3J^8*10$)yN)^J1D%F(8M=b!Cj<^kHc+|fGT$b0$Ti$dxc2~b(lX0Z4ZH0TL +Mj{bkMEwKV^Vn-;PDFLVc_xWs1|t~fBx*y`!_`hw{l#A6X@505ZCUgCd +Yk|7=wYO!?ECL^H1be@Bf&s@iGETZ96kC=pE?D`)1>;Hko +E=Z|AAYt8_RUx=c3t1W|T0%_rU{+|n~aT>RE{uzgb(()cZN?CZ)L3u;x*8mKMM=6$Sk+!&HwSLNFn7fIdxeZ$Wbfq`B9!E+a>T$dUUdm|Sy+}RzT91IWZOAMjRQ8hD0X +yVX?b9YJ&kfEA>&8Nijv+4qRl?@Z23xFRRp_uv0x@cdT@6aWAK2mm&gW=Ym +k86y)00090E000^Q003}la4%nWWo~3|axZUkWMy(?WMpY$bS`jtwO4IV<3ji;#8 +BEi*><{9CH*Q6d8L%wm7zLcLStV|9fY49ls>uDpjh5l6YR8nR#Y+b~%P&QEmi(Tq>}VK79P};a3Rb&8 +o;#7&E1K{>Vh{xOWUwCRSWZUgW?fESX>r8+a6Pu2^crLNEr!0+MAc9+?fQfH>bk$%HI&^e!G$%yUG87 +!nLgwrYt$vRJ5>STHnCA(pa8c#MdU7Rh?Wauq9zxZoL+2xF-wgQHpHbJW*?QWj^xb0FPT1utAJi?ss5 +q!K(K6dM6}o@DEk^4J<=e8sCM1faQ)1iO}42jyzRsz~{Qz8MvVFy;Co<8o<3$_f5qtXM +&y1L=v-B7P{InJ&!qJuehyZE~TGlue^6m0ZSH#sjNB42PHoavrzp6O@ZoxFR?qeD(a1U7@(YPeXS$gCGR&YC7@Ukqw?do +LrAQ{|j88w;x0>@vgiGp`$>DtpGiDR-qv9l^YJnD0D8oi5K14aOp)pAzvc215+oAyy5l431NC2PJ@|? +sf;RjKkz;OGQ^1PmFq_X%m8KJe!~}-jh)Fvhjp&8o>1pH45qiC_hlSa2;*Qfa#3~RVy@1`#5G~D*x|( +Su51`NSI!q#`v!;=YBQ5*1#vTWwE|;1_&1Eaz^B57fggqVYGd_bR0G_2GuH+u^k$fL1#uY$7>X!Izd% +Ewx9=J(YDc$gXhQGTGy1uuQYSHToeAR32%_yW==Bx?7x%SfVubq=_=;8v(C;h$%JW_?$#4!pAX1z$Da +oxAKkUY&|EbrbNGV&ue2!y9&F2VbslkA;Gh^b}4S%zllh#HI^Qi4Ep+mZ!Cty(X+w;HYYL=%@$0l8nW|YOu9% +U8Xo8t!||aA;yO+Tje)7z&V)DyZa^`6#R@5zsPZP;hX-ruXDj6gN5^)WjGO1nlS?B4^F!cPS5-aX~JQ +sc7v_r62tuUH|##g@WeLo{{3gT!yh)3f<4=ivscxmL>(WrN@+J-GQ|~J)jiiB&vCY9-G);XoM1Gj$gs +<=A>lx8=t7^3dZ?)NlzAMa~rgMsBzIV3SXxEvtY}c$+V1;$asJ7Xmx0CFkEJ~|mO@ +^j6GOoq+Vk#wr&dyUzRDoNGy~%8g)sGD)FH1bzjSdeV>K7Vxd$r*#OAYlO_S=DwRae@%VXAnXvh=^@c +lJNzch<@exu>pGJ;QmY&LgqAeks=e!Zow%E8A3~Dm9mzSZpXiwkp-;wBLpy^ezN#jC0sBWcV3Sn_HuX +Ws)88qMjf2&Hc1ipQr7vZunNKva`VLLp{dr@^2< +QmugO|BHD8-WK}I)n080;9tgT%8g2G#w4E**I;_f7A9?e+4VEt1#*1z3xX0mJJ`JPDvfSmea;8b$9;r +Bs&?8=FRBnC34jQqxGG|W5!icmMo83|2d#_#*vZFGhUc0%CQcJcvK}GDUwXn80fZvE~tAlZjw7Uk&1H +ye4ziHWu;r}~njYO9)y-bn}Z +xO^u{E)F~Z=TalpncZR49jF|`RhH10|9s8*0;+~x;+fdX5UFRZ8Oil*QZy3|0#$r{an&ci1UP5T5Gp& +hW&2P>XxT#ho8>%%P!HPyxO9KQH0000805+CpNx>j=j_S|=0IO>Q02lxO0B~t=FJE?LZe(wAFK~HqVRC +b6Zf7oVdF*|Af7`~f=>Pf@2z`AB+8`~;N!louTUnM9-N=@Yq%`S~RsJ9nl3|B=bkXFMFP9CyR);iv$OMf5KQvXY@7ts`7|!dG`r|c=W7qv9t1o2bY7$vmsJoBJHf{K`qS>ldjIPnc +pJ~g!ErBmJ^XH#76}!8n-r6@EYmy-(lWSAisWn_ToiFuC8H=fFOnq4&x7G*TwEkkP~}0K&4X!Dlu#i* +tKu|+mH|#2453*pTU`R6GC!|w;v#|KqaZHJe3-@nF&O2;*(AxTxWX3C({WM;VRZ?830g;@POC!=jgoj +Aq#3|V0{JSqNvq3zRs}^;Rz*5QC=nDIj%Oq8hb%BoC#h%!0T4b)1UoBX9N52yP@HRfnuM-*+&wG|v&|~fi&c;+vvUpWq#xR64#5-dTng?9R# +<&XXMOgtQq%aZFyr4$i@%FeA-|q%T2d|EQ+CJP3_Kt$LhX;S#d%62EXl)rQlsMde +bNu(<;8n2w=I_A|dv9JM#&>^yd$@aa6dW7|d#~T_@9n;fg1t98`#-+id-GlJ0&2cFI1cvrUhf?P*y96 +gQUKfAg?g_5$m`w1o$ukn_KUs!z2m<}!K=OFHwg6=fZYz>ZXX`+?fkgEeHgs`@$l`z(Jpl1B>;Z2_vY +0hw6ptq_subk2wH}x!S3JSXK?iW_WnLKxBVlG;gI^cbMW@>hkM_Be;j;&u>W!w9=_Ox-fh3w-{r>M{2 +f=~{`TJMD0sR3di%Rws&@cz4ymB%;ZNW1(j#bb8~(R*ym#;hakF#q=J*hPB5sZk4v$skpZ1P+qhR}R? ++6j|>hJ&>K*U0w0|Emz-|R9RL^}2yV5r%FLO7Nmk9Ku`UhZ!11GFQoZcZgm?%H4gi*_&wwt{zStyXJI +@f*p2y1~vEmN?K165J$#1vn~s1)rxGlVS298NzA`WL4lWlL>rZTSNM-flLt=P-B%887yKT?sz&a@_2Z +OaEC<#523V%jK9isGKIPlbhLI|_J~%iBIYFnbUaQzJekMCp#m5orDG{z3`pEXaxojn1;CvGlfg9uP=c +R;t>|t>!91U>jqf^rTV?gK2^f^lGu7@M2K)$kG@8jS!Nu@^QX)}W8q=?GB^9P +O-#3u3WDf$!=vuCOcAcSH=psfrmgj!T6IU}gpIlJOiD_}e+mPS#sn`#xdr69>=)mc;tlcoMX}2lfU`= +%>6GkG^OHA@mrz{sn9XglNG6V0e>YZRfW2tc=GqX133x;8{Ex;h>V_`4_D_;N@qtbX*0qDfAL+@81I8 +(Om>z_EVVPcznl9bN_Zb8{GxTIKdsF4A#Q^+xFx3v$xo*VwWHH1_OXU7(BlVa$sw51)aM90x4B>jZ)y +Fz{Rr*7$xpRvnuZbhOU#MqA6R`9WZNkHaFMS0{EO4z^yfD0(AioM6AHZ7>}oyamnQ#NJ5tg2mHheTU3 +O8zzV|3A=m8$kAqg!f`8qIU$hwRB~AlWa^{2HO<`QHzhCm3R`)ruSZbt4b9hAK=GUE$SY%?JVRxL)a4 +$5s6**?Bsi6BjIBCP~I5k6I$rBtH3q`3lkS0Z8 +fcpUcc90Z|TR!=_KJ->wgLk0F@-uuJ<>e_Jbdfcd#U^@XNg5LL}=7K{t3dttP{Zzs?W|y)vH_!vvVuM +bgWX>N&J6mNs{Cji}=$iLZ*}T&{Zj3KM;U&t!3ww^Y@6DZheLl+jpKRaK}+2E?Lc9JPWn9w$UC>d}-| +xBLauHB8Rp;gxzYpC%>uas)zk1&EQ|l)u;3s$#yWx!9n(#Dyn|9q#74z80$3w$B$VUsN+qZ0g4{{6Q`|LR`9Cm;etuRpap +Az7LL0bqd*X1@DMoC!}49$3LXZbLAH@gtDT^ObPa2hX!2yO4LcOFuALb89dM5ylKBmc)O;j%BzgpguJ +TP@?Pc^UpPa!agI{qJ_;(k?7y3JyR`YhW)_z6oJQ=;1GkE*z+_=o7vTKhFhEw9p|q!({;`psXf?Tnf{$dZHNbzUU=V>~~|hWvfX@)vzC5E`-A7clBwnm2fh +@93%EySo{%9Inof>jl-WtscFKt9Wdb6b*^3KovV839SxM@_c;opTxSD@8j=75Hw+Wuaob1Q?pt*OfHf +SSnB91ogUME$u$L1`G-R5(QHax$M47aRg$SMJ3>MMBn4~jpO86=eRm}P3Xu3!0sOC|$R+C6+9XY6vkA +dx(L#Uw^I1w&K&IOn=VfvnUx=Rv(4Kd-h5VS9o4~&4d_GL908 +}Q!8*Rk7^u~=GTy$r_YGQb~Mj=(1IRe}QrJW+%A`)BhfEDEIj?P@0SeMfekiol-bV{lV_=r0!+exzP_wB`0w`l`OW_KErWq +guT7NNyEsPLVq!%f0qhk<;fJ-ve3&|DJ>^%JdJT2xH+fXYuCI!LMffqs30#b~y!alr?r;J>&e++nWKx +q(|VZ*7CiQFe(Q>bQeW({#4lKTiWpLb3+pPsJ0{rli46tU}^te*y3Tfx({^gO@nf{v4t200jqZMCP1wBM0UKa2G{$&6&cqIymQw^TmSfoYa6NdugUtC=9fiA`K6$zn2Af5?fm=BS$ +5NQw;SKTfyUWkgg8J4q21c&Af4rzHo%0^fXFhu;uVl<%!UMDD0XLCGsjUy0Sp$d!-keQ6jq-pplK;au +AGkE-gzVOiCxW?lRK`QTPDFNirmqkA9rgWM?a>g}5$9P$oM-13ZNW%fc{*lQM#FjJx0eRjF_Mi&xl3Y +wdM??rHQ0AN=oyY08fp7%_=sP8~^Da3cyTF0=tXboNwBj$4 +N+4h2K7{eKKTO7`Z-?0;=BwY?3>|_J2HhH+uYSW5FIQB7=>F<9Kp5ii2u1Xuo?mYX^@5*e*j +@Ghqe%C+du7e;O}Y2hb#jyaOkW=O^{GIK#9(M7)U-&@Uj652t|V6bDzXqPU)36I1C1&y}^J_F0h +`@@eGa%u@>+lWJ7`rDJI0-CKiMoh^Pp)J7NjZ$6Ae`1h8&dh$yq+eX>0$-^JlGh?KYnY +bK?yVc>8hrxczOLxiQTgG!a}>0kAF0fax%`H{Jq}viFLqw;zKYL=FukocbsE4Tq8pE??AqY0L}{CAgDen!v(Z`85+gR&>b=j?EF2Oxhl +oYdM^y|rg(2Q7885X~sUy)-Kk`XTq*Y`y3s^_g!>b$UsT0x1 +~-YJ8;^rWQm}oVS|^Hjm_d9+#wl0BS2!7`&D!Kypi~!5}1MW)w`JK8P~; +aBCd|mhxf?wGI)fx9MwO5FFO%K~car{A+HuP!W}Vt0Ij+T4HKS!y&HEX<`d#8aEkT4vk?#aFXWY;t8cPx(G_o=lY@u(T# +kNwi!#85ZHRB7^wI%DS~bgU+3wl3{d0%0CI8x_C*%M$|r(4AHzws1YVcp_0#N3+{<|TEBFNrDx4-g#t +M8P#K2#`4gIwc+cD(Tf!H-PfyK0k+2|>Om+(fW)yu)zoK()JEw-n>8}PXnzL;VoK1B9#mK0L$tQRCIl +pP?$eC$9NlCJ4KFsMyWH*k|W{NgFU4b}RK46--&;<1Ja94>6Z@KE#3qil5= +fWzziK$g8-)Ys+k+!bELDezNUj0mYgi?~WnSZ4F0>DI$C2vHaVp)Yti0wFcT-fTV`p((`}{&r9q`p#+ +@KcV6`>DKEU@1mpi_HbcAG+2?A+v+0 +&o?msu!WoUMN+gn)-^SXtF7A6$JwV*c05l7bKVSY?^->Q2eBlsl#X3oU#FLPG`k;Ql~!a +EMIF}MZ(T9JKJ&i51}B^BTLi_@zd?-l6~#h|#2d>l(ILs%iI+Ch424xVuA(T$go-nnWNOaP$}FE{qi= +zK<6N;Mw+r5(K}aPBAf>qRoW~Mpvd{asv{xNLho5a{qu +xOMe0~S#!LGjb?*NohiaJ_xE3Sq{IyxM(lJbnv!kKg!qeVfS1+xqL{^X~ +(Ymw4J;{s3HA>Xet1Zvy&QZc9NZ0Xrrfno$97*d=69~T90a8R0?kXD;;jf^Y#$DK9cwaZ7l(pGG +Br#hSvr&~a3Zt4MQn9Jtb=lsEw6o#P?KsIo0lIV7(S?ADsR&;EeZYdE5ROCk<)nXlr!19>ib`-Z>h+$ +9FDS>r2Gj*CCAEbD=seWL?!*bJE-Oi?V#^ScOy#2#&O=eq0UWmGNen_12)*qmZLPs@KaYc^`V){3E0SR!<03Pe-cE^kt)Zm%{)es<+BpX|lDXzVYHGz*=ugixIO9<_M^U +XI;`WsK4_RWTHt)NLz2&8+SZQ+9I_@q!gB6pt)Zo-Ab1P~IIosNMh0@Xs&6lB|Jxi9%S5Ngw#HX*6q^ +uEWavR{chr2eN;o)T$>hm}QTWCODa9NAiAUfc1?&w)8YHX}v!;=TA2{HMR6zCP`@Pn{{kD{iR6Ror)S +^ju=YeUGE3R{&SNs*N5?92dsbiD&d!=2bk_Vpd=c{~n|20>#ZYgQtDt3H1n$3LC~VTomvKKw7+%`85(dR_xFV_kex0oYt;6J+10m%qL97N +IfXEfIb36`_&ieF6Tp3ZQVv$n)P=;71lvceF-jA6??VojMrN7Y$8(JK40MqJGs2*S;lPr3K<>;%CQc# +8tX_0i1}hr#`I0yAj)_;-ApifM5WucrNLNjm{-V(D-oEMIn};iD~SQCV~@$a0)H1FPI1{69I4cU`UW7 +D`H8Z96XTb;y3ZUl*^oMiTTivCo(oPqPs+?wHVG9kUReI4KwsjD=PpIN9cE=44(uYb%bx8pwTR#l2N- +Iot$<&BlOdb2J5MUA7jeZ_fsEmUSxhC{7Wb{DjBM<*?vH=?tcwhPNak#ih3taA?cvdazOFhGaxe9s`o#8=HgDEJ8qtX$D$yUc>DI~SJM +ygPM;F3Z_x3J-s1K^v0`e+o;iTI?brI;F8v((hh?C$N1wP~m*G5M)_~6vOs&Y|w6$RI;?ZO5!ucHQX? +Ra-**_*3VdFP^@p&3_r7193C!IR6$wZr0PXHe{qaaMU;_#|fJzM=;(U1W +7iVpfH$(Mi&+^b)yt7rN*UVHwH(%PliLvN~XXB$@s* +E-AdvC=upN+Ine_02m7j{NkY_3@MWD|{BO$b=(Dw&sc^)W2V%eW+4 +O&f(#(2})U%eG-jz1+q^TMeVvc72l<;%mOAXw-L8Z6r;idQAbk7oIy%1)Nt}BW&0u0s+6XsDU+sLG7e +~AAF1RFH4#|z)!2yI+WTxMg_Teqiz^Z7VJ4I^fOdF6jsAedmn;48_zr12o*o#LTAfF+sCve;4Ep4Fee ++MA0IicF15$z#|vAviAW*UK=3DHcB65u#qWgO1ug#07;b18mxiB1xDER;sjneb?S#dYX}WoXa$6K>!U!OAFQ0hM!sh-cgFj5 +}q`DZ=t&o@nyd-W~Go!yOOP`7Bm +=WAKGC_x71dHlKR9|Cciej5^Jgl`Kar*AB2-!nA42s%Hg8pc8dnC0BHoMZjqG*$gJfQ!$)Noywau3vn +CFM7ECG$wgD(co>Jaof>s!e>MhW#?uE33ivltUifQq2UwdLsG}o$Ml1f5jv3@{aBOxQuBby7%B3wtU# +P@T`GdqfGr2Cz9zSnt5cRCy9rOqx6k46+q^o2!-C*lKH_AJx6_O~uoC6 +c>Y^}26u61i3rz$>m{^H`B+{DHS6sA)^oA)XV4s3$t5)f(kdro4T1cebfO@bQK*6GF6(@SoiQ<`o*fw*^aS*XKm~klTjraFg9dqR7O@rzQ>Tz(-XjBs58Jc!O9AkfBQ2|sQqg*`Ej<_XDxdMsM_Qy`% +?vL`(SyDhj#*L*LKo7!2vHr$LVv?Tbg9}XDX?^4F$)zljSSGz>m*~KD7Ddza3MH`u>lP^){^imHtn4m +0BlA^m+k@*7qDY@Oz{eoTM#2$N|D9b#E#NQim~H>--&$=F@XD=EU{$2TWAw-GWeUl41jwiMWr +;?xES$Id4#?@{w1(SRZ6m56#?;rSex1krXcKR{X%A)<}C80yFbyh6(q6GEJZoHI+vGEqPvXPvwkv(<%4M+`6;UXChgY=O*aQi!e9l%2JR%e2p1T_^u3` +uNYGW&ddH`eRGGPM9!H<-+-1u0lL{HY~pF(MU!skZTX95h^S9QE6c)SDuVn`LA9^Cg_!x)G(h+XBFGU +W8?#S?T8&hL|g%f1)W@g-c!g*OG~%^5!j1@FTeb9rL`scjwEB +yQ}Us5=&4M8Sx8dJFEgo-Q9({W8)5OO&q13wA9}R?%Ls+X%(1iif<@8_31T{=BUyA~5G(>RhGhpQv!q +5USYn{xFQpfOU3s|^p2&+E(r+mSR-StFh+;Etx7oE(G}Uwhb7;!xs6$xe@@n)xC`aR~_vgX*sx*WXdc +|+>#i+a*pTEBvkIMI>t8(1-l7(|U%rq1Qi>}L2rTBPD(%S-#pVP*KmI;~_>a_UbCN_=`nI*Q)52w +RonE$XnBMi*A_cIa><%WU+@c-^f84tGQ80!Vp|?*%Hyr(D15C0uyFsjJ6$)y!(yLmQ$rp9UCnCP +Ch2sA>qvPK!V^Nlm*r$|tOWaxQ2QjKS()_)$d+oXIW6EJ)Mz4I+y>y7o;A%uPSSy}@vv#n<^j-*F3SO +t;!Rl{&GVkE6IO!wF+a4M!9K|AD5pbGII345c}r9}!JE`Z;Rdw~s)z6s12P45Ugv&rz5(tv4HxI#=%= +EE>$)APp|r6(>bE5InIVbEF^#Nn5G&X$V!0+GAhTS<2CWE7KXOazCD@xy@n9RO8irYP%}pI^o1|GVX& +RK-XoW;?$#j-@C6n>imTTif`!C+_-~?bI3W_+3DtSvD;LzzPJ#}RCtR}AKuDtrfejx6c;VksC@vPL?Ym!3_4Go^4+e7?J=OiR>mi0e} +=?Kc{f5v}bkgemNdpy${AE{!8B-1=@okL8T<-uerDsk~aZk#lH@&)g|wGy!W7cK+NJWtY+jy9~&;v<} +7=JUow>!E?UwjQpmE;*v(VNFzs1El<_o01E9#brTD^67M@A*j!4XNMWE#=@I$;c8TPKQ`6^hWK86EwG}zc|~X~&r(wV7iyrJDP^$= +x=q^WC!|kaLIZLy5x-U?@9@O&z+_qr^?M)EjqzB-a9eCVEM2N>&f1Mt(^C3MYP#c}oyQPC +42zMYw@-NvhXfer?t%fybe&h@spTRKYD3lkY=)M@d>^JuM&ehnOtjck_Ev1D9Hp9G%{kkK{WI=)ZFlh +~01<3R{moX;!p(-{#atzP+WuAG)j*sb{v~;G}aPU{6%_haQ6@FCz_vqjatgj-4lm4%AmT}^{*=2 +npSX3%=t$BPRjZ1{l)#h*Rk2Cn(ie$2=PeTwCT|ByX?8t2sNA +Oq3S~JKj7seoYD=t*s+|vjYPZwwwxGMN92$Zl1m@e^RHA=Nwh{E_ERbA1=eMZ=nVtE`NT#FU9ClKCI# +k!y9*m(^6uD{Vnp8eDWN0107LszrX3bnMy!HlLobxc5%( +hU5OFcTp`EuU8CvqR-evkp?U10yES*D184z7{>Sulb70pte!J?0?GtjWIw9t3;_1`G%M*5vd88@+c|OBGLB@!t6xNYTYn`T6UCn^{%-E#{A4u62L6GzSGb=lb`8)T +UWAjO)j~JO`n@9z^_(eQ078$aUn{1)sA{;G;%-(6V0y6+>_Sc@$PE_QQ}~D0w|R04tBX`tw`2^U(Z{C +alcDv+(-z#`U=oFQ7_tsYO-{L`xL;}NbqkYs{1UuBb(7xPSO>k9mM*t=WxSFi#1{fEi;MLwE~cx7f3c~<*Ceb4Qj#Y0>QU}nM%6E9hvCOo~mf92M*CwBWLFKgg_Pw +MPX)=*rRwU7Y7(qW>-{%p$XxH8Bl{*5?m?nFEA>w&D) +{0H)2~!Xf{s|PC5e-muNYx&yhfotvfgnq~_=V-F&n@Zsc|sDZ8HII1`HndXE9OH)5w1#yl)+U8`};3#Y +fH8lAz_X`2u9q|lbci>X#N+iba^LgT5juAMauI@k<0He9-ZherPz=b!5KUo`0e8U;i9de}NTQ49g=tm +Z1M3->S=*6s%2d84cd?|K%GTFLm@;1^a;LwOx545DMlo+t>M3tLiLHI~JVBlLL6_LO^B2Q%69$*MYBk +Gg#~6oBYyBOu{ex55p%%^b;WUz>Wu$+X=@+vjO@iJ2gP!*SrK2FCd^jW4pi1STe(z>vPjB7adnt7OR3 +iq26!J%T=KZVyonMh<4V$iN7Nxm$PI?!C-KUMu9wBBzT;yd$%dAn$E3{Qi$Thm^1ndEY(;` +w>Y=enmuwXkf#OsIIQ?9Ni!(yV@pBO}Zo^ATHC@7+eay1+E^C`b)Lk8u#bX^=U)^q)cXxPj2NL$5Z5O +BkrPTxHSqejJWkT7!h<>*6(2qUag*>2ZINwa8+*-vQ4AaqXFp<)92ObSdFNp{*g#=BAI$wSy&=Y +!!KUuy!prIxoSb5!cnqhwBE!J9D-2WEq2Oy~~hXP9Ba+9p1-(_$>ge=3T0oa0EHqZgt>HCQ!l^fUuV<9l@HK3jXdY4|7Z^;VutHfv6~6r)2k1}+)Kkcaphkca_GPMMdLGQ6VP +ww46f&5~5cVp-5~h`*jfS%El$>NeFZk~882#NSt*`)v^T@h|J|DT>$1@F90n2@RMCT66S*;D}=2?>SNM4K{uEtntD>e3Vo48B+pb^!a~nX +O|*0S?0Ead^E=_CRL(9g_%zC!Zpr>ADU}amglDA3xlWTC$LUGVMBU9W64$$eH!WZBS6mr`8WBqO05UHyN_0UOw +qDcyMGIztPgSItCrb+U`8HmOnQDa(N0CUo7@F%}HrJu-WcH(g_BpG&GcwF;=rAoh?sYa&y(hoT(isB} +0jSP5i0*TGj1RG@Rx3HZQAT^q5QzT{-5%()QsmSy+BCZ|lx=0R@z@0a$T)EV-L+rlT}%NB?X`h>K{?? +QNp6m%xV_;w7eXP63~MwarKz+hb&`YybW=__?vbY$;rzN7^$C~xm|5b7bchYf5M?y@cswpK(O7$w40D +cChCaDPI-z3`r%A>_%y5vDaDB!_TFoVkftdtJti2{vRAKD_l?V|Arpf$(nAm!%vy_phFXN2QZYp!VDx +jbYi^e`wWi*beO{y9SgCQtGCp{Hx9v)CKwQcI7ne#w&@TNe0MPW^kc&!jdAR`UOEOc|3!f~hX_`Uqo9 +~hj6AWoUw!y2P_z|jfiV9I%kcBTT?Cz~6mxO0V1qp!>)_3V +R=nQI5YB!*WZ^?z&K(NsQADQBTOqcO56ly?*p`l`1M9V18pGnvxd1OySYVcEo@945O@>m5Z}#ZE@+!r +!55UzeU2aHK(X+mX7Oyh%jH-86&43`3X#V#XCFY!h|SwLtfEfA7ui;N{+{S1_utMN@mPg6%hd4|Wb +-?gl&GZ@>9&_b3W>|F-)k_`g3M9mDh2uXo=Z9|Z@8!HfOvH$M;%DDq{T^#T0c+kN>3d0kZR$EtZl1J<<3dN)t+>Jap>^NRso5zyrZ?=I4cq1ldnVNBI-%c6Vd6IrM +(K#OUa&ohsF(Sy5L*uBHgkfi(uYixjV?D>OnJB4k4#NMD-f6}ESn)2!-Sn0pK!W}qw;bhrWV>fwzfP3 +v-tkcKP>#f2@72fo2z5Y2jCe#d`j{No++uu4@VXBiYxeOv}@#^i)Bf^79<;x0vLFXAbQ#Z%Os;@U_#P +oS)R9ks3QFqTF*?*^qeJoYZ}ecB4UM*RNAb^91MV!EyQ=N8o6pgy-rVp;1wlSf_8B7_M#M^xQ-aJf+W +_gVPWn{dq$p5sWYi1`rJM%iR>uRQZPm +P7+K>dWro9yHb@zY+Q!1*9$F++C~$v0yYf7u%O!@!1fYdY4^XrosEGF^2II;f>%G-83cV_y^wOA1Jce +BUk4&CU3k7JzQk>D1lyjk)`M9FwSg#T+4gffPR?V%DIsHj05#wnAv^v6P+=weu_#nM8Q6V6>?XqnoCW0~l)Rp;L!uH^D?l4^ +<0fXu^$46UuE> +79|l+4~-czAf`#N<274uF|RIaIOeTMQ8&c-Y2~^7jYuHE($9qAC+M0txV!MtKxSjQ>{Sbqtu8E=!cid +@Jb%`$H{rs6`9!$M{02cnoN)J2F6W2%C>kH8L;Zz4^!%iZ^l`6@>VW!KbeflXvSLr#-Y>biIK`tz=B4 +b)d`+7b(VTdhhY*19uk>|;?Xtbeq*VP;y~K1!j?ZNFKoX+?halnOE>mfZ{XN{Wjl4^4$1jY(Yg(7Eii +cq-CL09!f-a3jbU@SPJ)n32!LRH*y9C5p|087!T2}m1P_L=H^Y&|)JK;taeHYRSIFBUVNBEp6kq2lT2 +GDOkQ1Y{CY5r)4vBQ@z+RG``?#3fQrT*5(62d4p!9zxed3ONXLr{Nq#FoMF!2MNZSDPG%HkRc(j=?I) +vfLa(M7Dtq%|0{nxY&X{_Bs2?`h=qBI9Z|gr^$eZ@M$;t0Vb+^+V8KUk|?ia{Y&3#yp5G^r)_w#qeL|$@W`&rGw{=9xZdA*+UxZ?L5RsN0Aay;C&Eo3OE&v-RlDirZ +nW77p{6Csu657$C9hhk?OGgMUj|-h8&xf}L}<94RoY3T7q!$}xXJSvu6)~L@J3@U1=;cW08fWn$TKO4 +6F_f|$9zp)*2UXJ^i?FZ_Y65SpA}Th3bTYGOwVSO9=X_Slxo}xFrn%0&B5{RCX=yB2^BoTHTbBuUAY^ +k2paOO0!Coak4HK6BtYpYsbk_yir6t~ZPKCK_ae@gK*^=@e~B$1z3-N0S +d@n-)PY6s*7JGio02p5sJ0f|Rz`j?d1Dpv@KWKwV!I@iFr-d9l3IwscY+sDa|06@piT85s)-T@oO^|^emtUxEp4eet7;IP7-y_aO86 +6q*xJ#smN!G%sXU6r`AxUKV&XxTabS^P;Bam0VrtlN-X_9H4<9Owlcd9Ikxo#EG4V{)Odd;Gm-?>@?N +a1G3as9)U5PDf{A`$9v#OA57xdz?_Krk08$J|nL{QarKkSC14@JGZI>cles5e~LGbwylvkGgi3?Ym}D +w(jTn`rb$7xXJ5GNPnb*{Ul>JP^T17y`+!82SH1JWRSLg0 +uAH2Yn%G*Vr%d*irOiShIXl0(0>P+_)E-|7bPWG0}f65jAJb}m|~8nt}wx{IgYp7G1u^Q9ZDDfEhs_R +)D}xFRgsTy>=RX;P3t&Tju~kcJ+HbG_GEM>KILWY2yH^{sh#e4cSc51cimX6Z;vThw~@sd9W3GmBd{o +Lmf*;5qn17nj4Hy^<9^7D15n~3r0j9a#viEVJ3_eTL07vLfK(WIUcs$N; +IwlA-17r{?3yK+#pTh&6X~S7rkBs%U%tV+*41XCJbs7(^;tR$Dx)bl)4#iT)P;mDcj5OyV>)rE=lp*Q +)oGo|+Xu5vIonIzTyTp`_r6Ct7s76l0b7AvJokgIj5!h9TUX=f^NLT_eajVJV0KJlLQj8J?L@~+}_I; +2+2St}K+A_6m?Ecb8sg@+Hv?kWoi5Q71iM`%+IOht6IZe-P6NmCrnNG|yX+enY_VHyBk2tniJVp%$)| +R)_T4?-?R@U^npQ*KFT)mn(HGMv}O*MT!yJ0nbRmdIbOc;){7oo-i5pqw1UB3jBJLm`w|a +zX#en)%J5QGcY8>{IdcAkfJsWd&d=;}KucX88>bCgLD#Oqd^uV0P>s~S)h|v +xf;Qg3U7~mZjj$ss|WeJfPnX=TG@VT9uC+kT8(>#>fOCIjeDfRtgBy__V)hzSk{M{JVoFJ +V@)IV0|}xrZC6GrP^-Ye44M|AH>}jyJG6%hF^vX@conl^v+f3BBNmW}qkyAb!jKPfNH+KW_?@`zQsQ~ +b+CS@vI!$qf3Et-LdKn308vnO&bXZ-ll#PVkUIA@3BX2wu6U?oM-xvL#@13v9;`Hr_vDL&Au!z@8EMj<>yZtz4}Rmo&Z8g^JaOy +>?T5nfMA_y!;voxfHgE9u*z>axghtXT8M#z|M{=d)ZK8R0NoQ7Rp(sL#&!vbwu7A!48zihUpg9xr0}y +_(!&nb@3Xi^*+(HYLj#=s>`H3#9R3a&7NJu6SfN1@9kN)>e-ea_(9&Fv!@xCkM(ukXdvx1 +OE*7Ao1@uef{Qm1+O5zXYGdu@k?Rscq&v0!RO?*p$nrRdYgiT6qr(8{s@0d@BHY}CC3O!>QO!=aSC +dO*hOL!5B@q2g&~tu +MCRqbccx69`yw`Aq7E7Ad7WpQUBV-*Qy-gThZZSqGd;7u8q&JF7CM|evkF=Io85|%Q|RY1K#7r;H$X?92BFZNJf~9(!U)DYI&8O=M97+kz)}HG?f18L-R+|he9!$6B^z2m +0N|D@N;i^lE7D_Db;72u6)HXECifuxY6J_p|5#U<{nS;DJB32#f6Kvrwd6|gYuFsem;V9Rkiz(uc~$r +61Lghza_0Y{1HDu41@EO(gc~|c1OuCvm`t@75(|&OxB@95&l58U5xULjL9$3s?y?86H)V7mczov{)eu +a2Rh>o(8$c30~O|mJE{5L>Q7Qwume!;kEFjzBaEJ`Dz3WX^XfT=rs^L&>lH3LcaMwn+q +%a(Oa$%cD_}`=ps~l?*R0q;x*kN16K5KMqOaNxdBL381CzEAO4Cdv#@8o +a{8crMMOg>kBd46>$HKDX-5IOqznHwl^jGA1x&m|2L_i2a^5yExU1nRFwQU1p=E<~DEC#N#bk4yQbvQM{X@n^lIB1mH ++4yJjb(O_pH~Sf4kzfhf$?U?$%o*gh%qi^*`ZCxu%A&*9=uvcOe2;G3~4fnM`G7WKEUo?8PS}dK#g=1 +R~$oPgeE_))!@;HC#OK@Cd9KG7(G?f$%(R&LXl!ErG+Q+JCFmQ1!M)s+M^q|69|tCuM?QfyAC{}v|7r +_Q8D{zkzc2y#7(D2mZS`gW&~rdC?5(U0&ezOgiBFLQfa44ZWWmWkAr*;B`5-q7PC_GLU7g{Afg5qcED +jC!t--HEnMS_3Ma*pg**#;$CSu$nj|CGuF*J){ObVkB8?)T0SQKgjd7hE_^}D^5=E5~5ZC2?pd-vH8F +>Iem$*wvOerI-QuUN%NfY2apNSL-(ur{{ssZHVoH}w%Za>BpoF`;Y9bs)t{V#?SOwbLDgR7F$Hy#RwV +CT4v_iU!n!MH1X=S~j`1$c%bc6M&3<$RcvFKG+c9UAt)wu)o9$XnDc-31fY&aKtlopd$Aa_sd(kbCI% +C;LLsMmZ^FMmb^HTC~DbmPl(@#O0-!lCz{#&gCpExXn|n56vJ>b}> +Y7fy`Hm`zPPqQ$Q0Yz%gX78do{yOBMB!)Qc)_j^eNHPO{ozpip+eJ}W03E~c*vlt~TBlsR0@`5rq6Gq +^*;|AYkjmL{aOzhGollTo*)ye7t_+3_WH9HpPM0Vs%nadaFUc;{APPCKiIM#utkTpyVW$ +?OiH3~g_DT6VJ$tn#~#F%Wi_+_C%?agmPGVOoikZpl$3V5>%FN#qlG-Ct63AwYeO>R3hwFZUwH;Ibk` +6Q{)?za-ni#ze0RUmkT!_SiIYADbg4mR#SpXfxxyhagKCIey7oZv>JOMV+jSW247Zn|V1(QXqU`D0}= +#n_%4JYe_?>!8A{PU6bEqGe5zkVdObNGwnBWaP|Gcm^E`1ho$L`ssKK-em=jmJgJ3O4{va$x0((@f;0 +-PTJGT5p(%0`QtQ|#waL^l&8FH&X{DYWvwJ{*K$A$4(s7saA+YlycYR7Fm#! +x%P&l&u`ZA4ZX?24`Qdoxtaf@KR%LGGSCTg>4^UUV%l&oOX(Fi@al=`i+CCRvzR(wcnzg*F{J +@L0;c2UM+biK61TyLqbJ(Epo{@`j_Od~8y&tl#Juh)%Z#|VZx6sj_$5NMi5dx|bK++S>D +^I=%C-LmPV9%0&Z-MXR`3u=zgON9d@b(K4k=nsW5Ky_}!>i3dTax2M?H*O9FLD@jCGyc9HP>q15tM1C +NP$+?eH_0iJ_=Aj>GkCrI^I-4IF~|yloN+u|EV~@xzEERyv<$B1{BGg1MPXI~Z&@X%_BBwBjnF}ow>p2*7ZMZ^;ol3p!@gWkhGK30PfqrutGMVPMy#G274;g}LjL +uQq*XHm4=RyiKMKksim9hal`@2}3Ee)$zVxq5&8=RbWjzItDtkG}cypITO3k@S`zI9XLFtq_q5VJ=F@ +r^L*K-02w$K)~=B9%B>jp#6wv;BnCYNBdC-;JWm{qd2Ws;hvyZY<-`tMXj{4vjR@63je@Q9fVhV`j3C +qOUsXF(EHAXu%r<8cuArAfm9zx!lGmF$8PQ)w{3sizRh{)l%tp3c{aPDD3t-J#CP*?Nl!!(Zjrlq^5wls0KE(68ZR|9$v=RehB`0}`Z57 +K;}BNA2aqu&BTX|@-TXl+c7f}c6YH_06j+YNtez?75Bfw8Hl3jQUQ +Meq;@-8ig(LgN!YlU1Tyh6dOM47}d!8U8wD$MG`Uh}9C(lWr^9f^J-NSPKoF@Y_~H7e4W;2I>GO=7Jg +Hq)HZxMS;B&$@fm!0g;Q-G`=CG!d!gFtrGARiT`0!y~0lCAz_VGXtl|j#3mCL#Kq{Bw20Z;*d33u}H5 +dMRyWWSrLb#J&AoaIzNqMLptZe{Vi)|xtsR^P2hiF}-P&tx?K|1p5x4eY&I;xuXbr0T9b5A*G ++gCd=rk=KVA_LSOHO!zw1k-$P_ihlRn$U?@mBI;OfydLFw0QKj1(mir;5uRg_L2r0UgCIMEhs&{I_2^~G6GSb4MdC>MTC)|8rklq +CUmu(_*zhXlYSFM`x!}ohWI5Q6*#8WaRQ29SnzDBcqmF|`C+(o1(VQ*)NMR38P{Q%%-fXpc@AEX{C}1 +eDM}zY*^0q95dZr1@AKP;Yu!fiS&@MFwjms#a6(%uUv~iboS93m>>hzc{ljJ@lHf++^=!I*h7v{S(_p +a@8DUt{o%QQ)=ZdDJ+SY?`4lqq-=P^>c2Gzk3*Y|=B#(>LVAd${>V(8hS2-*EobUy~vaq-F=7nnmp(9 +?;N$8nAZ99>GW3WAU4Stg!P*a6OAYT9^g|<(MqkD=0&Q`n{jTBlGunIhr+q0skUo{EHCjc|+2yCig7M=kFw_R^+*TZVEG!U>Y%=08hl(pA?QsG +&ynL^dGNrsXj%%)H&?rF{f=C*hf7kCd>_V7#C+KDrftosZ#CNl6p+5%wU%7>-LlLBK-Q4mOKuffOth! +V>D#H~fVdr{)ztqq%L2@$}`s3)FnQ09& +qIFfMpzt_vom|TSDx*zn(e60AH`iOMKi+akblhZzjkfIkKTad4;%sZ@hs$D?X~G&eYJQ0SndC|w7^5| +)>ivuHkQ+Uzs3H@SnM&L)hTDU&Rqrto?1E04D|!Oe;gQp&`N$+d!Le*10`3RBr-Q!%F2K^*yzge))Hb +hn_>#65>6{)w&vZry`7|41Y#+09tD7nSBvCghQ$nTSG?*#7+RU2Iv|8ofQV?l!}C>Y-jsI5cpimWM4r +uesH)J|WI141*mKy(eX83U3NlL|=xt +%h)5w7Fw#zxn%=)D^hi1DSM}f$P!&yNVxn)lnS>u_{$crN)FAKx1n<6#r;++lvmHm^ZYXzpu +Ob}L^!}wrn3H}9#UO4y5A9#kQD*7ntD&P4%E!YPB9ZJC@)M=wTos-Rt+PRSmqR(NYD~E!)E;h51zN1t +3^bUP5am=LIkhPlIFgvmZr|5;T95k_q{wM$rw1)W50-DZA><89-S7F3#dZgNWytsSbskD$)d)YtrP!E +2VQBZv*jWXRWv;GSDL0;b&M}Y(&40TUiwb&TuLEGAt+Z6U?x;F(K;-16VhX|kbdTgrh=HcKwpFq2#@Tb86`&cq6Bl?kS8;4NBsZjx8s89IL?6 +h8tj*M6DBW8~)SMrf3_8#f0E%fq6a+S>bwfv;m{fLpA0S~iA5qbW}y8qCow6SB}%q|XB!#mwhRR>rB +`mBWrF`$&;Mpq&qMx?+ImjO8~|oq^JG!GHELF +RI~;?a9c{F{uu9NO&}M6yYq;Xl8pnmL?-?{o}E5*h7snHcQH0HgIA?K{U-uMGS@ZqxK!;n~aBKFi4tD +w~;&Pu&RKIbgVJr3GJfq{IPKCKID_Ms!+Yk!68c{l*2yf=e=9%H~K(DjZB(u128wjD6V41lA~v1G;Cq +NS{-THfoV=3x4Nx*xiTM?$uP^EM4}DNG{Q9jnQ($8j)8ERlM)s4CL2Dze4gq4C~Ysyiso#El}x&Mo= +F+?8y$8sivsVX% +VKCi3B$SzRdyH-i`jVbZ(kVRFHV&~vg!@+jwc2(C}okL3Pf?@%!M(Bh|Ah`jo +1d>@oLCc=8>D5m2bc=kIyfm0%i^vmEbk6kj$S1@ty@C+A&Gv-V)dQ4siLu+5e%_S2c4j%ysq)ymqwx+ +xs1q9gr7w+9xz? +hT$^tb#Kz|@dqLzVax3uJJ)PkR$Ixw0ERDjlg3tW39{J4h)IzMIxn((}JGjh7#Q#0Y@GtfL48@A(_wc +@j3(BF6(e3<_l{P~-8qo?}ZR7RwZQ>o1=FN}YU$HhmpPs#ed9V&y&6!uvyL7vA}lrS_;`Z49ptIa3X${bM^u4EQPZdEi>UYNd?tS +%qqFDM$!U|IvV-j^#fM=sOa#e6@nIaZA%{|>ZVJ*q$J|tjkzR+Oq)yD-noQ}A^u)Rx;Lt=M7b#H-zN6 +U&{>>=C@MnnGECL0y?iC>;3z98Z@qT0V*a{&Sghm>ISb*RxUYd(kI?6H?Kus&0B2dvEo1Gnvf%aq56Og5VwRmu5~>GXQIn`E>TezUxw+3-`ba&&68r{ST<=@{j@GiWHQ670Q*O7czX) +o>}QmmgpGLmFS8WsFyXWt#MuY}h-Vk5dc>Pmd@J>u!FRc+N%1}seVj_OF=^w{VUc4E@}nqcXVwnG=U< +FrKN1%UV~lhq;(QnWo2$3JR4ZL$)c7OkZpvQM<%hxkvBxo^&4eMbW#?$2TQp44g7OoB#*J4xW|)dwp} +8$)9Ho|q?LYGR59Z`9WFE1tw|K8tR8&ZqU|Jj^cKD{73EWgd;UjzKPUu4~YuCFnGAWA8Gy#XAcxl +*nn89V6BZN-iBDR$Ak&_Jejrq2FK5CR6c_PVwT#O+3Qvdmy?H+=XE&mI(|Pb)rbwBgj|;82=c~BRJzp +Y|s-Hi8L^sT8Ir73bP^XBZdI}Pg;L;%!tc*a1+nX2wH$06>-iCh@qAy-VM__BkGd84gY?KZ;S(FNsEUzV`0~C$OAzB{bx7=Myv7|L{ssk +X(@SUmIJ4vw(co^X;m4&M0X)uEY$#*D{Q5Q4l9$&@cOnmEf6t-w0`iO5X3B0I*psg7)7LT`gtRrK52s +H@afmNe?W&tvnoDE1sM3HF60h|lF0iIE^9*_zebe8~7D!R35Vmi`Wk{6kHZL~-V8 +_K#wEebV-kz^~xvjD9~?A^|-IUG81(`Fi}z%X(~#08zPc5p(7Um#})EY{F21q$n`NdNA@zHU*YnqF-K)3M?fIvp%5%=w=d1Lz*Z;ED|LPkb(wyy<7Rtxt(W>O?=9kc@JFpXYaJ +uF|SV*olQa$PVVBCXrePnw=4XHqDL1=__Iz|_hlYQ(y|?er38R(lPhB1Rm +mPQP_oC!F6))`5ZIQr{Teu=OAvgFfFpK>b*rax+N3&kLF{q8EaXB?ErTZh*cLC&`dcDoyo@7XC%59Nl +U3h{);sIjMPAewQR6WuY`beDM3f;BaC4Uw*e=?=#`Jz>@KrvuG%7(@=-46=fg+beDO41vQ*qwu74$ +3YaOgD}mX#0KZcoUX3tE)Y=vE+NaLGCvBuGP2?z3V9D@oXTDn%+!UL_71fWxS1;bb=qyGho6@^f{jt; +Cgf2ag!416UHPdE)EJG7I9;qGXn4^_+=~5Ix03aN72}tj%F(mGu%#+^G-a4%+bJ&76R6F`WYi5(x`zA +;N#^<503h?J!?0J-mxCNGvg^9-aq6Jd$k5bBV|MR!_M6Ca1&P?VY83&&=NEaRuylD`J1vLK +r-@KwzQTe!548{)S~Y-B9g#=`>36*~utAqR)1=24xEhjg8|5*X3=qIr)~Pz(eus0>z`rz>`#1qRkQwM +Qa7LvT?+_Rb4|O`zWaUY0oIw02a+@Z;$z7~?_jR$m`}5B3+vB~1H@dS>@iX^U>B{8?Q=}PZTdxbaB>& +|T*CRwg?hjXs}swofIEC +R?*aoqZOq;*LbZWNl{Enyz6iMn9*QJXGViPE2}~3wwo{86IDl*_nSrr?$}%{-G&Q3Q4{ +>Ip!HbTkx22ezKuWY}^Z*7T@$wU7I6YXrGPaOE>iF4R{RnPPM(;&1LrTA=NrIsEWX7I*P*32;@pQj00(TZjFcuq=H**=Zt({ONrB3A`| +|0swG%PuqniI8FC;OHB@2lOW6K2PDX_1yhZ*G-+?i8NiXcPF6TKkpHq7|JVwcv-aiL#fhB5538Y#HQCg~Qf7Osj#9 +3XJrF#+VMa+uQH**LfrT;~BHP+{IK3uI)h$4}iu2K)Myy|&av*eEOZ9>JnMZSUa-`GT!RDq +tU`rV<(+f|tS>b(F?c0-((Mr5Fx&SyyspMP-=zDW6R7enw?)mmK|0U>c(t%KfF4p0_%}Jyn~dN^Q!{Z +96@0Q}|5!x}A*t(tJMc7HjZY5#C_dlk% +bD;r)Hr7l_3hKKUSmheoNxB=N;Dnm!gUo@$V+8c;yh!*6}YDK&&E?$k2sWd^PDuKJ(0zeB~hpnOdls) +bx*9S@xnc3ztb1>Ibgf@5hQ3)*xz{=g<&6C~;{`1_(}N*Ogdep`=q2OXw3)E>tJ|Z`X!wNGm6`c6GCs +N2A8if_5<+qzk>WG(Zy($GCM!iq`s +0B+N-vvED~)GGcH-C;QhDFIb11`APMOd{9W_5HLk_0$*GLe>j3441v`ji(p}IRoDR`i91RQdFpSH$(v +;Hh`r5mr=pZ@XcNR)-B|j-tI17Eogs~hO!X$^gW_lw0*G>6ASmWBF$&%s9M{TnBmulJ7Ve>S`As`ex? +^wcynfm0I3n3_G78{%urnF;*IUYo93G(yx$#Hu^7JL#$+N1!sP3FEgZn|+XOD>1`7~XPGm@Gb+Oy9Yu +1avQ=S--Hq%>BJi<6wTtEAP&WG;HLK$?;&Rt$aIk|Kmz`JR%*=h;E;zd_QgdmXX8gZx--W-n8Dd=P(~ +WhzSrz&T10T1smP@3A7(Ddpo<#K$ZJr8T|RQm7q4n%73d(W42Pah72+`b-4)y9jCj0s-y6LCYj*A05X +Q-5*`YMJht6Wkv=z<=o0SFI(h*)>2wTtuP`m(%yyxlwo3XpjS$mnwCmsZv>kOc5ZdY?t+S3Xs52Rd6! +Z$LWw~sg5GqMIT1yQ5!<0z`on9{B8ENd!s@w|cE$a>jwi*$L=|U+2OkrM`7EngMW!c%H*>?3S7eJ9x3 +3r>i_Pw7SC)3Z=C)17SX9dm{-f2lq-4V<$hXx_Z(_t6pf)2WM}fR#&q|sJvvq+&Vef2=`X-UNY;_YLi +(I4`QbCskgo)oas97nI#Tq~DM`MpoBahCo93c!^c!9BXDZ38IXr1w&)cU_aNE{nXm185C*PdH)3(GCK5ARdwomVtHT<*Nu%E@ve@c1^2@vT1JoSsuvG*vY#&Vv}{&kG6Q%P3 +fx2E3cIu{RGSXSaLaukX!j)T`aso6tSFJGrbE7c{y=C5_)pMbd|bMX?V@Cds0d8`gRgdD^XAqAt~WHK +@)$gG@rI2UL0HLoKIZ<+0L)Dv?4JfYFdjK-7Lr#cD%$a+`3SXIl!qEmAmBScBGBn0sPdMo-K+c8n8U5 +~$CQZPJ8-s?%On4kjojC3G2q;Rt?Brkk37<@s5?YG?01D1AI +PM7_*e(5>ux(&wr+(wYUIsA~(g7wyK`N#9)&e-Fi@6iuQ<6Jw-xk4nc+GRsL9-W<82&k{k%S2|(%^fI(tgA4Cj>!$3u$XYfMUZqq$w=UYqvMukcVD*kX6aIj2joNroDl3a()FNp~$S ++0b3r;|uJfJ0);Jv982CVB!u75rF4yG={&)O**jx0vWRI{%u*r*#!sl5p7z=m?CJDMFZ+wW|b89aRUgIkq9M +4?PwntIA+i8G*-`wfoNnA?t951QP%6xnhLTcDnwd>rh75 +QnV;ak2mAIDI^TP)bjEw}7n2WFo?2v1mPmi5g0DSw-ea3EpVA$?bz~=%kfX3N_FgGM}X)`WpJs}qH6lbLZ<+ZZj-+21vS6~0>&)>AjNrs*>4}q6mcH&qTh))DYBFDv$1C!K;}vm!$1%RbR7v1Gd1V@ +}q$n~n?<4Jhp$I`BEnZb~xg7)eOFuffXWSR)Zp>jCe-qB%{CR7dTDTdkni`e`=g{0bITEH>O`NZ;bWAvUdj{XrpC>{M}G +Y+C#|S7LIi59)k__QnaLgFDNQnQ@@wSwU*`g +Fzg$xNG*cM2ohNSh=>0lek=(?gHakCV?(h3&ETeVK78Jj=B7x(Cn-S^-Q-iRvkhh=zHWe2afe;(|;Ib +O5Z3d#pdTA@Oo_p;;s-m5z@Lmyi2?`^}hOjn~=37XZ(@77q`@SkOD +BkaYyMxBKH35%r19riW6B<8mIEE=D%QPIyYA>d+ +ew%}{prE{c3M4Q>4{^wPfC4o>R~&b>zd#NPXq*Q8wBGPH|Jwb@AAL$#}$)ZVP{Huj}@A>h=Z_!a5qb% +PubkhI~l5@mI>j0=TiHmu8ZYJ}=(by?&$+E3ZtmXP^Eov!HpGjrE;!Zx^oEZ0X#)RuIEJ?EjQk=|!8t +F_p`TF{_^#`JvMZj>IPb)wlYog&dz;@OHl^(gB7-8K7bm-xK&ZZ1WSQhbHr(T(wG>n9q9Pzy-gFfiJ@sA +Zm_vsx{-@3GVHrIXcZAlEJ^OX-y}kRoyIZrA;r4) +y}0!l^VDUUvvV$z|9BF5^@FS7Jkov9$rP(xS+Z|Bt|hTTs@&N6Oq&oDJb$jJwthKj9NXvZrl#vk>J70 +o-h;a}c9qcj2-l>V+0i70;}U12a4mX(yLkeXs}Y-S^_jv6iVFf>y(!}KDI@S=6{xO@7SccaJedhbS$3 +{?zymD%OA4f}&_|VBoXu|B6*Je>Ggs3%$>F}fU5~! +J3wK`sw)670mw(xTpHJ^P;mU?rAw0HDw!8 +mzD%FWTeUgX^!3l9n>#zl_9CLtEVfsaB&ZxM&8=^{gqz%-5Je&i;=tbu)ILEYv9B8DQmc8I8VUt`zv{ +?L3&@IRIMK#TI9A_$%D3)dopOyKGql#cRdRClzV)}&ax*p49P4v`9DV9HwNby_suG +COMVpV|@cjXbVq)A$_wD=2vbd0?TP+c&!t(|Me-vQpMA~aH@Y0GceriJAM-9H*PyUM@;AyZA+HQj9kc +2W)nWNpcSffGoL$Mw<9eLlqtU*tZ(q)R~Cr5UOkr^&GGC8&f|>@bSl@mO@FOhEXf*dMA5GJO`|#6=+< +BZjNKM49*KKlj@u2uTfMnQ#7)#@qyPM9dXV8zUDD72FJy)}E$;%?mC)jLxDGWK<%g?$i!y^51#9-hyZ3$t +(IJBumpLTIGCvgojy5f*MPN8Pn+J0aV{ufcIW@K_oeM^+(^RT{VO`uI&4}^T9oY^ilnS8+Zn&B*j`)N +IVgosi)=|9^BOj3S+O*~{jCE>0gWapTh1}ha3(U@4HOCmpin5(VX#ri=xU2D^Uc&vG{;j{`G#2PW?wT +4eTDBXZIvg(8D$lcg}F#Aab^2z(VnF)F3sYuduVjHT~Hu!N{C)A5V5@~@@I)Qf~!1fqd#8MU;fHqgQU}HH#WMW-Yq~yv=#XT +heaf%H3?Ia)rBA4w`?2BD|>MAe>Qt{OREE`N8uSPbqeK>&eT*y@P{A$Ixm0ZV`XK)%p2uakn_G2QPW! +$h)ex!x}n(FS@Fg!vRAbtRL%v@uO5%09M860;OJWEYEYP>9w&UVU9*e(|?%E4viDky8-XYjLaLMW=N!XxzJ7xU +HATDK?sL{Hl*rSgxe3Tvbu|kxEJj)6zUySxf0@DF0p6Yzv|nSpfh!-2#0aayci>@9(3RW5wG7bCiJm; +9Wjb4wxJr8&1_}#MhKj3$sp1^xA5M#G&KTC9+U*1DvGt#)Pp^nGpgz?9CKiZ1$pX%L%ayd|`(c)64TG)mVr(Ej*hU_yCd=vg=ItEZ^#>wtQ7WXr2~$bXHdk~LK?O60j72`^}Hxi{kMZ685I4u +znmsTdoz0QF!}E<){@QkgIcBHv5u9{k&x@*H?E4`pf>&k0P4$ChR{Fd{u6Zf2}Fr9U0xE2qIjE6?DiT +KnqiA6a)aekf;S)!oDmZeg3ITU=D +cs%9rYY>_=*!Q}{M-Q6V8N`#Dx@bOCLO)6ynA8&^6r`hBON(2c@sW_XP@D;R?{dsKmWfyj +{LYP_UyF{8W=BWUqoYyn8d};L6k`<{&xG(`0V`3`QR0Y4HV1)?$aqf-GA*qJ*B75oU+$txrBN8MX>`UngM}EwF= +Rs>|~5xS|tk)6@-3Yc-JBzbz6aj^|wH;k{2+QCHk@KB7K3qMx5ZW|KhiUEPa>Rb}9mR#kyfC*)qe`0U +qsQB3dhNq|35%trkqyLi~4T&gWE95F;VgC)-3AZEL}z +B;O1R0<(Is~)h9t-xd_-!8Xo+Z|cBuW1=X5Pm3)-H{vI`y_j=^WB)YQmGqR1;F3RbPFmn@R`xzh8R43 +i_++<_G>UYtLwK#VwBDS*+;1OcY#x*U%8Bsy +Q(404&#SV=4dEtH-F8p}Z?|t964Z|g;1b>!N+_v%w1npcgg4$sF{uQ=xRvCof;C2#H5&g7 +?=17UBqyB9y3uP3%!h*QzPyvF=RH1=`g_{gery%+3U!EU6XO} +A}FiLmjbS^CIB_a?$oaM003Mz_El$JS~3a8{*&bAuK= +BTIYjiP2X0x+=Y8)vz&@_d-2MYayi7kb0hJ+&$#cY7ia!b@ZD>YhNH-br;K5cS(9MhR1x6AZyX=*HIb +k!{Bwx`AR!u9-na}8C0ceU!DmF1uc@Ma8$VwbKgUs50plW0ZVn8Fh3Wqp-Cb|fMk`*-ML%o1VJd$BrD +_`!%sn~fF*NzI0Eyqsl9!FhCY4d|Sw@A5Gv_$Ws@C~OvR4jap)FaaVlx~zC{t+Q+uCLU|K(*#k(oju8 +vQ(J*?O3^p9QV?Ho4pw?kO$zkeHJuN}Q(T2nOK=#4&-|`jw=eL%d#1XlSUSfE4X)nX;^}_IKoyY2>%@ +3k;=#e&E4SKj#kp}%Zo;>htTQ9923MGqp!pBA!jJ@k^#zYBR~L76)pg}a^0&F7mhW$?uBTOOAA)Pn^z +GJG+%jF27U1En3JoR0J}q9QAF)RLJea@XDpku=!PE0Mb`D~G%B&M;3~wEZ`3cvC!Eq{Z5cl4Ac%n?Of +Pk==XU)lUjG3bB6b9)O*g>&e6^d&M15&5&GKyWVW=~lv^LpaXT@An;Yinq$8|t2ABTUUPo*rV<7jGb_ +5Y8U7VWJCqsP +RfELle23<~7y4vam2^Ze`3`~KB5G1(2z)0OW+5usi>kp-{;vSlh-i^^>AW(JegnLPCjyf_kH +G8)k<7nlb%MPN-2h4NYFm-=y18==`x!_hjNLfD0R}QAfA?SS)y_rv_=RQ}!oGS#ui8Q?E-iG{iAsIC>vxp;fit{pObKcMD@Er3g^IzfFV%B~!5xCW|$s(&T{ +$Svo}Nwn`rpri7^1xO0=m7p}NQTWUH1&NIr$V0~}YuNPXOMBxMXkWbn_X>x)=8R5S^1-Z}Q4A&xqklx8^>ttShV=oVxb;on-?Dyy@R|1|vd;Cn)%?A~CY^f5c7BNkukFJ!kabOP%_E%AHDxr>})Fe9SEOaDHE6KA&5Id(S2A$lJ=C16O +`$>H)wa+YZnAo?aW=UMOV>#R4Yl<0BPk^8v8ngl)~z)fhyVxp{IrN~7>WXXJjD9A@~++4iYyyN?8OqM +j|bk9m9w*SGaa;=PYZ6-Jy-*!Ch!&D_uwn9Nc3QsV~mvSFM9h@*=R(ift3_}it%X+o?dL4xH2_L&{4H +D}YRcnfBiOSneO0`1Ewivn$brx^Q>`LM8yF!I>OPQA>zt917M`XMg36`Xryefxd(NR$2THdcU5(6f#; +a7NK-lu2q^H|CQ6wfP5iyTCPiz&L>U})DZzZs_mUPQZY%Syd@{O$=BSjzR-^0V=v7^2NsLO4%zqqMzbhC*IC7P +=t6rv4bt}5B7pfI*D_X!Boh6iZE-fOMTo@&hGS+vwF(e5^4S*w>(ig&V2J|m5-x)~V{YwdMnl-huP~< +f%5J%GFkLOcdYNnu!awxJ+sKIv$#2A%~;!O8IZf7zPgVY~o;LMfI+?ve?qz( +j+NwX6Q1Mk612FVHMNS1iK}YPbyX5Or44qM`Uwf(1_Y>f}ijQ~|82Q>oyG!)Yu6^EegSZ<-4g9_SOmx +Qm=W!z}=$)(Vl%G#f;-)y2qb-OT9QCs}1TtpK;6bHP@m7GK^2;FcfkD0FD(zCH`6ATu<_aoN51p+v+`(j9`EI9EC2{|CY`C{N}`05uxd;1|DULn`hZ8ITBN +*&_^gx#Woi_XYS*>ZA}PEqN%U1RHpd7?k9^z)@myP$wXrKCXWL{F7h|cA=6m6U??P?93Y!o^rTiU?M` +vi8tQLVzA~A=pb2a((9|X-47}unjfx5^%fc`+ed!*00!k+F +W1_e526RH_QUp95v6;r4owOr>&HpdsdI7u4s})uB)aky<#NSm*v94#of0CJnO)xq16!D88GL<$v-KmogLQ2JU;oM3^g#pZ5?AYp;PBMj7 +AP>ji{V266LNc>QK)z)DBrnpsE9k}93rbU&qq!Q{(wYN}Mu34jHq-|w}V-?~>&7lO(8Nj=zmxdj}gW` +NVMIVO}FjY%$?P$@z2`jzfUgxV)E-t!i0ia_Lg?0w%@T8wc@3*4ndkhZgl*ZZIO+*Ns!2MCBAg=bJPn +N!y&v2@->MU2(S$U>2)mEDAwx~Pf-BA&sM6gYNn1me98dM=pyTS*F=CZ;9Cc26pPHi+c_tohD<8P(2{ +9Q)MHJSxAW0xv-o%iGEA7Azb8EBE{`$rT5f4)6IPD$|u=5y{Z?=y;q-8?gbn{D9s07M9p1S+~t2tGOyIL&1bA}hWUj +iWAB{928~v^W2^NAIvr4{-?U?oGYnx^>e*)$Y{A5(BHu90yYxJQu+kcY9aAy+B?5>V}gXt+|VCqbon`L3BFuK8tjb+6cz?1$IH{W_WJ3Q=;iCZ7e73W{ +{Hmf;N@SVA6`Fw`XYLK@YB=i)laWq9Xy5ad;9+rkxP2?`1Q-bz7T12i}Q4nbyb>J1@q1S{MEdn=#s{`jP{o0}cRi^ovp9+AJaWOJg@CViSfg+z +9MD^O4B(qiBe#IKmD2yjF=1CM?YK>8N*14)?tSAj76pu(mJd{T3E5lY+&(=Up7Q1wVgFs>?77;T +&gGlvO<&SPRqNufO^QfMEP5!qBudD`|9H3KLDIv_zWb*wp`;27`+w+c)BF9lh@v~g4|aT@ZmA%YBtX& +|?z^U)!&=_1CE9uA|T0glu}Vp^+dNCO$QH#U-}y}1#prRE*cJbJWYtHX@u+K)DpZ``U}hNnJN+}u#$% +=D$In;XePx2BJJg(CjuJ?hlC4#pGVYWR(7;y0>{U#Nba&N>?#_#nYQ07_;UYdUR;$J~0LuIN=0HGELO +d33qupxbo2c;}Aa^_vch>_69~@WxmjzdYLT$??-uml}_3hrX$z#ZONIr0^>Ggm_ebRh +cLPJcu$jrOQop_Nu^E#sERNbM?CUwA)PlIylvuV5eFianU93YTa(^K`Xa6* +3iJ6SmSR!ZeSZHNzw0JI|&w|IIrA;+8s0-_+W{Wj;bpd`I<-iNMYZ{Tbc_T}--cQmK>GWQ^0tkrZhabw~-G|5dLwH5cG~L-x2q9YBr#8z>H_I^o_dsk8C<-GfKac7P#K0Z%jUIp&112L +ahQ=qFJnoCQuhGEpBRkC(x~O`O-3Qt;%M@$$<{PCLe+r-j8X^jd+U1ygvV^DS8BU%mlV*+Py2fTbIE&Vo(djg$1n16OF+JDAsN1~31)HI3_}*B(Uh#4*+ytY +okIEtYv7jCSKXznvb;+<=XW5LH74oUD;s)7*q6`i}_3fN0(Bj;qAuJhF0T4!VAv}0r0Zu8lm@o|;S4N +Lsz^=@jh{6$8feZF;n6twN&=KZA{@_M?I>Q!txFugqJENIS-9T%5B`+V9iJWj@l$Q8 +c3|aG#5M=;jKi+RNx1FTTB0AxeQ1TE^?>M{vXK26qd^XwCQ@OFf4$r41Qt*yi0)7*Ni6orlxtcpYMzP +23v=)25#O3Xt^Y%K>|v=d+j(V_PlZAylv9j!ZTvO%WxKKem$U%l{~;+{hK&=F`zRP3Rj(uTVNGUFG^S +1+cJ!cG$6cYC8Q%26 +!R|fhhd?+xNY`DY7?p#9l6>uM#{ZEN*><04g@q?g|9?)X*wRBdaI@`k4xv`1mqJ4o`YM +7?0nk=ULjfS*ldz6TbXq(ZJe!v?7qLZ3`;3(Ks{dLrqEz6^)l9YaRDd1SIFw8hV$`IZz5gdzVe~(_C9 +9l8Y#3=E(Xbbd0BgDybq(5**#Ck8+d_F4D_F(GaReqxoRKazB|aF0eJkYfKBu*mYo-#`Gi`m}oEgj7= +v+_{ylhW$)5pO{86n3aBrHmCv~;z~FX7!F4&X0Lzxe6RUP*=L=x2y>2#QDi6P{qq~8NDQm}*m!lo3L- +8J7*)Sh*J*v~eR0!qfi-l$|@Ung`y%z-hU<({%r?VPVWdp)$XCDG5ZVbsrkf7QtLwbh5@sS0;su^K<| +FcvN-Lur#=en +(fA$Br<8L#i*$Z&mzQ#wCFU;mf7O@Ux_sn(W;_?q^h~D +XNqR;hdD*jfN*UE{#pjot3Aa61G3K&s7ueQ@ +I$DIsPR9j1z4@+00E!K9}!#?GB)F(kG +EwhJBDvtqzFL-Z)}kTi*#K_sxXZ+7_sC8!Dpkh?+naGz6PyU}0;6|igYN_|TuiXb;5Av}=7@W2#R`l# +P$n{jH!dHo5G$RwfQvl08U|=7#xbD0Bl40J=zqVSt$CO6U>M +%#ke-P&M`WN(y>5OQulvRoZT`;;B&j)=pdIb?s>WX3@0xcmWqdquJQ9U@9vK^Fj^L`% +BrE85XblwEUO{es8%(2+fKytleYLEIiK8XZ^AhSoDhETYl9C~hZ>Mfe& +n^v9H|tHtV8tF@YBZSCC_vtVsTB3Td2zh9yH=Vr!E8~;|^I4bgCj_GA!y&rrqYw3EW^Zeo?jj&@3oMu +d2{%0lCm9yABF%RxS&AmWfoy2TQRZWz1`74Voe~JTir)r@eue{K^FXn>*=lC9<{F3!%&WZVCJRT_D!* +YTNdl%gW;d_MZks^oaY9*S5!5|y$YHQFJXR=&TgoO%`Z7urg4cRKCnBJnF!GUc=XVK_Uv!9>kv*_1+0;h$+ys(WtRImOyPY0+Q +wZ<$^IOOJ!+$HVJb{>(CpogK}bR7S6p@$723;@7tSEn^t^&rbAtp4%*6?MTW(%yXV@R9Sxg8;SGA5tK +GuU>nj-Q3vNXfLXqkLU^#fjDoz{pRbh9yOgufP2N&!;)UOJ)lqq4;5>%ovM48m0M~wv22>>5zljGdhR}E*4Rc}Ii=MAmwa`-fDX7BAu6()2GbZ)|IplsDdFB +M|{M=Nnh9E7H6bOS8 +>nXtazT9VEC*r%l)|=4oyVU|q*zU!c=I-&9FAAmo@rkv5gb)(6WX8g?hM_^VYgF35{MnmLDnA79;wac +-7QjXkJY>QES;WZGuJd=`c_}4i4?(fn&&;5P}8RNO<0Y+!5lVN=VU=^4~`ZZsfpX0*iPr!pd +zCk#4Ja7)}_G#V*GU^iwZG^BWGxY<Y{*mq5|@)4dCDb-1Y=HR%{k +u?8G&tYJR}c?hLVNyv-6qGsui6QA2Jb2$6;D%G*Q7_aZXd{**ZEL6{W|SMX9oz;9(NzsUb2M3@lxX*> +^ZboZsLiI~^-Ud~m2#-~s^{i}K{wj4@TQpDM&MIR1^NxF`7{&&&A??|Vpr^Smg~rQK|aBdSAZtYC;0k& +L`Q7YxXhyBvY2JVs5ecE^AM)`^Oe{AZy!<|tpe6|-a|@EvcUi;NMX(~Bhtb648}aJ55{L#qk1C%wEfT +n`t`T)_Q!mLDOs@K8%C}`Yle$+U{4^nk~hF?jCMSuOEsv40Q&H2Uq-YHcu`1)H&0)|3#)y*5_(fs2CC +VH!7Ou_TUxb%Q{Zw&2b%dr@J3QP0#pITZ~}KpgG4n}%ZUP@$)veO-p7-JQ-Q4%s_9ybK(>pzIK#Gox)ft`*t48`eNdEU#h^>%+nDD#ZCbV)N04?mCGGpepQ!#_6GSavEG|B8Mdm~hA3%<1>-Zc#S5VOmf=A +H-)|ohx{8m$_u5iMQp1Q453BGNJVhhE6k@mo-##qiuh10ufBh}uPb`b{^K7w2=0S?VYoBuZ+aALWyz;t+|FrNvP)n8noIM#F07A2-o?>LQMxP{2h)b%#z**b +x78%cS}U>(+M-M7Zw@EJO&DlB-s+6XBvuBMlme{KdswX7E;f6bo6%eLjy(6_8^(D_^27&GPO0$~Z4pv +`}FZbfqPiuEVb!BQJ9bQzQ%<+Bgl^N!isVC%OUq%2=b=a2IwiFK)zcc0l?P4cQJuz1rR}Gz}^Yg2Y(p +l(NRzBS;cwij-}&tF#ND)?&wJzidaRKb*57^d{J^&=@S~m$qD;p!tuIyTtjWRHM@11wWN>3+SaDw<=W +2LBsJ`0sShFNcpZVj6skrn|cDrb<9aW3)?i=V +%FhidXY~1D`>@3N!T8t<}}s!>8ZmeS?QrwWP_9pC#X7UcTOo?u<}$h8XmxFj^^#ChC0hmU_RjVKh57G +Q=^7hee_op_Po3^!1>;e#uuYRxvfB-fa|dOg@Z3Dysu$aOmno5leX&H+a+W57jS6Xie~9sysZL8Ng^h +LWg%0-M6L@@P(3&pkKdx*TQBQpxQNm2OF>p1`ES_RpHx{19dFM`SBCncsjLbI;1S_wj>F<)b9&LIopg +H}s$NAW@E^}=I^x1{cTTD@7={ej0fnqg<2$O7whkNiM+H*%MN+^&(u&Y{LWRGbEvm5Zj8P=R +|wx0BPX*lpPOd_T_j^U}3xlc`u(~FkZCqA=;~uAu!>yDMef#m4+)3Rg*TDXG1mvHo!I^V>5+vV_9 +b01p#Y7@YrP(>)JeiK6KSMS4Z?Y^p_#oG~GOW2~iwvCWq)elkFQzh4W(tSEEH&N`jGXDr@~8}S4yZUi +C@7_CD4h=3zlRcy42tvo)Nkgu3Dip^!yysqmHVb5CPMHiV+G-G+=K8D$*C0ze86}t%7OV&`7amdzP#Z +rVIYcutrWCjmLAFanVf`Xf{6K1Hin>MD=a@da0bS$L=3pGi?<4krl*c7*AHJJ>9_tlSpl*$b49=P)m^ +`D;>fI>zEz9?r>JLFzmm)I$M$Y@*XPdh=L?}7dQtW@#v8z`$h9h3gNZXgIf3EEoeNnv$OsrcllU|2xf +iGNK{U*U<0;1^1QyGIXfn@tt2;%d_Ket>@%YdiA--n7=XP9vDH;?B +&P&6r@o-GlDi(z{GUKVs0O{&k2{hr505^yr_0)*TCWe%el+<0XGETUyh*2*3L7SPVu_nU9E;5)=A@#U +d+UUz|!6Sxwj)EX`wg-!SgnpSOCmRciWCVd0>zL~KY@qWvGZh|RYRj9%UhFf;&<-3U!lRL$NCZF2&*t +NK5e58zzf)p0Ok!pFhCazB1NN(D@83%VzWzWu2T76w2be3;PED_aW<>vq#UMJZ5H5?`>5shcG|u*&$nDn?UKJVonV6_X)&(?Q&F-~}fFNWh3Gkgk61@45YKpo_`CzPj +dm$-=ItqDWeZ-L&ALzzrex#tK6mC(&@+PX{}E*u$@{OTjob@r4;4Nqh>CDqllItByhVc)>7O!2pZuEs +LF*R^PA`6lqMRwkp;V;TSYgzk#wVYtpcS*wSe0KlotX5w5SPulUgVYFx|ZTDha-eO^{UPdi|+Vbc-37 +e|dMRldSqujur|8w_?#dqssReQVjbc8nDcd2Drw5hV12hjMy|gdJt> +`Ptc1Xbnh3BmWMsQU0KQ&irG1(G4h*YkD&N=v6iQMzqxXHH>5uUE)8C+da1!36^gxp6<;wyq$)Gy3<1 +UvvS=)+RT27RI>F4hPZ<}}CT*JxohpH2Ag0AB^0(LS}ujZ!-fHfcc}Yg8J1`L4MtrHbd6t5eh97dub! +mzt`?vuU!*z2l=@e?=SgBG5`8zl*IU-ucT-ymB-A*yrBzGjF_t9~8b@K24~5TRs7GAGS;%bW$69q{zc +Qp?IS*WP1Z*ffVh|y<)kh%aooDWvyn@$)#3K&@5X`Ls8y4anAfMTPJQJc>=F+-^oA_!i%WPO1EV<7fL +uVeoM&*Hp=QdQZ$Tw)ivxfEQNPAN@`zmse|Q`eB`$(K(IoQ0X4LFY!!+-I|1Vm)3pwQL|>P#9Ol2~v- +6jyr@*f<2666dEFI{Zp+qr=Tl+YXFazCL9Sa4ogh@zuirnj+^2>sH>aY{7IcFFT64irk&D8aWND$SOX +?(F0wUKkiqUYwV+j%0Ad1p^Di^8U?L>b#&pi4{KlWx`kkObRUbXu!8mr04V8Z~{U(uGYxK_h9bD8bTl +#&flnEH!hYi(sWqEjjL%<-TG(pOPM;mV%_4M7^YMWul8pY4D=oMf5Rs(*;U`A_xL!NWAF#o4Bsx?DpJ +z!%dQVIzx+heg2sWe-?Gv?9ZoKXH3yN;LR_n17(R?Y6a8FC&?2}y~SecufC-IR0Xht#A_J2BsS=38H=1?9=ECtt?6-O+*M;Dd9Xybh@JKIudz{QkAJuJ +VR~6+R|_(ctnWG8M +4WZXmep2iMRLW-ll~}0Lcd#_x{$%n5bm|T1ldLyp8yFnaes(fHJ2N*xdU#tbbn_h0M_k8&hHfyh`Gl` +C`UWhWOZa59|Dm?KiwA&=7{>DtJbq1-;I7$Q`}qeIzqHHiv5QZy6DUi~bz$n0$rn9Rday3*x2_wt*7X +7udt+p_Gdy~*<4zdE?d{sN6W*BFx$<7*eJ>(wpG%Pv+=Og(nxp}(j(<>Q=;qab`vWI5r#J^NNmaK$N5 +d(Q8@oL+Lt#3ERh4x<_yU_lbE+8Ukbb19Nw$B{$7ya)i5F!(Kp2NIt1Y~^$%D83Uy7(0^zlFV(+8#me +||ZwRq@{4T{C4WI!;pu&KQ-jfeUXWQQT2Q=s+^)tAF@kD69U3;&2xGa4pWZ+uPdaEsQ|~F7tUcJI_Q*6V)CCNCk2CfoCRS;i}3 +T$Ke}#zCP3CZPS+p90vN?blSquRIpdo#Aw|$BXbu?eixX--D%@!M8V-Ttc0v&21(H%Ho7Q6BVWs(8Uk +6#&Wm@C8U=Xf-G-ELwZnQBhA^|2Zg-0kn((&ag(;-vy@(bre3~Kw0>JY?0DQC~C{f{8J0_*6pop-i)m +LQkW~)xLMTUa^>zzAmch;h_!T2N{MCaK6HueG@;T&|8-6k*wJlv@zwM1o`%G`T?J-7ctpoFV-YT@xU# +rV|mk8Ub{tOQJbzfK|{NLS%|cLHRR*3nVNN~oxCr37?z5Bn|~xiPI1EKg9iPdKZU`wE3A9fPh +1CV%p53jq9dwTc|9^pPewMDOSa|Gtew!u`-GabiABE$f&XS&og@+TPyQ^j>@}H=`|}=BaAZ2odY`I=>I`x9I<0R;=}FY^ +Ux-)PrM!s{R%p7hfQ_G1)MXQ*e2Hif)bNgTTj+}1pzwKtYfO)ehlg>vO}Z4S*+e1=+Y*#ZCTik_o0sX +??r(I;X=J0#!r?2YF{m$G+KUYI~csX7s>z9 +}D?MA%nan@Y`Tbt_0#{=QMWHexA(S4PwQtiaH)2`OUtKR8{c-H2;F8S6wbSdQdEkfPsCaof?`5n1!~T +@4?MPX$MtT#{b>aQvEvFq@Y68HSb&UxCpDSm1sMTLV@%^RH2={9e`4iDrH%cm0`R2^9YHBAcmD2XP>E +xoRDGtDY>g8OM*Au_hd$EMBApfgFw$v9cgHD-mxIFPjL4h100Su{?e-3Gf4)3jbjSE;)X4PH=K*ri3x +2C4f#2sHJ@1J41FU{-Q`_-9f1X3CD6nO)4r*Q{ofFn5rYR8i}g<6>|lAZg|aYa*b>=(kXncIKT@Ao^R +fWvk;*Ub)>_EiIg$-YT;7ZkWpfvEU`c2=*YvGNRv`>2 +$NAmrk_jT=PR7hK9VTL4a1R|T{4z`Z=REJdH7pZ#K^YyR +g==-BcAA3M>M(tq;SrP5E%bS*4#q&oV%Aiaj__5QDNgAmhG+HB=>Sb(pg(7@>=0i!b^|a+7;^&22K+k +x8yXMO?0SYRT(c+i3A95_b8vc3>E@4W20~mSjo_bD2Zw-0*`YwH40SJw)A!)0p7nHm0aZr6gFBUUjt2!z=zskO(r>YReIc +XI2TvA#@CzCtsny_1R2M>j*>1$>j1@Fy@Z#1fP0>cSL)*=sVn#8qj__~YXbar=uM+sK*E;R?ffc^JLR +rEk*0*R6(ctbeb3Akv9FL((3}Rb$Vo#+H}d})pMi7)gA+!_GT3A?d@znh#qh6?Crt#-S%eXg;S?f +e~c&f9kR{dWXrt0J@aVu0Y9Qb+w=(Dic-6}qI=NC5mF;4B;6vzQ08do8mU8anw)G!X^X7tVv=`H%nvD +Z6y#&!Rx>4A6t1MejW;&1Wc`Wo9@Gx3`wBh9SwbiDDs&0W70{DtEkj46!HoEFcrqS{@Wk#}nYe8*yqK ++sWm?4q*1Q%h1_2;~#T2dQhyh3`L3ji5JelchPnS|4zu>(?(ZVlr?YW9`o=(r^WSx$IL2!+cZ6dpPX( +l+0a@A}t5i6WOZ!Sl(^!;BMI@&vfR5i%nWrLl~hNcVIF)*4X74eHPCmmE=AcuZzDD^4Eb;_e{I%uitj +ixwj_2v{@f!}m;d(c9r|4YIiMUFwEDZAd@IxZVE#(F-*Dy#&w(C`CF;0G<`EUaJF+htq1a)c)u-I!-$ +43M?U)JHa;Ubi?VNt`F11C~oAH-beN$?_>M=fF*J9L-*ao4nqVY%LIr*mi*@Z>_moOQPD9a+iuaj##B +6s>>lCP2meglH!gXM>3vhz!6R$6Jocu +j}G@+(hi!u4+rWYq)_qc++vNn4+iyWsEfRoq*#jnCQRxSvz1^g^z4LqsVfE^boz@Z^X!iIWyK(nx=Tx +*}kCH`DVsKsRB3uX{DQA9?&V|67^DG6t3f$51T)DWC)r&1`k?mwQxw6eiOzRCf3*g4xA6!1M-HX~HNC +yAm%5}+xn)A*Fz(4bJtMO*Rf>!jpEml!8H(xZb2EEG!Wq5^XOLvKimZt)cpwyrO`dUR{UA=;JTi!EcA +cf58*YrFXfLpPC-Nq|B4MA;tyH3oO~dMPQzYNC+h7^Dg#OaZsR=Fw1JVe`)98VKRUjvUHd%?4p+$`D< +Qaa_5Yy}f4J{mL7uKeHFn?RW%HE$!Mx|GKZVjrlEh!HJ4uvv-kW1ReD#gf|AS!qXBR=&Tj4aVk>l+2W +rFgg@G&DC`Fmu1jy}s!g4kY$`(KjRaJAi#8?WFo0zaME}+vKC3$X_+C6W@Bwm@z^VO(NbcAw5D$%LXM +l;Vwg&v4Qmst$GmJ)a2=Jecrz-iI_5^1wRMkczJg7C81jEoHf69N=DJ)o@TuQZN+&^by)d5&v%GyAgs +4Lebj(Yf)!ygYg+HW*V&usX*X?j5qs4b3lK#C0m7Cj200z(OK%6QTalKM1k%oLr#Ca>ce>V6rUAGHag +3WvG9w4*Xw9ChwcaU1k@VSuUrsqI3~68iVKmjZ16gC2`(d(t73fI@k{YBfy4%4KU^YfS^vNU51UPq1r +=AxHAIE?~+p;R2Of8gm_U1UE$7q!nOkR#n+)V*)~xVmcm{qPGAo-i%Q$4(QZ%hsoya;Da}9ZBGhE4^P +9aE=lw(vmHz@Vj_o^L1myMHHV!fx*|eY?jq$gCPK$)0|<_lwW5TotSYKKQl@AfTGQ8ts6mXjPj(}a=K +9fgzKi79zMt<#+xOw=2=|8p(@eyVB9Cbb4HDN*YDq2kgL`2#cR2p_2IGPhN2trh6?B-M6){wG1$z`x@ +Py^@0tSLRJSSUVXt+PBZ!QpG{s_v|7eR*`Xr5594b&?;?|6WSm!7r9VBGtWuk#= +1J6c%S>1e>*CMivAD6^>L&ys&Q#`J9HBGz3x@yK!Y~6t?3&Qi7(L3lFX$b~IzyMT-EZfhl*LJzYJHZd7b;=0#Py|Gn#0nODLYBM(U@yA9q-0(`~PWE^|;G*32Oda0T=A$ +#~(Y+N_Y+v(He{3zl>V-+vNR^fHd~eiu?+9T(8JW=m2@XX%G~nZWM588I{rERxQ(7?Dmt$he2p3NV-7cr0!S|JWr)+7y=4Ex_Tk>+-D{f|M{gSGrP&aW +C%F5o2`@w~qa)^FdIH<+>V7Nw4RU(EiOxsPL|_LJsg@u7QuI&Tn-2zWi~cXa@VB?W{LZ_=X#ScWw7&o8Lmi@NV-&`hL%A@DtPrv7Bxjw@u +x8HBU2oH`Gud-Cc#Vejap)F>@Qhd6f#v9zOLfIH$|ZM9i>j}zhbWznxv7s?@jP#xO3dR*ZQyZpTCbA| +B7ll?dxW=cxaKmb=tt;H2lA?E)|+!MIt~x+W5Zn{%^;fjpny$^K`HI?0CJl80vhK_s*xWwuo#E*sp$C +KiYU-ZzS!n&?if`__8-Ew+M}WebZ(-?XBbF8v@OOumbCl?ke(oYM*FKu9&>E81b%xlIW7=hjh3*(2wJ +~rf?fWi5tu>YIyo+{q*Ab{>vv%0TX0cr2aKAY9w+(X;W*`auIK#_B4A8?Cx!*jYqW!R;^QWlK$3yW>U +Sj{^N0Nl$`;aqJrGAP^Ux!u`AiAHl24MVg9e0$vH{Rw^OWYOc+D)a=R0lDt#cLULv%pJ{($>v{52 +TOB)9Lu4P?uw<`Q>xU6sbIk>Yd}d15l|nY43C-e8RDY6Zg1=VOE;EQEh`#{eJcJH{aIECDZ1wwq$zJ1 +HfnJ`7dt=!_j#1&uKB6zq@#U`D?i5e|53$;+p@}Rk=3(;ylMKn(a60U(|)b&=7f1u)@aswY6)L0~9sPCfS$>ia^4X;Z;b1uKQI_vTIBqB$Hy$p-(NdZxHmO`LwZ%$$GJZ$V4q1mnPP}QcAFy1y|K&o`%e$**n?3SOwxWr?(GwTW6E9{5B|XxPxr%Z38 +p5`T))BE?l(-ZA20PPwTWKzxi#wC4USGB;yzn+hnWy46gzPd=H#9<{g{)26hgDr~nZ|?-DaI4no9&MW +@hE%_U>9)Ze6DU>9N%+R>rAtM&hx48WuqLB%2S5@QB|-t=TJZ@E2mkCxt>k)(@R7ORypNT8DS`%!nHp +Jcrm@gLJc&~^RDv3?)nB|&2b{)#H%JG+}%E2f{q-4(V)fjQzmC9j$^7r%$%^4gy_#m%BK^X(u@0h(TlyZFeC{HV{+aarSj@VStN~8FCwM+V#NUp`{+6rKG=K+=Z1$7HV*$9&q8>P2MYKDt!vAE-vh7y#dB;}<=L3<%}7WN<*3W1?FZokh +fl&%FQmy-6IZ8e`v0$B`Hnnd?f8)aaDBd0UFPEe!Hfu2)}m^xE=olv)A+_A|BUv6w*F +c4iD=M7Vx4(nFSJkD3f$&v;%gbxE?Qt(VEVqH;2=XrE3b0)rUhHVgRIo`5*%x9;>wJ>P(F$9JZ1zF&K +S(vF%#xU%^jVGUHD>h97i-y12FDdiXd;xfvax1E(}CCU6}NkDhUK_9}T!hHL}CY=q=Ez4~v{H`Oe2O +^@hQ9o^a#G;(+BY5E5Ub{5W7?V@$Yy~{6EiM{P5)EkNEZ3%hzN{i+}#|^7Wgi(z* +Dv5Tiqk_<2DGJjGgHo<=Vn)*AhYV1LkH-!Rz6m#k!d17M-b-vO*2Jb?1VmM$l>S1s}|oIfMYhxwKa9* +_j9y6y<`ScL+9z^pvWW|S|7IeA?N0s-1NL+yV`)l{gLdc(vLStjL6ED8lmO{dg}PNK`*kz3Lvy>n+iL +6b(~Dq|Lrb;?%JCL6|V`3_Juev)AlJUr1gf|3ts^EBJ!c9Fc+Q<1%E@J?0Vr^3#WMDK?KyZb-a87t0>1Yp!nbUmwYVNm};m*wf +1d(*^wb4o8Lfs?g*mti`&@t~nLz)};7OIZ<}e!}zr$u5z}n=TlK2s~Y3e*)KqKGc?-l<)w<<)|nhg3~ +AT4{n(2wQh6EUU0^iXad0hsY{&x$>4vb)TfmBzDJfLjoJ+ZsSE=o?YnB*q)%kT;~M-+zmH0boD6A%9g +Wgt$_`2;>W&6$vByx-A;?yFdcT%vFPIM9Bp;Vmpz0D~sWN?Mr+%MI*DOxEwb1BU?eYPXdcAjoItsK%P +%4d{)s5JqbbQxo(hT6hfc^8vqgB>=3%q`-vGj3t*Zq=lTrv&*I1_<1txQB6ET?+_WV|ovh{|>>f5#=d +`c}e<@88yI#^{?^gZ1v)swK4uuqIg!=K}kRG{kk&_T6F^bvLSR303{IOp#Il6I;F?YFc-7My;z?4pM< +vYByGO6H`=c?p*7eO3l+vHwjv+2)VplwAj{MMXZOXbXv=Daw*|W9O~L_F_CflNjXKg`IK&nP@rc@$AR +}KBlUfWy^}IRu5Zu!ySVx=)$lk{#?IRy#!j=-o!a?qHrcv=-)z9Gi~McQjRPAQ)^^RC?fdC&gl}QfKg ++i716V8OuQ{YP_IRN%KZP+{ub{IELbTbO&7nu8i8M)-U4k>JwLQTU2l?o&Hj_@R{S;Mf&;{<>F4Be89 +X&0d=MXzANEiPao_pm_mcOnFbxn?<(%f$E?b57>2l?A9sv*H^7zOEK6rn*ygERx20feK%Q^w)KHBxt4 +Vfz8Zs%82D(r**p^yn$JQE?=)W6|7=mJEAH2V=#qNDD0{39nvjfBRfZ?QbitG>X)#$j`-T#oZTDsJmX +IsrbPMIkSRhz5yaAk8`2{E>#n@Fs9>Ba_=6_4BQH<=|Sl_p=T-|seg5#(v4g7wK2ynbSh?oXjI!`EUw +jko7cJP7McOWa|h*XcGw0iPA|!oSs5)sOSXYj-(mEHX}St0i@G98I(%1@G&;@E`CKkpzb>W{*LP}fSys1dI +je#LDLX$K?bN1dTwZGkPiE~^ovEDQoHIm?(7k)tCS`Y`GOv%ko|vo3GFV~Bs4bn +?tQ4yIT$wKeK^96;ed}mbc7^4V=S+)4TdJB9X8lx3ohciri*bD*G5Hqi@^dc1GkaTtIaKjo@g4Va{$I +D@rOo@o!Q^er1vy`FU)~;R&y1w1a*V0$VLJs$ZDvBMH>1sjtb7Tq)*Dul9xRG`6>H~=@0^^H1nu`*HK +I;j`>!XvcX$y8#=tu0nJHr9lO?(^>D0iy{to#?S1wh$gDzhYQVz9E7hyVL^kzieQWQ<-@E^}ckt8GYv +m@jBqZMXY>19Gz9MeBpTFC6p1gsfBuSxEE}C6VvYp!5H1F4T+tI^lBWgz*+xJT#oWkkk97-n-qD}a(o +wO^;?~*3#9QV30)eV&^KQd#8AK5u5nZSQR`2e2R+&lmylfjcvhu!3yUCUC!MGPFx23{6S3E5&7pODMY +yYgYn-3bIOg35^DOPNv$BEbN-H=Sf_8|ay0{j1h`c8D>QrY4rByt +-Tt>Z63=Zp^r-=xFx>Rp8c=12_=xUFnwF0%W +$e=0tQhs0iCp#%_#Ju#b8w$b}3Ym#p{cmsA3|q1r}k`(SVMzys3N>BrReXJe-&wa}6H`*D$9L&ChA77r$zSFxT0s8F +Qq$s&`d*i85+SUF{+uN!e5O?)I`wsp~6A_sU>aOn=>STa6U`DLZPsI;11XRZo$%wqO^1Tlh@K$6P&b7 +^!cxOD>D~d5%!*_MGV%)scF2MX|L~W?5_8K(aPoMe%w}RTXn0C4xZ}wIrDq+$34F);r^ +j`W|EKP=M!iuH?ZL5R)3(mQ>VOXnhnQx=%N#&AzVit@)~ZlC8?vuAN1f(qkiD!=eiG+7lz<6w*+PA`F +3tA4(VXH)sFSFQN=**UO+4DrISq4bj(a(UUu&u4+{VsMrkjNUN%4@yI+n3P%?X1}_s%-%b$A5gqQ6V{U9NQWUv)*|+%8Ma6u#WK>o=g)X*ea)Jl6#3)|B7BK#hK +F+6}}2btZ7Exv7?#x{vD1{tVoNzXOakOwd)8DzG^%H2v2u({L*O?)cGHM>#$0OiHHNk5m7uAH#eHVNX +_)`xIO{JJzGS>S9Rj?gcsguK0M5(Lui_2=mE@ETEHrUEVJWA!ro|xnPCrfFmG~U4@H(28fWUpcY<}|L +@<-x=B2QEwTPSGB8ublv=N7nG5VIjMNpy8`v_NXB_&*(}+(iKWcEfqyv7^`R}g5e}0bF~?-rgRt +Qk97vy|KM-T}&7=FUtBevE2WU}jBg(>Mj90`~$Iq@zA)4eKG6%tUKUrTJJDM5*NEt+wYQP=>%n;5ZQ!DM+b1-721vOU?&`4Zq;BI`Xj`J(7H_;Ij*SeUT4 +Yx|nM&0#$(R~ylHf?E~wH1ZeqvrC$#{r4fcCFeT@6q~$dtbTD!lQ=wthw22w%g7l00bOsj?r?56AlAg +Az`{rbUKfcsJ;%BJHQz0_u$J{$H&4b&TqeCYdko%HEabBIVev|C#HEB;rS9=@fMoYYHZGsm6v4*oA#h8mCX*4=p53OS_a&cwV1Hv +}_L|I#JE~hl$m(e!t3@m8hElS1g3e&}RcA^I*eT?0(C@~K4?UCA@$!lb@O6@^v2FlVE*LWkO&1c8%f? +CUAw!*2EH{30;=BjMCep>_DB$EiIQ^=P6oFm56K$EW_Y2fW_J3G!IE9D%IlS%h*h*^ ++?mt_+*NA!aY;b$xqBifgcS5fdO#F4Hao_LX(fd6@9qXvsKZyHA+3;UR0%0UV_v5s)*Qfi|F^@;|H)U +`?zjqqf4r?sgeAY@m~>isZYUZkfoJqL>0aG_*fXXVPoM#VH9sRIA#-COychc4YB@+c-4!AHoF_GmNhg +3ws*t_uXS#=yx=$}bSW2_(} +Cco9p)`s8nKbt83V_A{Uy(@#EL=6Eq +C(i1IVNO_`ke_vT$hIb4onY)8zfzA?i+E8~IP6Z5}s+9%(>3A~H`Cm@w7(Ec$9 +b{;Uz!vzfaka1tRbeISwfOt3&d;@@(b4qi==chL)oKm==je#uyg$BrFT-;*8jXAP#(KS0FNG6v9R2&_ +Ii9=7fDk3E;%o^fwK}y|7ns!R%P^@m)@$|JVoX$E0fWguKNmr+s@C(Z_Rv9}l^d#usL}VRj^6O&epc# +i_aLs%$%Hsy%`F;J^}Uo4HKo{Q^&Z74;y7|UwYa7XW8r&)vfh$I5GBA&A{*LkC)DoB&hFeW$@Ok{iGY +zG!4mmcW5AK#1AdYAAXGYuMzu0j1u%VI*Q{S{5UE-^w1 +q}8|O((=X(Gbwa2^AStG{lo^c9CTxfi%H$(gB-Dq>kP6Ps-qI|AVE}wUgRF-6TkrAenffGEc=T(|0yR +M7;9xCy5SSz!^}HI4}`rY`KY8s=5p(SRZLPVvDsz+fO=dLg$pBG|(P3F}|m=gdD;+=B&1}{b7ccj%Z( +dIkhIEG9QkOAfvO8QDKfedut#E +L5Sx_B*&K_cufQU8FBs@HXACy1T7brtpA%q|DnK2NWP1 +llzU-<`AOUxd8<x2Z9P~?B1r!C1ir}`iD5N-SFUo+y2vHK+8gUWygh^$09Qd0No?dCICLm*h(U +BC;@Y7KT2IvO#^jC!Ti#tVHEa|OHnNNE#^l>fh7Rl~99DeuSVuV6x@xCWhhMnH-pdH-cG&#VNDwSeln +JC>Qc};3a?zR!57E%suC%qQKq)Ad=&cA%uI(D6m_fX=mQy63x{4SIcPyM>sU=Z@Q4G7uDtN4BMnIerl +|bM_743LuC!kA0JgjW9RC%KN13XG|d8>Q)mw>ds@cgeo6c-Qx}EVYZvh3>9f6`4i3A2{mb*i +r``R(?7e=I=qQ3!?9P4`2dQmwjKxL(P_@2Bkb&dnvXH<2@%{Ncy$JWGb*YOqc)-|Lq8}qPncaQfJm(HqFs>^Jm(a%Waq>~rI)v*Np?BrfUQp3r0*-9zSU-Pl!Es7?r3gjRg96qsEy-u4?Zv-3V%w +gy3!${68yn)u5AbAfQDJb^Pe?$5P8`j@Xu0 +OraK)vMwF9l0lHTcbhy04iY{ocP^sN^1{X{)&A`0_)1)cWQJQ7U6XPQ1pJP(+Idbp@v01!5Wy;QLl$? +2N`NZ^{wHzw!Iz22KtpG;FSpKX{*72!%jM6xhRCo4&tI3b%z|AGE}*ekeqe}MTX=4d|>o8R`^12q8M2 +n9!@i)ov7l(YsA&vDA#CB`1o6$Fbrl^UD}>uY%}q*Q;+ey`YZlv)Q_E#TW-lteXmXF!<@{-8yj%UrH4 +P5hkKj+jK0vn58#0Wju7q$BuZF5ejGwGrHp0xr?(Qqz=0IT)Bu9rBNMY&SEou?0QnFjiwwwoBg8%2_h +mEnCrf&QoGH|o_xR^>m2Md9k&#*Se=YR^*_p!k*v;UAY_NBp_1?b9vMF!PrKoUtoJZ{vWms)&Dap*L* +XGmxF|J^WNt_5yhB^m+`NfXpC7ovbxTG;qC3hDW#E6m!gN+%!>_hVgi`BA32JH`AY+?k(7`R$K3v>D6&k&aVbVcYM%^U|9hn|?O +tCEXlFbJZPb#ULn($&?fYUK}_q*U1TDbDD6X-`dd(!yf6>r8@uO^A}H^zCib*Smh~!ouMKJi#u_|jc= +WSsEdSGPoKVyyu>FZFm{OwFbcp=8l^=5^q7n4KfQ49$n`l(WMCL7gAAR2LT|?}4t!0(+P|c&PWc?;ms +fOLkA(h#Nuhbed(YQz2M!4o^#Ggmoc?N;~vp4^eYRE-<;$qqo}ME( +^}_f<9%nVOc<*%p5uqrS|Z>VP4#xf_TSo3Qv{WX@pla4N5s`y**b>Bu1b39C|f)Z{C +JBm7n6_}-GbHzkP9^Y-?~N?%kKBO#6V;< +-ni_RIX{D!l4Y#x%clytyU|#cmKL}=MIv=wyoRT{-W9J92G}zj_-ZnZ0^eOB$6*}0|8JgP#c@U1gbAj +ah-}*TF{Sj?kn3AR-&UnRKrPgGI)avzKrhu`(%oAG`i~id^9>n`dBFU@2^0T`-E(ap}1ieRc$s9^WJ3 +gDFbvBd1%WKTVG!|W-1<@!tvmPGgGVqg4e(`V*LxuFAr_6BX??V&`^&O&H!llCBc}Gj?IIjJH6I&h^+ +N-tIfc*N@~+pe_CV{H02Sr_TrmYW}&Jl_0`nr_LxrqYtaz}yjw{TuRlhQUrTCAudntYPGXF@^DG@==V +Ff|rq7{&HRikN8=bp`yi9jI#e+aKV0wm$swB-4ZF#a&tEsG2qE)A*S~+6zt7)b@45fk;2B?jbZHN&P4 +e2SK1f{EYb4z%+co;b{j5%Z*cB$R(uN>`|;B*b>E-F*6*;aH7*eu$da`Z^fWg_*UO=Y}8(XN^p?Mg+_ +AX8O%1slo*C&`5ILeFFEdYP*@i^fy`4p;QC^A+M#hDK9zvo4n~8efGu490X!x?} +S6HVPPM#C+d1@zO@w4E^yjRRi`iBeZ_p+ut6hy{>x5SUi9A?%{SmdH1mN_$z$;m3?e5dj96+H(zbEp; +R9x0U%I}@i$u2WV`I}%CBbmFmvAG1B>Lrho63W{$zVT&-?Nr&9SDPzBtFWLlaL`av}nlK_Pz1&d`VB= +R6KJo}Bac85&(xynB*j7?{de*dg~d-PGCOh4PgX;oN!S1re{z0$O2=Rqa5zM&Yl}_J&f_p#Fer=tSgf +)JHMk;4nA_wn7=uFDLFDfvYqJto;Y;{(}dt_QUq0Z=GjfwKg`h%?B>ztl4(;-)=sLQjbq>r^{q$_ebr +cNSCsxpJ~ZV&=yQm3IEZaNl8I#m1A#Y>98l#|DA!zPqa}+wi>=e#X +npMht6JE?f4(jI`LQjztG?6r@o<*gjh0#mS9)AurB1zJ?Ir1pFRsXpC%Lxh)#9y`dUW(AtZih~z7A7C +;fmDJFjp4$xm +0gVK@=WsDgvn@a4Qq+TYc*8=RY&9tBO@?knyik}--#Hs-5o%QDN_ecG8$DhvW^Q{n4H_TCo)mhl2lEn +rqQP;~EZx-Bc1QhztbR_l7ebjf}u%4iWZoOtYsh>Eh+Bu)C>1ID?hagO2I|>XA&uYCcjK~CMrJxNTr3 +Jh{!wVuMTR5@~QpQl}${%Z?lQ&=L&APn6K^p~CKh$?p8xU(%Fq>tnIPV=zQC&Z5nnvnL#Y8Ak%Au1h; +CaL<=EH{0Ta^w1GyJG^)W27EG?Qk#UNFa>Iee^gF%qK0$i^rQDE}8c%LWFWm!vwY2T+YW+0$eF +9yPviRCGi|%`dA4K35OjaSSxPkOpg!(XJU?jX(f3?JPR>$GsvNxJ*_kDTn|&U<(zgHAvKY^+x>0Ymf%^r^b|L`Jw_w2#`%3)@Uo*@la-P$&tq#+#2i8_h?@SDWz9!(((-KE7&yPy +c>sC!5!e_^7qKP~*dcYuQoMVQE#D?y7u->BK?M#{U5m0|~Yz{=06dS2kRsiEzMPP0O0P +_1?`raSKF6aI^8|$!{*h1O|6NKVC-h+@a(8>9` +(~pegLO2N2b^Jn+VzL#Nru>lb7&m4u{Qt-^h>tG^<9+$H+yea~K`tgY)rx%1^ead_J1bGSvlo!l|d|N +la%<>`3E#d^P)Z_a9eyV!@YN-&3W^J|eQAe)7_keLXxs-x?0LK(H&~e_X9MH#W9lu3b0K@Ct@=K)N8p +3dV7m4+gpUMVU$f;I9<1Q%RrSQ9i-R%!wYo|Dk?ZS9Ue^sD7=;i#pi~f##d*xG8@FiQ$CcJZf(`f(&Y +Db(irwcJsaZGy{M1#~v2YWUEV;y%Rc>S<^zPm${0BouPQKfcZNY$Z9>5GT6vP?Pz7mIuDcQvQ-`>u{) +iPhtWlLLg_I1IlJsFPob!r3THh7|SSOwfsQN(U)tvbJEUjtbnHH42=OX +G7~Imz#eru(?|Ib2W!-!%BNW)kk`Qk$IxF5nI)?3xR}eM?R~8SL7P6SnbQ_v+OduENNtdR?&jR*eeQq +67SA&uZ0;%sR)gSIpXTE6(#v7USzTta^6DIylcsF69mXE>}Cjv#EFE!o%}TFcF|0%+r{`CwQhHq=A&- +6wxv|I*&yr92siu*Q(GmoH}jcGs1ZYEX9@?4V+rkq!XcK-r^+P~buiuk(v^DS!F)KPxY=AO;P043wHC +#~qh-j>-#)jJ!`|>9D}zQIqe;TIg&NKz#-~M10>ZFd3Pp@9MXvI)0o5Oxx~4m~*&hR$x>L~~Q%H7)`H +o~SyG3@Q3XsZfYvFSb_V$v;kCXj +<)sf4h)t{#W$E-lR?DNo+03^}lB=YJf(IFPzlyLG9d$GItfbgsQ_fJ6tHpTz80JsYj#vPEGv5_ivJq( +bs4dEk*x3F&X^UpscBJTr;z--cyqLvvM%84hfMjX=@$I!*MYw?X(T!R&h%1y0vmRk${cDS!*)mMd&Fu +AcHePgswGelcrgyvv&6B8K1_x}S>O9KQH0000805+CpNnjoajb;G=00jd802lxO0B~t=FJE?LZe(wAF +LGrqc4cm4Z*nehd3933Zo)7Oz4t3Tc1SwWO6-WlXY7Pf6u>PWA+3^tK-$O8Nz+nkEQi!_-gBOxOP9WL +0XkpM5c$Ux_SBDIYr6e}I9&soqBx;L*f6#3bvV^}@8egF=Oa0*FDR92$e>bXSrkWX;OcdYvRoIyt9N9 +BTztjc8XQ(Pw8zfX{R6fKgWCQKiQS@1cve^Aoq}BDY6&z}YdQyw1+r0;As<+Sj570mTv^sk_;*J(p_W +W8Cm=Nwf_yBLnX_6+QF5bpm*5a5OoF_Fr#p}b&4FzVLUdvYwhNr<_2JB2CnP^~wTA3jz7Qq23L7Fu0| +!SY2dS?wn!#H^)(35jU`iEu&-BX0Og1*$gV>dmTcaCnSsZa4Hz_`9Y}<-#(}`KP|8!cgQA)*FDcEd4C +>8Z6B?c;A8?-V`PP_J2!rKNupH=hkFhWPzcC|~z(tO1ep68v;XkHM8K4*;4u1xXx_w8R$O9KQH00008 +05+CpNg;c@3eO1u0Q4pR02crN0B~t=FJE?LZe(wAFLGsca(QWPXD)Dgy;}coyL%VrFzp3PI?DU@)f&6nHDR;`zgz +$Rbr+Dj32fTq?m=m2&LWhzDBR1Yj|mlj+4Bxw@N@zg^s2-OUl?{nh;sH$UH#_ZPRf7uWY!mv`jmmb|^ +Wes^_$b#o0*-;;~$U&-IEuHVfG18V^v_EZYg0L0{INtS4{-7)5fkQPQHS+ba?JO&qz`*ng2Ygmg>EfF=-+XoY= +d(9}o3Ir8ti&!jPN;a0b8>u~eBRE^Cj>sz=~VxH$Kpaz1;VFQ9;4=kclDSIjUr&is?^3^6_8ioY1PrM_19o +Vs3eax;|UlrSM*6Q<0;8l9%v0_WC=FZYhs#Zm=b2zusS0TjXAnXi9} +_u^PAG8{@tmtD3M9+Y`9M%2RZ%XliySt9E#=C5^^--Al@V2nZAum8)n>)SLGpxUbT>wY45O4kv1BiWs +YlU<=a!)DD1F+y7>bQxm~CL52$EhX8^oDyANB%5iH2FM9a*%gGR3h>3mep-7#C0HZB*ou**>AN9HfN3 +0XU9|htc1GeNQ3e$9#k3aKBp)5q#nh38Gcd&La%9Fd7LNDCA#bT^gH)?G^EK!j2J*anjMIcZ!9>!i@W +o^;{3I3rqv1(X2rSsT=p9bioTy9ga0T1nVaEA=0P5aMsK?XuUJ^K!<7Ki0hdiau^aFg(W(^NvyU8wfkI4PayBk6iXcE@YqU(0VWD;31=+ +Jl}q($vabb>V{MuIdSKDOig(;g2ND5ATac32_qg?XZPvQQ7x6cwnEtR2*w`+pQ(19-r3(H`6e1uW2#c +OWdQVH&@Tug>UZl~7V^3GIRw=o}ikU62O7;h8=gqaCX(K-0Z?ZC%ep%4o;|T3x~HW%Gy_W>S- +GHs2F*umu8A)Te_1#(4I8+$nVD)4i0LCK8o>lXK1lttajwG#ZbGFNuLEwpSw@}n&LUS*QB-LIeUbf{- +t`i7`>5x&+E3}7@W>PcPtxjUv*fNfjwPP2h9a)u;(w+o-a!$4ZG}&IsaI*uz^Cgz&K`x$(V^8dFHALiIsM)hcrT_wK@mc; +3^r6KL99(EpB9TwBy0P7L8}{i3^<{iqJljM?{LxlE2g%LK@p?z+DPdWv470!B(^usmlxTfkICHc3Gk| +{*9drYF_U`7=ebGa!P#%_Kfuj8y@z}B%W23!{tQ~=F{r)98) +@#25!YjYZ}%KwM=UeG;AIVL@87j;4T)u}da1qu>sC4~&w-`)qOw-Xbx~!ByRtcS+Dma7bTE7^t!vtFO +=Z^$^bMdF|7SVcaW%bY_(-#geK`HtMeeYD8HFFUdvSQKfm%7j;hh38=m0-t-%r4>_n62Kr9 +I0VakDlNQ138B(a#kSVIvyYc6#KI@p{xD#;0Q0uv?@g^KF0$(561=z~;^+OXg%%Df69ts-$_rujAzJTG4zD+j;<7t*ewiD5UhrNq`Xx8>ct+|PqGF>%$BW_xX;sjFU+H7`VqRkpCDajG@ +3VTvi4N0n(F^%rjd_Jdrg?eRP%r$VJ}F6PCxcgzBl^8B<*oF-RzZbO0~+-Z0~@92iC_&}yW- +5F6;W>Xg-m*E*{-Yw`C9xphQN7+#y`t2XFQ*LD9@#Bn9?2M$Rka1J5Z6N@Wc6SfMp_1k?3XqXR+l9Nn +!QAh6?ftO~jJ2fca`(D;KOn}yT?j&wX+1&e9YoxusHMT`-IA+$rFX64H>$m^0zR;?()v|fm;$5XZ?s( +sz1lrEUlg*1-gyxCnNNus|WNuDxD~4V(wI%eb(xl#=0>}H(dG?2XF+t2{RTBOb3Z|C_o%=s5KF+OZfF +8toJUh^mbSFO(L{@kTR*E`2E#E%F2sP@oc7;4Azb$^B6Rqv}zw+Nsf1idaW?sEB_G5lJ4L=n;589us) +YOq$1+HqdXDHVf;}={E-w#RAahkdB^o`dpdr8?ACp)y9@`Nb>C~6q;=9gl196sU$mHx^06h#kLv^ZI-E?+5mQM}NAT0I+z*QxQjlR{(v@(@h{m0AvEe);#6QExSwIDC7Q^t +y0ceykg$kP4D=aWieE>WeMT4c$v9Dgsi#1T(Sjn0Gq9Wkcd~=qnmQ#%oQT`0v9MUKlbtsk1{vI8dpIG +ZM3pAXTycU7>=kKpSvN@19q`g7qZ6yTAYIfxX9ALLn>nc^1|FlK6G&yYywpWqLVlTkORWGfOa6aW44L +?V1>V&8kgkDFc9l8^8+Nl%rnRonCbBdv7jyg3H>2>h^zq(>>+A#$ss{uJqZdnQ=$@>^SF*T)z$>a(<) +CRsFo9!AA{(q)<3zIVGbg!;xLRKr4B@XfbA0RsrzoA)Lq68oSG!NJ&H5nSn`2=k(6Dmip1ItL$>5fa! +@tM*{!rHMIJ;3dJwoFOX8F&t+&>eOnjQM#ns1~FO&I{%@*u>e)ZezYF8^Tvm|dQY+4T48`E;>hS92gXySP4|O(A!7d3yf&YCbbk5?l9La!^V!WGV<7c$c5{hzKVHq*gk4YOH?z~v=aV_R{ye|FT14H9heX>xv!l>xQMXK2G5xn!qT*MH1szka%5pRUf&rjYqz3fxUToKIzC(6rO@$?Rgx&L$U=U#E +n11$3~52q<}EUp`GS6YHG7ztfx9)g?CO^y>0v4#_dJb$(MIf0-?&V>X%37ATgF^Q#MNCJGjCu80g^UQ +Q()6neF900h&Y7t?|yJDX0(+H32kE#32k1N2Uh@mA}d(FN@<)= +!^g?O(i1+WpuMR)oHOUin49O#bDq#ZVrPuh1yQouwk^=PfL~cOG4Jqj?=rJhk*6~<)EVy?~VQDwf!3G +A++bS;Hx|&QwlI!P;oaEoGEx1?W+}-JydkmaeHw6$1#uq&TLIGh*t5}*SGBCgdIci+wS7GSp2TF{QdD +Q`}u@fZ^!K22t>AG0Q!Ew;1A7Bbmx!+5I0N5lplZH#5&Vk}cqn))S4&rLnbppmh1{_)j_yV+JX*x0>}2~Ci*Dd?)ZjXg0-WbsIL +G$LidV#N61o}m>Ba^tm1Y7>zcu{ReQ<{($v^(RV*f4YNH=_Rw*sxdU~i9sbSCTqs+0t@!Lr`4pMGL*- +;CJz?2Y8G6pAD|%Z|XV#$Z&JAxA5{cEJRr{Nj~GB4GbIZ0Y +SzT1n|k8f+Vd>*pjVE~gXT;F%Vcd*dHjM0lw5&@rQ;@8~@^irfP!tso55rSfd?I0C05%8;tO9SM9JCK +Lmirft^sn4Wwl4WBhb)1QD8kD)rU4d<)4CvGhC}%~bjwbF%x&x!@Xw(q}@f8bifghE-|)5bh#BL0|ocf3Rcx-c3O0~1`TJj`&QAqfYParnTkkwF^dn-NRnvYxR*9MQOl9 +^!i#VU8oPF1uST(RBge1pc`=7+HQ7f+q$(7t9&VeTV~Jpqr~ijbL}+Yl8WzQAznGekg!^lv$9#1Y_66 +Q>a-76_A$6F&fbr9g|FXfGxu#0c=BR)R$5QMF(DhN9JEheJVS1M=wIBgy3^W{PE;6jw+p+!?bA`L?!D +ZyP#5SggLhuc|aKjj>Mbx1PhhQnAs#E&{8bpk39q30EA{34b_TNvtvqdwZW&UjB0v|y;lee69y%P+oQ +P;ZkS`aB4jywI1{CYf|s?7CF-coHRV=^tLkkz!N~;8aQly3>STk~j!u@1E$o>}D&5uvX61g6Hm4J8CC +<-ZhYAC{b$G<8;Q6)&_jdrqCuw2Oqrw!f9%S_!R8hy(gGb!f1xI8gQ{ZUkOJWxchJa;T=rcf1(}0$_f +gEEElE~|Ab)Xf4^_gQ0)quvEe83#6hen^wFOuzpv8edq@rX6|j!8$2z5a2DP;Jy@?{tv|Al>F}Ak7Cs +wJ?HzO>5ACsjF%>Lz7mpdmEXyR_|_50nsJZI=?$jSz&)VjhTj2qd?oCjWNz`X^RS*vIw3o0PNb$*3t* +zb!R~P7!$SuK$w=YwOXK|Hxlc`nh2h397KY41imu4skZ^B{26YWuXoV81)8p~fpsFzUQT +!OGVl*TF{y(EObTEx>qs^f)`x`7AL!=~(3eoK8d^CLpOpC5o>ik-=`gb<8hw#6~g~cP*XfTA%T7@AE+ +MGk5S5sLB_G^0`W74L&<%8j6w!2wvRR9Keb&ip6-80?Q*oF()-TJbv8dkY=|KQsehc0yk!I>OoRBR1t +L`Y=^e;(8&iZh0l=)rD^)Noc1<@qh4eNGS7*Ek|vXc&@dZL6_lcxEFjUaK^r%4INwU$)5T^FRamyUj=C3?R@gyKH1&bmnCJOGG%=U1Hdd?pJBZt{wD@UC$hh3|cz%)`5a +h`h0iKo^eIf16g6-C});1o09N&6hCeOqIyC54`4d?QTv+n8oClZH0VUNA(-C)FKWF7>74$w5WtHg0;4 +%qgKkeXY(cA=muap|_x&w%HZB`LIaF(!cVyP7fQS=*H+4Vv+Q=5?23?q99r7pVuRP8OJqciuP5 +p}b_#lfqu+8C98%iA*p9N3P0*^G#eD>lnW7#X40gsc33KWm@RFC_2Ot1+$DJ6LzeE8($_NGj*x6qu0)<}9ei$s^OqavE|Q}gp79rc +Y|Lr{cl>;_**e)e8Q^_DEa5O>!i|w*_2L&O8fsZw0(Sf=N9Xun;6fR~ +^dJ7&#kz*GiokYsM_;hn|eqE#pJ?ZWk$$S_<4VvRh%VkL$Cf~S0=xhR*^*1@_3RFTQDBr%AT}&^U*$8 +fz;5+C>anwN?e3&lk6{H;%;1OAs@J%I$2olf^LU@W-CG??^Lxc#ZjS#|qy1BVt@bp1;TQi5cL&#(sjn +iLeRfI;yE(#0sJ*zlvdAsO%*MWC0=Q-mskxy+1f8{(UnE#=NHjtDjsnSb)Y=sfAch56X@=obRH=~A~F +f2xot;p`l6+*BZ_1FXE_<$yMNb36frv ++(|uY@>hZDBbWu`aNNirjgGm!SlK;+s~?R8$v!NYz32*#kR4e`Y8qu`Zx2Vlq@f;)-i>+{2sjAi)LX} +~veMc8DdwE&oW|~|!Iy#AU&UsFx0=cxIi(!kM}1Won7z`!uc~Nv{~{$_#gS6RkHwQB5O>T$8g;{kfVJ +Q+j7Nb6-Y?I+T9vR#8v7;+BpBgt{C-%C!R>QZJPW2;(UI6T26F|P&w7z;(ayWXOBVT$ +B%+GqF{CIv0~r9c8Lb>E)4Nn7?@{-4Vvnnkv^3z_hIDetGZuM +9@17fBjo{Y`)*{h4P=`;`x0X)RRDKzi&{nlylx_odkj9BCz`meRL>g>Hx;GmqDe1{dcR#i=WdK2sJo%8wGQH4xW5=IJ#u^FYyxG@DOBxfyG +bi-W`biXBK!F3mVKZRA_AI(X^Ts$8)j}ELG +nX}tkC7>V&;{JaqqSYFlso0Hfnx+wo)O1h-YE!9gGeT?&cutLFlHupO2m5&9vZQ=ZLzk&ZNC|x;m})P +9iN6Z8;J4Vzy6>y?hNiroSE2+z!uk)bw(duiNgXnz>rOJ7-+-K)>0HEB)EZj7wSj&$yrG=hLc_eBA3V +8>qNPawzU8tZ!hX-o)`@txxS*M}0x1U2of4yPw_??m>D>n7w-2&ewDGRw+xD-d07tOK*#{P#cMzdYf` +EPa^wfnyctlbysEXuf2d5Cp>CbKwU-W86UX+Vdx+M-l4-gNZ^ry{}KXt(2JdW4B)NmzXKnjjx~)#@b7 +q*r16v5ihnNlTooVE@+%VBS%B9Yx-7^J5@>(U_{s%upX|pcH}b;+I|6CVxlio8l#V%73b-guzA&t)wT~vIj7|CwF%u)eV$|1!c4w``g$_u$0<;fw~;Jwyo +-)D5A8+qFoQNX!#>nyi;C2|*jyZ_qd@$BcpD(r)NScTi`#ddM`TtBvO9y>kRnxJ?2vKqYZ%@$<#@MlF +5N8fPsQxmLvv@&;pmlnjSkJek%N!8JzkAUlivEXa)Kn^8}`;Fu#4PT%EqpS{l0Iux#lg*|nyq;QzpmH +7Rd*TdNbXd@YEN{N+ogz|?>>SCou=H)ICC4CMpx}c;(9u?4HtZ~#20k%9=^UNUqbDD+ +Zut0^YXncl(ca%y={L`z3z|x)t-2ICkFAjnF>3 +XAgz_-oban8h7zgimV?-8*o*ZXrl%bNzGJL`^SxAuR66GnE9wSwak}07DATmR2AkfjF +)bxKvV)D$~Tp&O$avh*wz9l!pE)#nCZ3_6p5}TR5Ci+V5V`(F7(0mAMnD2gSW0R_zt~m`;-k-_g_Nq8 +T~JZO%=lmvZgTzG8@TQqXGT^(K?pNgXe~!yQH^d^t7B +AU>G$~&R!@h6PE9W2)3o(~F=K(%|CMJlrkg5d7_W|A`&99Swz^{q5Wqs6rKy|*P>@DNP!YB0{c!-Hci +alIH8Qc3vFgT{n`O#Q>I`Z)APuo}Xh6$Gbi>PX6N9+! +MxbJVuNt)7okHSB%RYHtmq={0N1oLo65Z&JXLX0fHhN><&d?Cg>W~8F8J$vqAWmW9w7_ApIM)+0D|`# +^3uP=UY6BTIUk2)Q)2)qHAWb@wr5%)1+jh|+PEBLmN7DlKbaWqBCkE+m`qWd;qyJU1e%n(;(-JMMmib +TE@=};J#QQ?g_ixNaTi%L685mD*jSd6+PZ>HYNS5ZFjLH^7*)fI%lri=o*Iv+%HT?O*aAf0xTGbSqXo +zwQxTgAG7bt`KT3y+VeEvj12TeGDK~M<+&>8@rO)i6&Qu?J$gotgOqM{FosY_Hsy2lt;D9uh`Ce5aQ< +!*>Bay?Ia(&{dBC0yg1TlUildt=-vmbi0zYkkh|_)|&H$V`R}j2bLKUAURI=E{?=Mn>4PqP^-F*6eA! +YEi~3_9ag5-BfxW82>eMBi{|d!D35L0Rf)XdWXuX;Ek5BQ=Wvb$F20}pZ`1>GyH)E3{aq894s!+l7b<8i^VOII9ccOLYj8Vi=w$J7GF}$LXt-AK_Nt99hmR3^WNK +|iK@Ht4bya6pb-71nX)nM~+2?8FUYc0gy5$)CRAiQgWY|J-K#TI6%JGe?O1au_sWm~xocNoY-U&Go;* +;uuS~w&L+K|G?s$*B`GMamEWd@C1wY{vK&Kk@~fIo51F~Zf!JskboGe{o+O#7d5+N`m%L``X9mMvSN_ +sBSSt&y>Gh`cPZMhz5L2jT4oj&=Z}0LySV*|KfJNFrdclM=_umPQP$5^PX2PtFj%LAoHT7&W%~xMzVl@Rvym)0v6{)8dr_S;ISsu$O+xKCKiFlu>A#Trm{#i428&JbK +?!AChx$$JA2v@Y#{x+Iu}`mw8QDm`YYl%bnN~Su#qJZDsW57xB4A#pVdugJNS04HB3`vR;Eh5JS0LGQ +uuVC>6P3{W8B{peh3nW6nqX@q3YNLoPAO-3;^`ir8=ODE8a2{X=CSt`cBX61I~#p#U>@0E*HVnIGp_# +R36%tEx*oTiw~gPbF~6cQd!PwS(~x!DJb4k0H?52x{FDVi`fCQ!GhV0A8_~j1`64V{j&12au1B5whhI +*B+6Ki5Fycohi%UXa&OuiH%Td4Q2?T&b}hwjj>8>&676UH4Cc$=sZUlN`&kTWp1H44Te@4uQz^VL3=2 +_+A!=AHU8*@j=}m^QK&Ki07icoMUQTTdvJl;fBJ~whl)bM>&gc?jpm^#;E5@)hBg^p0ib11GzC!O=O) +doF(=9L)RdD*ib|AQ{U?V$Zh@*38RT@6iwq+%BCGiA23G}d9~$A;BEQyhPOpMDT8@Bwwj4meb<2t5o- +IdC_h>m(BAeajt{CKk2n=fA%Sf2`IS({*)~HGrc{dwbb10CV^p1RzM(s^u0!*JU_YtW6T +c+H-HyQ0_5)645L`LL&YxvJ-SRH8cc;0|u!@jV7B}pXJN(m^m47R4a$>B;^Eh^fCmrAY}C?_1~h+wSy +f=AG+shg3+MRT4AS`?Yg3@}rbi_8WphVh{+U}Mzj`20lv#9LLdBj?W(HS?A}{mz-#oJPTB_fDg$Fc<6 +ktc!U7PX@9Cl?*kPD29Y2HJsX4Jw_7DGXYxW-l6g&$MSSs4ndqZ=_F7^>mRi{jjv1Ly&IJt%VX*$!ov +R(j8h2ftl%!<{zq;>Sbo~TrRoO4-U~ +R0c8v%Y59Tr*&oNl(L=N7kzHA1Q?mJENAs&6u+mb0`%!@$9GWM<(LbT|1!ecTvnhKz +MTr`pURk#I?cK2f*gO;=9&^sc{hR;faVq +f9yHpTbiu%w9c3IhlJMInlyfv@)@aQB{eP8PEft38$>=v~lh3_aZcC#G>Bv=mtgF8xO%1Oe#>Q!I2a6 +H%<)EZEaknv6n)#`SFqVgS8lEiFk>gN-;~Z6eErQg;JLZrTB^~J?kg=7Yh(}Ecm1?Q$n{l2S7fjW>CJ#rhr`HTaZw8o$(tq{(E*8xEkZfX*+RYGjo9M@mFF_(kaFikDx3uY4Np6Hob(C~62{X2%Z{a3S8aNhH +NG)DzE8fBTRGC3R+l-&-^Y!dPBGo8&A@Cut}ns0A1V^YuuB9>yyT-*QSDp{{ys?%iWc40=U%jeaq@#p +pjx5iDpJ(l^NrVo=Ca{01kUS8GX;sV%;MXIe#N0qIh=rQt_~$)JEyZ2`82t$R_$?O*w!hH`k+CUH7rH +aqNVP@Togr7eOQosQpo3?hsyK1TnDBx8OJgDgr-jtt+pu?Lk3ZBk_4DlROK2LBIGO9KQH0000805+Cp +NdQ)?I<5c!04@Ol03-ka0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gD5X>MtBUtcb8d2NqD4uUWcMfW| +$q#JgPu3VXDhzk=v1DVtT8lclmi^SVo1QHi)|9gM(M{8Z8ZK-6RgnMv9U`cTIiKIqLMyV%u1TFz#{6O +MOsf7oybJwoj$)%RZ1U>r(JPs5?z7UPlTC1wUF=MGJI74w0XW@Yo*%uknfUaK%WpZ)sg>7e8ni;=IVv +ZK!V2(#~DwO&SFq2>iB-^V0XI2AW7}CCRUC=77fAsrqj@1`XO9KQH0000805+CpN!nCKr2_&004N0j0 +3ZMW0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gD9ZDcNRd4*F=Z=5g?z4I$v<$#e^&V3~gX;L+ZbX7H* +vt_|7SOwd)O``VKcl^b&P10}y&%Bv=^PZ8j(bkhm4}(-gRh_J!iIIl!XHdPiL?(cRUkfzX`%0M8vbC$%cWi_JfHPV-$Yh+s22nyx$FU5 +TS-TtqSFP3`Jx#s1@dX-|#gxY&@u)#u`hACTpwOY=gJrfml1}1f?S9ZNaYEih`WTm||26M@6aWAK2mm&gW=T-ysV +r0l0000I001KZ003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7NWMOc0WpXZXd6idDZ{s!$e$THEt{CDJf +zjgjR3HyquXh`;4F@cTdpHb+Vl#;l#quP%x$M`El5AO)<#aPp)Uim46Mbz!EtvbUZ|hPE +!PR21m*Pws*5t)2)RmCAguh!*TIIB&jRvVmr}WEq`}rsLty9ZOQEMqU2iXff)A9(<{&O#9zV;#?SgEa +8x4358o2>EEXlFN{x2t+{pshR!<9p5364(XBE|~J``urM^P!VAqsT%ZTb1jcDW +|Y4==yHY+sgttrk|Lf;}k;Rx@1`nF79F6YKZp4^hL~ii{q+Sb(Mnwb{xxDdH1RSm)uniHUHP`+!6JK^t +FaoT$ZQakXzb3wxlO`kHcHJ9z&K?gcES5PQue3}uY*WH8-=CQQKl=O2@>z#z4PyXqBxsUK`!n8L4-!ZjVn6*`Nz)-a5-kd4bh+0|23y>P1GNznRohRKw(cUFjF=VqL%TF) +c<gj +Ao?VPQfwc!+*I+5>(h(o$XR~P`t=Fx?XqP0eO6Q_yHTGgw+hL5;)NAJVsb*C@uZXG-?TfpBtQ1dctF^cMqH(x&hGuoAX +{L|u;HrX!^hkTaINa{U4WQ0*D28weJAbDSnFA#-Io=%vRGf8WX*D$RM6HuQFq=ck)K`!@t`nV52O`X! +`Fd2H(wROwb>2a%%hWJa>!P#+M`O^~d_`jq(Qu@|$1v>iuQX%}v~kxgR@Vsr>};(Kk%;bDFgyOGgA@N +>Mv2n93dZ$^%pu{ZSmcRO5c@jXk)h1K=H=f7y0OUn>Ug +6^g))#T!oxN;P&bjv0RR9N0{{Ra0001RX>c!Jc4cm4Z*nh +VVPj}zV{dMBa&K%eV_{=xWiD`eol(7RgD?=@{S+rABBeY)qzwI8B1KV$?#Q)|;Kta@0zaAc5+DQi~`n1mhkWYrIK{2uQ`!#y0M}@d@L$Tx`Zypbpq6vq^S*FJL*9GxY2>mr&QMw2)ccRr>h|E>G(#E}mWzaK-zS@x +jkF}mqdOk>W-r$T)gpDljT}W<>|5*&EbjQrP(7L)|IZ8-UCS@bFHEr+D6Y%y;Wv6yrDcvj3e6Yh9$Md +~fGhD0P)h>@6aWAK2mm&gW=VMxOYqJB005u?001HY003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7PZ*6 +d4bS`jtl~2J+13?VE&sPMzRFJ)RD|i(2BBk`cOlMP#o!!JFQ?`Haxb9L5dTw|*9c +2UwMX5_foayL5huJ^pBXMK;$;`~*--0|XQR000O8HkM{d$6&eM2oC@N;4%OJCIA2caA|NaUv_0~WN&g +WV_{=xWn*t{baHQOFJo_RbaHQOY-MsTaCy~Q>u=mP692w`1y4q>+RLu&*nzKS!0n|@0t85#B1x|weC~ +plxVx(Lsz~|K!~O3!GbANakB!|H2iyXQ^&p4CdH!aoAP8okcY^JdsKTkOfvJb;=*FJ`kJKfZ$@wTR*}uhL9}b?|c-UjBS`_|3u9^TpZXoAB@u?(z1o3%I- +dnXbZr;iY+Y5Jvbn0D7}TY_urWO`V4DZ*ewb@B?}OfR82P3>R%A@Wd4Ct`=Ky&$h7hf~5s}RaGFd^qz +go$_@MY_JW=K{j1YxMpW<@N)SOVmW(%Qhsu6f!is9QWFX-hZZ$0gNi~)9{oU +3?8Vm$d#viFk+wuC&AJ(l0qnsNc-I*=Wrdj_WspSInn{?Z2>Z~a1Jd88BWSwOhF?HQgIg+EXkXohJ@Mo%5Rj$N`Wo3VKxyMcWtl|@x8XN}Q-~)C+Hk +p92J`{@Ivug-r2`h{mIBp6(SZm`QyA~jN;mpT~0}<3jfh666rAJ^40{+D``!qU^j*-SEm9W#(sGV&5V +y#6&`eD3CSny2{{Zghyc5iGL +Ap~!t*19{@cA-=giFN!i?!6N{5w-N4puMJ8+Zj4DbL}j%G76uA=t&4;uoS0e}rsl2%&MC;OOst$^Mld}4HtCV`=Xe&~jhmtbB32l>%*) +Gm##JN%RH$&ioG*qm)+nnruPN+ZdhhY4nhLV%s%> +;>iTD@R@IoIqA>x5Pr^wMLKRCG0&-pn$eiT2gd7$BiePKTL`Cas#MbDo34wkHqq +Z;QhcN5O>QB&eJp#m1GN&sNEmsBxvpGw?V(fQAkm2h3(LCEg&^Ok2)jQc_B`;_w9T#3QJFc`sgw?hrt +qC{Lb+i?EAEN{?3n~DV(^<94E%Z~WMaWT8lSlF;j+Q8w)@^1mova(Sq0gcHt@JIoZqAVa7Z$L^r1^}0 +P?pl;9%@Oh!$G&U%8~SL78h_kz$pSk)FdJgm4;2Jak@Q^76}IQ!^PJzW_|~pZX&{a-+s9XEnnzD%3ud +ojcEI4~=y$Ppz${%#;1V&wTa4ld$?11c35xXza5{vIFK5Otxltt(Q!B1)qIvBCP00oIALS8(6IuIoUjCV4m_*?igz_1DcK=I$iw +(qBWa)&0&J_14P=Zk70d>VMdTU;jsTP0=I@aSP@QfuNC20O+Wp}?Sf~(y~oyk +h+mw@sTUgyp2HR2S#?h>`Ka(wly{&@>>@?@pHra`*XM1+iC%B>un*(f22*Iks#dN8933>!)QHwGj{#} +OXdz@WWMM_iO~H-}J&oZsUD83w#0h8YS&F!$BkMtk&mUfYIAfn7dI=0cpnFJ`O-{uvmx?;;SUs%rPn8&73o$<1eAel&L7A`Vd^zCM$#e{5RnIDVlt_!F0UapVmd3+1ksG*g-UfC0wV!vq} +y>OE)B@ETr@B(!_a?&5`@1L#Z%?hq_SG?M_^;fD*+p<^Ry5eU=>0-m6v_8&eDxQn*i!Z!?cTnHFyWM% +(prBz+$iXn?z4`2k4XL+QCs#DxpS)VrAh+g;6FUM}*m{OBj9@P}=QPU$-^}2Nkjfb%ZCWTTOJ9n$+sWMjXOtv)+h)@a4N+3~4?sc642n2WvQRt +4hrJeQeXwoJ61q~pap<*UIV2|++Bs=K`h&l^&|Im)T_MGVnyQ~FDjU_*5 +J^QP)p|O$!xmxj=Z-3Es|dvgRo;ar#;Xkn5j4Eca@x+`TV>izbA0LqGcc%xQpn}WjFREolT`w)2A?X% +Eo|uyFQ7TB_81o`YkxASKyEKO)($W#wOxI{)lFq8&jUJDA0L@hE! +7}Zs#6f4*pf}wFHIF+A(P(54yGP?D4FwhlAXwWVKK>?z`(u>L$z=9eLR~n%DwS&Lcy+G89Xe1Lwr!bI +z3#fy3kfAdtKMm0)HO9&!NvW}$nTDpE?2bLPQ}wtCezHx`5h}#px+`lO;RBtCOP_SAE+g>|nYM +CbW#xds3wNqzU3g_N*oROpaub9uva>o0pAF)~)-P`IAoV#y{7bI{Mp?v{T43tO+ +8;V}-Rht+#gZ1E5eYe%=_@m^yLzJ=(MV1z8tI(|kC@9FFJ<08l-S1vCqm3ZY&?SX) +v-q|z0T>BP2E)oR7o@Y71hs$&5A`*y_yF#Ms3Cpvyibr;HmVU< +74d1UIysMXw<2n@}9%;mngxCc3Hnr}=z3M)$`~UVf|+-6GH`G+z$cCN0J(Jdp9vV7v+j^EsM}- +|II8&5q+2E@&ZyU0|40*n!p+s?#i5({tE?PV9~q#W5vRJba-s^PUQvx%jom9;DU==iZ?VO%LY&fdVP= +&s%x)G-zz$mMC=#r$EI%d}}*~bhOuLRwHZFL|H&`8(klNj|FR^k*?@kqy@VXqVj4_cb|jrX>h+CZ0Xz +kz71cPJe@T3J<&)v)Y%i1*TX#2?r@k@`mir)^2&jIJ#0ZS!YASh?Ny?WLs~cC#RH~WX--dc6|X-ZfnD +lD(Oy!($*-}8YDCk;T=$#jlc4|PK4k&Its^Pk#1?(yV7$3#!|=J?@@_IqHXEiSFvHgen8{JK}*Q$RAuy*eh@R?A|DwrTKaG +gBw`L9+&z8*hl`~Ck@7}k7EMNQ}SlbHRrpI`8OKu~^i^b&PR$1~t +l@C0g0Y`>y}Y%rn292|vV(W$@m>bl{kJ0<$`7xB|lSB5BWdwve!w_iOP8!GWjNPBRI$J{{bPDdn6u9C +WJ1;Z-b1F_puDPgz4AGV5hSgNFjovw-{J +nq(=4jI@o`5h4)jnwPEn11$rTdKmmh%%I7$h~{s1-h2;i&6WuBw+Sr)RY~K5f4~cp1Ius55xLHW0o0D+bBIHjpaC9s~H0rVUV_Xo_xuJ#-6!qDB_i6 +e*BY9RGdaP_`_)!2;dG`jFVx@XebyZ-#Dy@5p#EUGGDppAL!RuP=+mLR%FhJt=D|rFYN9@~5Esp2Nyl +Us$L0!-DX-xw*;zKX!>l(=m3 +LI1_yf(o|(Z|&GGnOZ6+i_4H4%%?kWy(WT2?_LuHQ;QG0-|%5qH>^$K1exG`@OQFqL6&L>H$v^F(3qn +-oBR@HtFEzUfPN%;Jx=7!4BIFrh971=g-Q2lO_{1{5ZtNMm6$iX=f +d6*XUcK*v%_ZIO5t$+Faw-)DYA>`ckj-!@tfv8UG?x1rpH__{zsOP-M44BrB6&>hA0-2Hfp8OaySZ|c +g1{^UVeUgpvSt#?&ui)-EPG+VvC|Eu62D@Hu6l%O!Hbp(_GK_CDW^itMe);(6>A&tM&S-7E}kvi|@0S +MgL6l4i41{8bBgi$BnGIw2_CiuGcE5^XS6DIUIrixfG<)`+zmIk~8afd~-3O>- +XF<8gFKjqd^66=Fg}aE-!h1jq)u1f;gDrGi^5XAuBx|+)%ar96r0{CBa)7g0-eP{hWwn6Z0<<`61xr* +rTUEe|yFSk>9hcuQ2jY3^cGE+^%?USDY*Tp3?pcP)h>@6aWAK2mm&gW=RfI9{j-t001oz001Tc003}l +a4%nWWo~3|axY_HV`yb#Z*FvQZ)`7UWp#3Cb98BAb1rasl~-GD+cp$__pjhw7?wR-wqvKojOC$Q+oeF +$Zmol2C<1|&D4PvMY9tlME&AVgNRg5y=hFB=*5%yzoy$kkEEiIv7&F2XEIYJ()-)rXPAWx)NQNm33r( +3q?rSP!hIN898KE3YMOwF!{^pd;ld_)6r<0Hrk=vX~65&)68CU}&YxV5C;AF7uAo!VQFlPURtel2i?1F)nkVF@fmlD4s7l*a)g(EGZE +y0QLqMco*RWCpAxP?Y#lYywc(?!lmFc=KLXw0xu=nt&OIVmJnn#O@xe{M@8Am_a!s!%S +)4NXXbv=9h0CU)MHLX2J$G@H#U<*nBFaxwu?rb0?|8Vb3YY<0#aGL2uH%oooTteXlxJ`GR91=?+iBxp +wvCnTxNXkoIkh{O%7?_`0tqLA>!lJHK9T(0`F*%XaY_v3+uPa3k;?bqNJxvkm~JM~}=F0 +H7AvkJ=Tp&iv*g!vv;v-2+xpnd;g^?C^an+VQ7T)uk+c<%5Xx{AlFNC;8_8s&2{ky=#xW>2)9OT|qHBCN +n@(S<&G|3Jclf{AW(`F@_RRWnW(`||jb2m>Fn!)7TLn#_*tD6?!n}iK}PidAq>Aqqdlzr#2Z^5Jd2&p +EPZkSi(612s?^v&!3RWoOPU1v?ksAwmE<*KvUV04tYJARg6JTnACbN6NW{A$p2S;gZQc;!f_#V79bJ< +7I)$FbmA3T938^I{Ftu-`5Vr&3kL>(cH^yU@qWVmO3(J{*Fz{|chCGQ0+y0y(DK417b|IgwN(brDom5 +Ji+z9Yrqx!{PPrAosSXEX)vo4Y`$i`q;fEm9>+>(Tr+9TjgWKh0)6}J +$l5-1T6xFJxzHPP6ui8fRV6C`Oe0=$7l89JMK9lw2e6{*}V!Ff(=Ql6^Ia +~_6ZK}Hau_O%QBohVul9)_5(K{lqCopWahy|M%^$Az!@aI!}4)}&~owT9|i>=_y=hQ*(jG +)9K7=U;Rwu-Z}owhp?Je{(FN6Xf@2*Jm1)Ic)ezC9%uuhCHGI#U+Pi%Gj43$C6b=0Y_mOx_)o=e`O4e +$p+o!knQ5-fHCJ2WQPYko+h>x)V_DGV%zAVh-;wv-Alyo)8QuZm((>G7=7`x0nYA>{xet#n0ZwR+F>L +ff?IJFugw1S(H)f3)z73`$D?YZaYe7#tHlXnl8jZMWtrW7o3WR$em7%abOWAk!Cc_!y%3^X +YWZK;RA&zn>k({pjjzqH_n+W0OZrcR+3yHl<~1q4THe@~9ndGW*uE-QYp?I_P8P$7HYbKTt~p1QY-O0 +0;m!mS#y3VSuc!Jc4cm4Z*nhVVPj}zV{dMBa&K%eb7gXAVQgu7WiD`eomg9s ++cp+{_pdms!9voks?80>b^t%LX}X&NO^RlaJ{X3FmZ&i^GNp=?r*4t|-g8JwrY>V=YXlix$dBjxopU7 +ib=7FtGR41swGj4BRNd7lRmtx9k5X(Gi=wIaP>VX<9JtJ@CT;j{EmvBlN;hq$+lDJ}J6Rpq?_u;3Rc2tF;CKWhGMzKJZ4cQvAW2sM>zwnMNpsMd#%0zQ)bGED~^0Ll>Rfw^e>z +zN_TWO7`t$$63xB1R1at-gqepGz?!;x#y71T +|2;Iq4hPT@PIM8?YUh&JR!g>Wr~-~H_RyNqQ!PP#Q!nHHktj}5D9-lVS)Vau|IAMn|)_Ss!Bi(!=Aqo +ILG;6*_hj6$LnN!lF;f<-lCUZNdtck`0p%^e78M`)R7vQ}tik0N`*_Be}zM`|)I9c#SFl(}}^1G8PKc +F*&KUd)1^cUKJN;NMlj~xoPrvSfG>a&Y2KK3r<6%4LGIGQ +vOY97MU9avs`NWb!ME=t64DFHoN0y&{v7NMy6wTu=#6R|z|rZgA;^dvZ#<$pZRCJ|#ZH$$%m +caXh;TV+bA+IFPNz$(#z!_bQrhoRbhqSGOc!k7A$9EIlB$sHDHvJ(^jJ%%IHLF=6}Mfh*=^YS3Ckndr +&P(joWwTZV6jTR)#}Kc6Dv3SQ$*Qb}1b;gu9to$*o+v3uDcCCO&-KR(9>$2xm%9A71xdNA@}~B_j4s_{MnJ*zcofK +jJ&AK$iOX5z`(EE=M+UxttRZ{rKViyQd62&7TW-L;g4r70F5)F@a-Ug2U91T^{)-PIAaovg;RuBuGD1 +LPo1$jSRAE`63ub9QA^xheJ=RDGyNFnA&nbo9-l9g4U{8!*tcCWrT+(5ZnZ)x55grdEiI2ylq-OO_F% +jiVatIx9j-Sdz2N+C%p%W;WZmq@WHP>WbsEHVlm!wF5w=V4QVRgzSc)7JWv$|!cQ6U4m}%2tu?V9SKo +8Zo4r6cKJKs&cEm%7RK5B*YRs+S_D77UQ+#<)k3#SITiqN-xk+K|iUa*|DY!KTe|`!G{(Hu2jX_?v{7 +utT%>)JkOe{PLd_{g@54`Jvm?auw)__8l;W$8j3D(q3K~oPEwK)t5>a0Ady0R@Dm=S?N;wm!L&&~>%> +zwUV-{c6rx_P;Ve>nMqq2x|?Qs7@hcb(Pizpj_*1efi8i)*V^cTU1Br}VZs2Vx^<-=(qd>Z|AL=?vn< +flxRHWji7i0<|VH;R<`McU5k3nqJuebn-myaF@==YD`lzZ$duUm;~4y{(Sa1ND*<*bc9fG91XK!91q_ +jhS;`xE+($9x3g{U$-j?$*u|P-p=f2M={25A2~K%cmLsrFEjGO5Ud%jA{K;T1aHgP;aY_;IJ(*aP=Ez +6LDW?W(objeT%e|Zrg5V=2RdJk@NbGRQFLZj=*HMO0=$^JIkpN%zDE|BkcJN94BYcXfd4@TRk|05No-?V)m{?edQo2m?fbyO}go{U`TVH$0FA8alZLt}*F@#UL;x{Ps*QUnX{iYn+s*zwj5 +MLs)H}aJHB*magcA+~K&6*Z1?g2T;`X{HJAaSO7QpT>j4P`~mE|z*C4Ff*yGRCS>PrPZ^Bc{2PVs+}S +*J)kVk?p6w^gchdQob!6RMs9Esh3nY&lCMLk8;p;FH(!}jh$I;%5QZ@&Q><@Q*gp%!YZb~G7EvVcFj`mGjH=ixb6QiI5TJ&H$gW+H~4kI1MJUZn +7Ce@!JNqOpfAa8Zl}wJfQdYo*1aW^M$>y6rD%7euWTrcZPb308H15pIw&*1A+@TO8w2+!0v8L}{w{$O +bd>;>lbP;#nb*Ew?S9YHRZ;%?!eAQJ7X58KPhr|3c?ZqWi&BkqNyLdx%1cC?{m`yU%wWH%~PBpE|u;j(J)cOHt6HlV0#(Oln`0FI>& +eNW+p{46J`^_g*uxW8>xu*fUveZxPIQ?2WqwL&XFX+ +!L?moes8zQ}Lx&0vNJsW?7@rTB*6qd(GLIrP(3{R3&!d%OryU5P) +h>@6aWAK2mm&gW=V^C#X`IQ008m<001KZ003}la4%nWWo~3|axY_HV`yb#Z*FvQZ)`7ja$#_AWpXZXd +3BIK4}%~O#dkgho0u5gO&A(Gck12{JS&NcIgX{Dz7hYRMp-!We)sNi4ceaPs#YTba?_6%iC0RuP}zad +c8^(NO#ti1$B6Z*5`b4k3bBe2UG%P7aNTQ!SwsA-9LZ~Z_bX^F +Z=1QY-O00;m!mS#zw9aj9y0001S0RR9i0001RX>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eV_{=xWpgiIUu +kY>bYEXCaCv=@F>eAf42Adninm=^_yI_rDk`xQ39)plqQobx-X)Raqww#W#J(r^FTk&x)UwJ&q6*bFm!R06uZW^B2nha5S1O_{pR`BbzS3M`{Q6W2IloU-C%&(x-d=zePoaL8(hf&3cZMdfT*5Lj_$i^OS8fLh+Wi$iObFsoK1;gW66x-t) +o-}V&poF6XH{?Dg4RP_25$>wbS0Z>Z=1QY-O00;m!mS#!8rw0F91pold4FCWw0001RX>c!Jc4cm4Z*n +hVVPj}zV{dMBa&K%eV_{=xWpgiPX>4U*V_{=xWiD`eomXvd+cpsX?q9*VA1Y^t5_DS!7znT=O@IPv45 +Znzq9_DfIz@~nQXuI#9{S^VM^X}HC)+T6u_)gA^W2dZO{=tJ6*pBaRukcu%1kDuRt;-Kn`TcS3#HRq< +?B+^z=F^qqY9WUCJdi9>>iks^^R@1w9G2zr0K<0!Z6aBGou(;V!|>ZgM?EeOU_PN^9RFDv0~{ +myT4uDTz{Da2kz6w?d91W`|cN)e_mX(t*C2Oa#1r;qAzf+7_T+(V#nZF7;Bv8t@jnIc|8}+k%aA$Q#0 +w1jA`dx-*n!|pnEHXCCdtS*9 +%tQ|{pF4-eVn6+pbuW*k7r<5?*-X0OHFY`EEVj9sEN%v1(6H^#V&x0||a|}YsLRg_BBGRID>H)h2bVJ +7bGB_$ZIFW76Guq-ZSOO}6_q77FD-0AVqSQCj#)?|}g;rQU)toU?sZCwP{pzEjFgw1Z7%~N#)@XmaIRsj6cYh*^?^nm_qeOoB +jh$FQ(h~BTq;%Mt^1IcIndpn0W{Nz?~Vpii%OZ769pLkXXr +sFU|6C-dH0|DbLs@GA-seKP!(5iX}Uim;{E%!TDXU>v;}ge6uWY>3_@<`^=l##@U~7%p-42d_8aS|^! +aa7m)Xm67#5i&i}VwJSpOT0mn@k?!gK@fjHy2Yndu$jqSy!X)h>L6QD_EE1qXf$+As9iXHA@Ot1P?1# +7U_9)6>G4X-^W-PZNZ?J%>=y?S)M?1;$?4U2g#U?csfA{X^9JV9P1iU_^ksbeh23WAl+SV+Nj~|4sHY>d4G{-o>G$wuQ4 +!3aaITprjz#PB-sW(G;0SydSvyjv<-sx$%wyuUavJ)@=b@9u$8T*la^~-NBOp%t`Dt%PKmm!T>^vD^E +YK1HgwOYe2Diwv%MMm|c-I%9Tug;Ud?<9N0jzS_D4;Sgt!c3Gu#RK*CJIO;i +jqW=B2;3M=t@ipGH{4oSWi-e0?FF2af^kBkx*8x;8NtZk>$equAKI)F4VE^Hy_GovfYhS0mcJgkhSce +k^Z;<|Sizfij?S|K`c}FtN<_i~WvgY!cj|aeuxX^>3cuimX0UCeR`QMz1r_(|4!!5|Si2t*&(RF53M) +778e}W(U(UV8#)^s|(^;B?NDr|+Poa=Gg{QdSi_1U;7Q7G_dM}Kb#`kpI4bmrYJCWQIz{j2f+i +ZYCgV)F@i% +Zgg^QY%gPBV`yb_FLGsMX>(s=VPj}zE^v8uQ%!H%Fbuu>S8%!1PE#-Ih8zm?w98J#FkojvvFKW@ECmw +NHvfL4qxfT6bg*dhy~hvJZ45mq)gI{>Q7N$fAw&XW-)yqM7ey-oqY26OIEM3kQ4|JSpg`KGgiY`!m1L +@i0{E;}tDh(8f`|Kh2TkY?n)Kc}OD7Hu5ZgkhlO~Ex+rZ62=_c#QiO2UQ;mdZt-c|7VY;ebo(<#9(G&X(LO^0RJzhFaL?4Th7Q +ObHtN|gy+yW!TopY +MRj#LC&^;fh(ece$;m?8&&9eMcck{=y{xXMz>jm1<#)|G)tG#2)SzS1f5$ZGX3%m(jYAy=;*7(a_ygS +mBeWr&A=W>Gb`GdRNsz#L(9)0I>x4D@P6+Rox>2LiN8+F5(`BpWh#HfHJC!ABWp!=dSBmC+{=4WI$0o +UX|9HlK08mQ<1QY-O00;m!mS#y<)M+`h0002+0000W0001RX>c!Jc4cm4Z*nhVZ)|UJVQpbAUtei%X> +?y-E^v8Gjj@UXK@ddq`HBVulXXxxFfuq-50%4Y1;e3PTWxN3T6)^M+rM{3g^P-M)T0Ja$+c5HUktXA& +@Px@jcSoPn2sl9JlV48d^sRjKXfKBcaxR1)(#(=VfH@4uzVx%9b9Ycn0|XQ +R000O8HkM{dJ{6~5ivs`v+z9{x8~^|SaA|NaUv_0~WN&gWV{dG4a$#*@FJW$TX)bViwN_Dc+Bgt?_pi +`Q9t?9FvB7Pox#0nfo6r*I0GV8;?RXS>!MYmRCyAr{`&-El#&EuA9_j}``|103t^L;KiuhT65Nwku@* +(3?C6tqUDpU#w(sSH?myDKU(*NC0=}rPkSp-}{he!Z2o%q3Q8IUzgp=;T;ZLJa}$u^63DUc0t5LAIA! +`X5|qJ#<>DG(&eVhpN`+v{uK-97uxa)=r2W@2-#SJzrM1R2pB +LM>`auzXB5Aof?M-~VD;^QHf?`es|BU|Ou48{BEdur}3%DhqXevZYt;TZ`Z&KJCG7|Ml$$aRKg;~6Z#GJ)#9na8eBF +Rn_WTz_s^n_jFl3ymFlNR<-od8Zq_Pgs-?4e{Of83cB*5_!xsP8 +gSpV$-Q&xY~nGj5kuoBREm(oXD91=oU`os5H@w8t{|s1kz9iYuNpmbeEuVc9Fi@owg5l!ysyv +2`%FOVI3T6kXo@ACbZkKSjsX_IxYkMpTm#%Kf?!q$dItC$OsDgw8qhCuJO*b{o&g?)cfo8mJO$nu!2d +j)oiW}T;OTy{3hKa3S?)4e)q!`GL9WOu0erUWL0eNM(gO}=n&QOgc_tLZ9WzvV0CKcG$=1a@;=smK#K +nwHCwKQNb5>#Sr;&f>Q~;h;5jKEZ0p_fZj9vv4XJrrs`lmS_gHj6tuL8=m(ij47DnOrA#duo*=B$p%Z +)#o`(dhe6c)@G(g4g5)ugMEulNY=uFL+H}@S42fHF?4NwO(+YCNsEBlN(&8$qug5GFZMG+Sb2NO9KQH0000805+CpNylTr*>DN~0K_E#03!eZ0B~t=FJE?LZe(wAFJo_PZ*pO6VJ~ +5Bb7^#McWG`jGA?j=tyqKnX>G8?yF}t{Z%U&PN5?(05k~k7li +GV2~*wy81etkP<%Qz9^gLsprxn{X2uhdqRm#I29Smx=5jk#1YvrngR{bQN~8eU!S=$pB^)!PIf(vLNJ +j-?j)rnJ0|N%m=kuLO7MDV+p$=eR6#)sEfL2?*#^|8uEQfoD3p2MC +3Mio0O!5s}rb`E>iV~hnrq`nExJ;o*^SClW@5W(Rwwjdf+YPMSkkCmT!hsX*N@(o73K*SpLbOb=t^8) +Uwsj3>2EqVo@m)JWZGXn5Ew!qsg=Kq}-eb}A6YFx5C1L{^MdDQBUJ`*uKfnwE#3FrGSgTNpki$4*)9c +$y7Oi;>YfT%R&OZ!HWn;teO-(iX7p<0Kk%bpr$_&K9Krk3b0|$i7@)Gw(}dmH2 +-qdwFN(-UM*V!coelN#i2aPQoAZ(X_51PP8hx04K0%FhO2F+_X^3@}ZZ?pegMABTg8CPjA+XoHfbkbf +=*f>fQKC^$cU|iHGR-%T$t_L=VqcKnz+JkmS9K4COr&y8Uz?iZ$%^Vnb<91`pJ6#A>tEAzef?5o1Q=)~FH7s;zK +KDocTyYenr5W{jo>!KTL}LKK)YE@8&h%>1?;P;j$BDkPBCrfFQ?qShX7=*UsKX@chJJTMWv)ssYlVlZ +W)+QutPx*n(;H#=az~6#1OqX4;%kQ2?xRtDi#P&_STb5B5+_&{OR3Ig>|rqhB?IhIEe*l8A;pb3#78g +(hR)+ARj^{7MP24bn9iG^m<4)XLY7JeS*+EpmR2)9G~1H8I!am2C-`@l7s8Y_77tCNZ~?PiL8>W*Scn +Cb*ODz!Zv!kBv&b;St(`RDLlYbh5R^GzE@2j?sUE0FZyZWsi&&|Glqs!n+$^A2+m&$TQ4So7bM)yBT_ +)6(kTBEW+b2;0(foi)BvW~0)re&Y*RVp|fOHiy!6jju;edh$m1E13SZ`sM@vVlcB^y?~&I{4Shc +U7a!CVvNa~kmDX^6b#s2++4nUf9Dt~vz010N4CKr#@ow}0|3{bZaz-01_4ZyKZ}7I!tuq`boRkPSkf- +B-0YdxL-sfGx4W(3<&f>WoB8~Dw>7;Uvi~x_y83j#8^F9Dj{fs}DEQCwA?uIRck}DJ>23hqUl4M;MG1@HGnBEk$}QHwp%40{IQOp`tFkW +DWn?elz3EK96GINN4VL}c0^95&b!i&**6ID8od!y~GWHa*d~)n3{}_DyYSS?|^+vTbWq%X&zg$iAaZE +r3C7ve7rRsT2H8Z6fQgHnjkTwTUoV+SCFV&?d5OYg0FayR^v;UQ?Tl`H;mfZR(@V%jE0VrY?#0MC#F| +K1%J0)~8Lq1ltp@t4%$0+Y_r-oBGMOCt_EddZ@T3R*yFI5VIHTkM;r=w^06mM|0n0`L7X7_uv{`B#9PVtiObWGjmhh#I)uOzogKBw9huvl1_0!?idJiBj^38hR_cmU@{Nr +Hch6xC`FLIK%b8GAdH+nHStu25XPB;0zW9n{s?$Lzyi>nyVh_IgVH`*FFY69s1rJaE`rZs +B16XZ@l>*Yb4LY&z?6o%&$4?QB%!icY(at4HMTq%l}ws-hN!@T0?qYy5m*w|CB2?RW{BPsl>jieaI=rji@C|7s@O()g+R;;ltc>;dncY@G7^(|JThrV& +D3%+IHI^M!IuJ`uPaNV{*dV24d-VX0|ktM>1n(?y{TH(0D)nA|>NLbkkF+D>Vrz>D=5^LXk(4O;6%o?XUl$|usXuE?~I^(}W`+&WAWsq7^dV?pe)RxOKk#i+N73HF0C4_~aE?;t{)5V9u +E|OS^|FHwq8hUeB&MsN1V*0>&#Q2j+lR}GL7jWTZOv2K{`tqk7F}1S8kz6EP!}6rzh^$1XO`1bC1*0M +h*aiG9(q|d48C(JPVN9WD-ogzoo*P!*1GWXo-@GaK0R_&E4 +<}fw_txUzj|rbai@zP-u%$5?n9U$kMREo$Q3M1V-2$&bqWcF?UXQIDN>0GRHscJ&Pk0^SufJ&XVF;oS +)R5$*r~e6XUfO%>5kdMtwF*nRp7)~W!bp|2kYQJP)h>@6aWAK2mm&gW=Vb4*e`_w004al001HY003}l +a4%nWWo~3|axY_VY;SU5ZDB8IZfSIBVQgu0WiD`ejZ{sK(=ZUd=U0r>!=|ec!4?UrQY4@hu?X#DS8xD +Sxy__CICeF5DEar;&X<$z(v4Kro*9qdn|b3Itkkh4zCRfFtRyoBCgBq!Bd~^>m#-Enyubedix(@wDvc +oc4yDEfG$MStU9Io#*HCbQX~fH;A_L6eUv9eHPD#5rf^R#Eu5}a@q)JGc)ZC~Omx~){z3;5)L49+kD2 +kK?w$Ub6m4OWIl*HbIM4c%*5j!3+pF{@MFu1|D$?eA4J~E-LG0L$3LXBp_gox+M2<*p;5D#z-QW>9S> +D)88)w)8My?MO^wf%)VqoMSr+~Q7^=tFHmz*hv?FGv{&1m|gRe~XAqZems$Et@Lf|>7JL6^PnX>#05FB$A^ +COaa~U9BV=Vf;x(>%0zpIEnfU~;BlJJOfx4dr+{8RObQ!RXdj{aJg~5P@8Vt+>y2fagzvtQ@#r+7(Cn +4RuI&rnbk)t1vVOB$RgtL0Sc|r6vL0j-A6Ew9OsWW;zymV>1ESY3`BoB6{gd$e5jdR4;c20Bx*Vn&KZ +q-q6bfzxvF;ovAYK|iJyMjwws=(Eiq<_#R6`Bb4a*@Ud&ZK!>sV4K@pbOR3{9P8>h{<#q+)d%*+9n-I +yn8#x7iH7yvVJuPu_sQcKB!9M8@G*vH`DX>m-d`(tT*@=LQ|1!Lu?iP0Z>Z=1QY-O00;m!mS#x}ZK6F +)1pol`6aWAn0001RX>c!Jc4cm4Z*nhVZ)|UJVQpbAcWG`jGA?j=%~x%2qc{-$o?l_L+6(Ma)R%A7^+T +Gb*POCR6|!nqs}&+J6z&L)Y|}J%y8nJ-Ou!^SH(H&vsEW$?nejZs%y@iChIGAU@k=DgA2jtuiI;I8N$f+)!6F=hOvb~})ESX5PQdQ2a{5p0l`{eO{0oa&~bcU +qoCAp_2ENA%P1G>?H&Zog-;?76IMS~BYytjCjt&~=azu(IL0tkugVn|%q;E;q`sN}-{9jGE%!LaPZaz-^FST6n4{H@vDPYmse*sG&xw^FVmH_ZDQQnIl=(x=4 +**oBi)4S1-Cwc6DgCp(FX_Ev$vtp5bm{_i>UGdb3QdGcm+-$MXfSK?AoA^tyAosdi(ht6W&Qs>G*r=wBc;-&F_O5(hza)>4zGAvZHC +d&StZq%<)K+h)b6V+$Olz+1U-a8pFBgK&xcsW?k%MYZMZsCZh$Lm@wsXR%k?(PZo#RkoYlskeOHpLHQ +a?cmRhi<_?AV0_$3s#u(oaY#f26*%UEW`fX=FfV;U*8)mXDxx@ju}if$EEVi8nLEH9dSTY_bG&h@79v%PPiV6X7kE45rRl61Y%eyRLO<6L?#LFQlgNW^ +K)y9$t_+F}Bv5S?Q_3Lf{_6Qlo!HE-alpzMFcal#zNgYV==Y*vQLbpA+sgiZ|7@K3J4>z;O4D3MdM(o +Y`y22TaiMUvJQ+ycWEJd@hjkwxES{4m?`{CI?%2=rW_SN-?%SSRi`|UslMzTUxcWpZa>esB3ou>5GW) +aw0q?j_q1#0TF6`G31X8c(D$^(AtaIKtGG}Q`b=P3YTUpcf(>KAUy=1>m@p+IE0AE6ZnJKjeodva3(h +n@&wBB*LdY)q<9-cvVQ~&H3kD423L(FzvRrCL_xoV5{tCwWZ@v&N)ZTrXS_xoLTNK`CXd6(C3$=J +^}xG1loxJW4rR2^C57heX0KNX+E#66Bm4zE5hR%4qXSAOFB*p*;MKpS(TB>Y_o(sa_w>CF)GSNpaNM` +k|d6~NwqP)h>@6aWAK2mm&gW=VH@XCdMR005F00018V003}la4%nWWo~3|axY_VY;SU5ZDB8WX>N37a +&0bfdF@!;ZyGref6rer5>f*#;UMYts*|Xc5Sr#Lg%hM|^Mv-pgzXs{dA%i^s{7k-{IQF@ECkx-bPvZ% +cI^4~Z^q-)pvM<0k=)ND{Ki=zX90tEfsmA};I!R2Yr)0%63$L~G{{l{G>HgHNfS~+;O4s5AB_7jO(5i +taM*aRk)2Ev5-JK82{+Xsn{YxTe&yoIF(|7%wo8d>b|0>saXZU~F;pkYdDDfQ~3`g(JZ@ +~MZ(+}-7)F4jgAjyMl>aQ?}{=64FW3dTobba;iwnFkXN`~ef9ub~gV3w{%!w-W?EBx9wYt=Zy>tJq)n +6G2eT4OSW$s}QkoJ{H|p;H^A`YEzCL5?7!5^d>IZCw%B<1FQrj3Yq^yU3n1LG1R%EJ(?lOUP_N6n(?XhWM)s4# +J3jsYwJf&S4IRwN?VbuJ$T_95j=;^D_p5NhXG$*GmW(kA2&_-63~on;MKxKZ^APyZhzaNq;B@#yn&aE3a%U@xt4m~3R*T_U +!k<(6sF^{Alhk4t;?LDYDAal4mjKJeZRs`T#>23y5{bdxC`ql71pr&)Ha)-)7pI-P}RxT4(SEQqr}K7 +WGK1yhWdFm=@x4BVR$<==$GqinaEj=#IaY9=!N#zH}AsmYqxw91uMabwhKP%!r$8@Hxj+hQ}N{_T7k+ +YT74dzXbsBBM0-um?R3?!4*de(m1y@S`Tm?c+P*#gRZ0##30=7MDD<~Ii=F8=)n1u@|FZC|kS#5vV($ +R=9ZnO3sqj65(2UhVm@ON`x>K+F3eJ78cHX_gUFC&kU-70~e>5sM>|!x5+~R;z%mj5KYXfZfH_3vhiA +*@NIWVkFxcUA*Lx~k`#minMQZD|mvQC*?kVwzBAI;s4mmZD)3C_a=FKTRH?UOJ_N$lRl>gp`V=j#XZu +)skpg^rPKZFt}M1TXUG)?2^x*XajZ8r +>kxBgFb=j@S|xSP*%f#!yl;5SCh&h5rT!@vFwI?bkZMyO#GkWN+QdIJVYMsYPZPt=oZ12?n2o=QwkA+q<$@gEpiyp3xWwW)cYVdQ)gLXQGC8MG>r0KGm +Pbf;*ab_EHg&`-CwC_N|IeeMQEwOhnGx)ZJo^^R=V9-f4E8x&cRNm>kd|osbYfIu4f2)oTPpk7oGRh$ +Ipbp)^%bA)74K6d=^v)|M3yJ}d3Pq7%v&?7`#YFM^nQ?$LK8%iFDnL{F5tRh!O5xuqNPhS_$=?JoEb) +&)?#^T|CB1ybnZ8>loGBZ?;a{#YB_a__7im3*ShK#7zRcTyEgl^>lQei#7shQrZi9qX#y*vE%zi-bBh +Pk*${B5nr|(}dE^nlh7YNCWm~T53*jQNSX7n8`&ZdpU@T_H+!#&5{pI$9=aF7(Vb*TMY)}$EluK%zri +@h$1~K+|$)#er(P@<$-KJr?#H}-maN+o7hs{$BdAe#2)9KeH^))-qVMv?Wa|IsRN<8OD3OUQ907U`-03QGV0B~t=FJE?LZe(wAFJx(RbZlv2FJE72ZfSI1UoLQYg;Bvy!!QiJ= +PNAjuokguObDS$yD*BFG;L@dT&t{g+d!LCt_R!S<8~d|jT{pD<@xzJ8NuXc0;$W4EkZbOK6&gAHBuv3 +xaLHrC>gwk53}jrY$DqOd>E@w5bICV1VUSx6m5$cumdg;-cDRP3$e@jM-#$}JJ?LK5ljLk(9+K`nf-y +CWCbDCXt~ph5n;7lMC&*T_{gAb28+#lw_QHH?>5`G1BItd-8f>XTv3Q|rIO?usg)K<0&^HogIRDtRw} +J@+rqPHxib6cm}1k}@ctq{R3NJnmQqZobDEQ@FVZk{S|6(FRoqla3j1M<`#tgbOh{DBncEV~SGJ&^CKUrc!Jc4cm4 +Z*nhWX>)XJX<{#9Z*6d4bS`jt?R{-~+cuWycmE2kJXuk$%*4)2UwlWslRD1SchWc;J8kc}9+eg;n>9t +Me6gd+=D+WG0YCr*B_-WHcjrFq4~ZlK2M6aIoHrbRyJCNDU(AX)&2NrGQ_uIm#9wxHcXq{bv0Rnu&22 +4$Rga`1E?{`p*dpXSj@oJYT;%MhBqOlL`6C9$XrQQs!w^{T!ta&cbF>xZaJ#EYWICb5@J^@%jjki9f`bvsX`;_PdJ~$yz`sWGc}<4&Lhy5X}ww|6%2J9RSEw +zrpI;iuBM0ZtjSYgTG9gMP7>;iG)pe9VN{7Ze5PLJJg3v^Ce7+J2iid!`K2ir`OT!jyfn3-ZpibwJn-5qfY9%`aZ@_P2PU~rATx7P%X2xmXGPP1uRRi6{rBdmI+WOxd#xxHb +qS{p3)}(kgE@6cDRh{+dNt%OiJIMYHC!CI_yzDr<@7n=y` +YE`ghrx~*&A*|qu8yG2$mXU>oR)+7x{&#(BQCG58s-@TNJK#!z;vBz0tATMdX0-4~2R7MY=8J0~AeAb +^^$Z4IFbx~w`)uymiYhG;pX>;3olvPRFfxfb!OdCLOSr#`+XDM+d5ypqXZBf;RNDc;r_Sq2sy*yeXv* +WA3U{m-8BVP?iVt@Z@VK*3##n5aM0x%8uCM&L^ti{M&CoP(3MR?jvq}AHyujbs!B%BqCB`CRI`1c^(8 +~p|U`NL4I7yMg9_3Rd!>TV(Z!t*zgp`VY`%A;@LO<6R{;9x8cJ4+MM9SelAvy%YfH>m!!*hcBY*RHmQ +AAN8xpvmdk4`sAmYO(3+dY^LdDD!^h4eKPd6nL;fgKHs@DtXOPr$19ocT~Tna$U4aR&pj{tm`bhV5-6 +`%z*l{%)!Rizg1rvU_Mc8%D<1&o-PGDO4Mwdpvf>>N^{a07N5;@b#Vxa7uuk-dQ`K67Bn&~ou$7GKwg +FJ=yBA~EXP|Y@{lxn3Ja3ZT&vkPX?0UGQ!7^T6Q$!@AC&r|mnnOa0-B08q3K5vH){Jx3d5qH{dN+LliJL`bTulyabMhT_0Ocm4*$h?yeu5a`& +5L94`N83zU}=M3V_5Kc_{Z>RtFKWmjvhZIDu!uN&%>g;d5mm$T+V0MbyxP>=bpxp#w2P~r)6T%hm)g!}W*afST0Itmvm +e2xbBxVqciHFBU3)GdX9xh4o0y)ZH`eiT@lZjqG>Nj)bp5*~wn`=-m3vmz{tuG+pmWuHF+q1VXpNm&# +7b2>m;gSf=&QAndA*rAhG9X56HcwFz=HlTto!uG$F@o2EFuRS)Xol(veXJ4~02)zb(RGrE0$P?VJlF? +idLMl +Vo2gA$1hgY8&i!R9wEJF}+SiTQweH#ql<@@{K@q*#gJnKGoC$y1;PeZ52Z(^eZ>jC(Z^zji$oGh-BI0 +gtf1&{z>;InegMYEiA_&dP;ZJ)Qx}ZFO61LW16vsqF*6^r1m0&?YpWfu4NQI?kS_i9O +^@+<%+lQkq5X4R<641(yZ~)(DLsVJApTc2??skBXM*P#i578clr+{PN&S$_J{|)lRO-P&$Ag^CCly8jryZ2EXVvG7%O`B_E@j23G`pCdSbmq@}uRVsOon@r +l7oig}b~4NzH}<*=LqSOwyM2+y0G*1ALU3P(jJC^YHk8V{s^V>ig$wfBt|t(mKEeSMIjRLt8=7@01Z^G96(44i*nX;q#Ha|ZjeQ3CUJ +Mp9$Gioe$woUAAkI@>*M2s<)uNkA3UlViY!ElA#ix7s_-?LaT;N4}Lfh>N7khtfGxD;8|^qpI8ZkqFwb4UHb#k43Z$&;uUpNsLCLj +%Q>d4@Cbxuzyr;z*%7c5!PD&p${8aLcpG~06!LkfL3l$YkAPK7Zil+Nd|iLAt5`{JCOK8_YJYT>KhbV0+TkVNT7Yp?r!g2yDOt +^wmRH;qU8-k0#(5awpQvfzbQA8wAWth4jJdG9>W_b;Nk-M39-!^-H8j{3r=q~572u0dtgz)2q&*pyO2Q&3jLauZ1Ikd1MOG +Ad7+g0?`3Oi@MkshzMj*mCW{yl}>rQfS5Gw>nCdDkvENkLK5(?XvNd^n^K9SO90G&0!O^9|4u23i!KC +WhEx@;vfo$CohTMkSX@u=hV*__Zz-DB4!JD`b=OT52t04Dl*H>c>y#J^z1_%lcdw&}Qo_@h@u^hTWlo +~F(@NJ)q)S&l3eu@nIU+8Q+sn&-honm;`p_`J;y-9;VUp}51>1XlDcF_uQ?5?P8L0D=DK6Lx2!Fb~tb +!m#eixb0zJ%@`r6PJXEc>XsSsa+iLz-nG!Z;NCSDZ|BOFM39Icw6I?Jy5FSdygzeUJ=XP_T@lF?vXh(3pdR8h1rVz0u +xdp%Nvq=EZF!7g{Gepk`fe!VGbts3atiGUl`v%uxL}BIg0AEx8RJebGXiabySZuB@kB|IBSKJ|p5A3kLZpl# +>;LH$GioSoo!=+^ZNS8ccc10B+a1_1)YRj)w_H`RoQC*jT@jJv)(UUQa)QJVOmF*r(PTt +iHGV+%lBRXh*4eUk+Nj+XXmY8kh!DBo9qoKwbq?|j!^!q;eq|@u28BT!TPi1sIY-U*jBJZkis|o{_CT +TRm@dE|}#f*$yOxp*fl`;5>ZeTtR(!8yYg_&4l?QI=c(JT6Ct~mjM~S%WI$c5<83gjgl5_E*TuXY?`Kft7gVDLkqM;?dglFyh&g2n;19nx`X^k +Srb_L&z;jumv%9<{z!NaOyLyNxnJzZu<7(#h08QX_lsPES2*B +Pts&sCiV{PfDyPnnq2)!YS$hO^L +4tDVsn5(X~ObY6^WdKIN0^_0rlPFvs9UNZifKY9d52hGV?+>g*26dc>0oAP!kk9aoX`l +EB^zzD`?B_y+$pr&U8s+;3IA~fG`(J+fr?1*?>LC?n{A7Z5#@BH6Z9w}DB*3r-MPqQ+cqoFkY;{C1D3 +d78Qa7KhKVve+?K0Av$QZ&j@=Oi4;zWc}{FDNyZi^;slUQ=YjJuFwij-GV6-_xyIB_h*DN6CLOja2Wc^hePEYoLJ6B6^oDng!)m9@3diq#K!Y +Jwcp_1{Xw?cHBlX_nxI7(^QtS5(vE#RNq0TSxDQVQ+!Jm2vH2vu(4yBR`!^zSulT3MK+iU1Nib#)HOW +A(@ME+ui>#Oz>(!1CsyY`JfAH0pB#Sv6e&K3{*-}5FgyX(t5oCFE!8nbjnj&bMgfh)`3fA;cU+A?gvA +XTDoJ4A)-)tw41#lmkM~iQawSleAgf7hTc82fD?CC&!j;-n2WYhE)#AtpR`#p(h6=aT{*g&%Oi8qOr3 +QT{MZheVI}%81c?PDPqK4^PLE0jyKV>&aBeTqb1;N+_0$JNqdVRD$U{+QZh%qHfz=IdMsF#4YZk*LaO +>m;-XT@fS>9i=PRb4CtM-O#oh<|dms2Ms@qnz0}Ks&8*U3LN#1IG1mXa|b(G>@k&KY^pWdhyv6&!x7h +1Q^ZzFGF#X%G$t$mL`j0OCQiqS;VMy>)Cg8Q6kq|rb^GDKr97#JS`$e;{At#5)&OVto73UM8v;so0uX8+>S9VF^8In%d)u6l7&1u +J@oeLXU!Uj274H^%OQVmy@&oCl+mrbF&S2yRdtZXIP(({a9 +jSjO0hfXt*n0V4X;j-(&d|p!Bce&--7Ce~lK)|0R-o7CLb}9_mq%H7B2XkKc2gev>-QeJAmc4)G{{@N +_KxD8;VHxjB%iJ@o|&A*G5pOAm(!1|7N9Rb=>uR+VgQAaG@Gfu>p$*ciF+ +@o<`(vi@q{S&7Gdq^x-m)i$*PDT}DlVKQ!ZnAkew6zENLlhA5xrIB7G6)+T+_tGF2208=YLU0VVGP+B +&s7K%@uClv-%Qmo0iHqC-@Jt&%W_&ac`kFWv@zRhMfGER#MZa}qyDHIRirVu8B^AV_85ZRT~O>oM+90 +lHtv6Fn)%hg0g5(xVF>^5USFvNQ?Y`zD9AJOb^^77KJgS0`psKm+WESD$0)3652G2BFf_1N&r0Rf^%!N>KQN&G#*NIG!eYDMMQGhmjRij}S_ZCuI%r=0b7H +eT}>T@j+Zn73il!IO26L=edSuKZSa0@;D9dky4w^^f&LuVzL+pS7P2DW}PRu!yo@l3Z9bO66INof)~;bC5!hS26+~dngZMnrVpw~-;T@Qk`=r7q(>bfuoCd3;Tj-lb0tZ*T +1ZZ#tHgV4g}x|*pj^TjSJv}gTntiC52dw}jfY&4Dm_UgdN)X6FGWq$j{==l_uwR}SXx>l0c_l=X31OB +%{8eeI(QagZg`GKE2FbbT&y(IL>;RsxV7UBE=-)(=;Ln`8LIv+10l*=TX2$5Sw>AhEE?xM&A`z}POwZ +GoRrjEw^4Pg>i)5;wSdX#-ST$abW^1ZHs~GMg(lA+RO^IU7G~tDK#2&;rX`gf$Y9p9wRj>xU-!Sb-tE +YNOuouG$iw$fK(t6^rc-UGKLqa&K8$pn-jPGrRu~zPe +IS{SlK_VL1ihpRC>7bq>+r<4G;x1^yUR%+yMK98WR@@hg-8^x$@C-_$qm55#vK@>?KGfb9j!O(T_s{; +T>zdV>GWgx>(XR3tlv(3XptiWdVSMgb{e@t?VKg18o%D<%&Ee{9w-q(3;L}(@Z-1M=qf7Uqp3Y38uR$B7mPs&g|cRFeht@8P<$Ju)eZpxQwt$yxK6oH8Zr +58{G+#q$#p*HGy7E@uID|_D&vM^wrx*F<_-U;dU-WaC$aaP_JEtZrw3_$>x5$=9u>(eBzuI<;zmT>r& +SA$WHbnst$#KAvhcFDtwbHiu=Ueij7FkFF*{^(%=;=9P!3N4t*rGFzIRmaG@M_uG_@2)}%two0{LATC +WOZRkem%;jl{_Q*6A7R1#?qTI^XQG3k~?M4Og7mf-Fa3*;F-kF(R<&L;Jdr +x{rmUoiYMIZ34#0Ii*cMgD;AHzJxiBK_4rR;eE#`YPalh*{A#qbE51>crQiz~0|z6SSRmiMY$!-odq0 +QaAII>|pYWg0@t-efwJul772Y=cn!SE*3=hG8(E*#PNo&@JX+A5;CFV2mI0#r?+S87xl?;)?p3H20%a +tcgDxD6boUHz~F&#^w;%2c}O}7KsgUvL$Mh2?hu;i=n)8t{yH%!RSr=Wi6<3_ZME5exiCP&a^G4nak+ +mM=>lq~QLni5Y8;sT;tcI@8@xfY9BK@P1>n!#C;8{+UoI#bGpdooTO}xYx7zg4b|fzJ7D^{aCy@`SD^b{& +w`bTS!;=kZp!PlE)m1^DJ*%#1Gy62yD125r^a`vk3>c_U+;0yB0d&3SnL}Q#iJJP7Nr_euFImZlR;Zl +YdPIKho><3zmw&~;>{Q+bTa7PReSm@&zVYA~V +T+i35KY!RDJgLEubBk||S5DVvV$Ioxpw9=$U+5O+ZZHaPsB ++}_?jG@wXQtz#8(^^fxq&eEteC{unG?6>#893)FK?pfd8`-y4w_9)+!_EZQl+Xx=ZcSq5`Uci>_GBh3 + +8?R|Szu2ft-!zi_84x~0IdxyGgcU0vyg-T&Ms+$yW-_ZQf8o8qo)?&e}H7=vg$dv0SuAdW1oPy^%I?S +9APdBhYZq0UBVAzi}V@tC4jor@`ns&b@&X$+S9&v+Sv@Di!(@#YaO@&0$A)q&W^O+vm@B|yZFu +j7e^Z@XZ89mSgkJYZJI3ct2!Z8%5b9g{knNTuI9qS#_tw83UoSxjt5qkM|sJl*()*WcKlr&Lmo7IO4u +Z1SttpR#QR_;U|@X_-rm) +NM4quavq0RMIkSr6aM0V3z0Up6FiE!Vrhg)l0f4#cJd^2q?_)qgQuT_D3=atF|L}$lD7r;$nk&**X*NAT+22QLFaT(%Zkaw#|zby@N(?BecYW|a=hGspDi +f|Z0Pr+Tf;KpW}fZa%(w+ej)}!hm0K6>8&xf-PaoWSn^xzp-Yuuttt9S(LS3iVm^T>c*+y4cFRUZx51 +0{3tb!}O;U!yO3J7KBx&-M$7e{4kO|Xloyd#<5i%^60ySb`9OZDpu8G^gZaePHO`+lrqg!Vu$a?v@gO +gBRefJskc`FAM>;nLf1M7ck7i2p_tMfRi +kuO3*Z;WR8ykBocT$R-F_brR>kgZ0imb>sfmhjz;V+ac&Kr0Y78;=PwHFrc`{?A$(vxPA=EZ_|WPj}@wed*C)IIPp?K|<1&f5+^y6O7!4ywiu51LpHt$vpZB2x +2Ub7Ey}kZlh82(%oTWV`%GSNV;5YvQr%qjG&`ULaDL+K_sWP~gh!nR{1A;%1ig(vDa0 +Q&DtHc$pm+RkBh}JD$@$HF9i^R{noSR^j-(57O3#n*xEhbCiB;JZ@o>d3-lEb+~t*EHai7f=h#?i{Wl +|L^2Wc>WP%@=6ud=as4w)_*{791cuCCrRUN{*l+Tm3lvkI3N)@h$-YPpr^%{6?g>J`5jpCp$IvFuM64 +aNY8DP3fJy$C^srRV@mR(UJc8&fxd{yp6)gOrc?Y!UjyZxfhqV7N`%K- +eiqJ#z?At1a+vF7bRViq%g9J(z4>_1}i%GjzN8YS5zhZ`s#+VMWp-ESXM}VL}}pZ^OIK>r!P)V-neg? +y^Qw%F}=cnpX`4%z1sVOeD{+1J|$yN>-EqJ0MMx +9eGvn$Bq<%YXDqo`=U5-t#`n0W&!T_bxM+G>e?E*iaL^S++}%ekNk<-B8%1Tcr>fQUbfS3+r!l8u&X{>P +j`V@$0{`seIt2 +q`S*1q%&=x;zkhG-nr&b_u`@|L}h(K!xQgHP;^frKOWJYbvFIS20vb64a~;eApW&|E>NO-UqpqYhI~R +pl5$-`j?>^@pL%tVSbyC4HjDlKZvVsoe;WR;$(=d8@88Yz@crX?z74B>4<2l$|5mi`rMrjbuJT4i1GH +>wls9cwnrd4${8+6`wZQ+Qwg0(SE&kanH;vy-_7B$a+-mz@!Ru|=^xvEZTP#q5AJon$?h>Wv|0QdbAp +L%e^#2paISsd7Jj`7;TwMQxy$jZ9t#eL6i9EKfl3a8lZB;DjO5S;s>BN_Pm8t%6eD>;ld~fROXBQVIZ +(a%Kt-pT{{`c!YFH3;??rV%WuRa?cJ${To@>#8~!@bcT%u|g&oV|J83k)x&{^{Yf5&UoL0Y5+MAO5G% +-{(X>6;;;f0fdyq4ll3{o$Qrz9(G2iEngZPycVS)E4hWLhVZ0~Kh_TnvtmAa%!ZW+^i!M&ZfE +VfmD+syWpa8b9DVH@k=x-s6S} +o|?j49Q;z3(JaBYme5@fgi3dIlzMZ@{0&7TmyPeb0g&bAa(`TFFZG5k1OaLs)1q}TE3(iPd~+X2tx(^ +|5ksMUDk=bC11eSR-Ah@hMP!;BnbX8h9e-odf6Hq3o#$_JN*5Yw#7E@-*z0j+{G~AxZ~X6afrqq%kw> +gz+i!xFeCrrU;ghRw^W7!ry;{U$g4=n_TRQm2zY;ac43pbSF_Uur3mYd8Z$caYHe5!lFtZH%M%*^zM= +fGJc5dOgzJ0rAA6njm#0O)S^&{dRQwG|uA8b8c)Zbd=ZT{hl{y;68=%h6QdgnU{vXiVJ{M(D>>12gZ +7su|7{}x);`Yt^;wF5$X#nyYtG0qBmH#r~#a?qkzw9rvI-u*Db&?uuL0Cc@VD9)v~Mtd6g;zfE_h~qP +=H=?eLeG7L_1f4l^Uqp9_i}jA2T+zn1wB(5G&hlP!w^dJNrwWxFpV(s}bZf6eY_`&Mx9f1lFt-m^Cx_ +RMD`otCe_T1dMr42TubysaH_6dI2TqFo_DOVc;0S|Wg5?G!_^0ia6F*A}(SuRHCW~7G6;myew-pECq% +DX1dFWSlt(zs$bi-KMG+_|FnkEBb-Diz+uWoh$wD@xmS}tnJ!`IO#Kj}A0N&S(%CteGQv*Y;qzc3vCDk)ez@Ysal6%}7zJF2Fnh}N6fw{@DO^{TyMT)sg@6%Mc+#R>s3qa6wHDxVEHyzb +L_mf-&@6aWAK2mm&gW=T2Rqf+V8x!l5<`B_-tpBuM`&rkwXa)2rvLBiMx0I`}Jeq50G-4y +}kMlwHu4TOwUYDPfvGGch6yVd~}@6n?+e)on)JSdHhFwb8vWYm_2LO+qS&A?z7RearVV$pMP--|M@z5 +e=V{%+y1(#vvo@$Br?yR&J3-)BX=$ez7^_5SUPKY#!J_1ky&63QJ +sdi3bc*_-UkfBHHrSL;fwMBOtG_;PTtY@1a!n=Lo}rWLapmTB5P+tej=Sj?)j7j02>2M6-QWzmVR|Db ++hnR#b^)xEgytMXF4xh}eE>u1$mT>%o*&qmi=H(hzZF8XWrqTA|ke=XPim+b6R_3?SxVOwYSbFsz&O| +n*W&8D4;PL`ZED*&p>zw29Q{Kaee@m91Q)KXusL_h21*MOf%_I=%L*7#N|{=%is+O}zB#g*s_n1@2ud +?|lVvX^J?pFV&3{^{(S7vG(|diwHglKt>+XJ_Bdf)5hZrY|c6X0$HaPRv^I%cg8;nkL!2fF3Po>$X{o +w%<-NE>jmPF@p)8$uUe0vhZm|v6zW_gxyWDyB22B{CxKAFK^+yXz9-%@MAkZI5?QiimC!KIL*#;#BW< +(ZVt{ +c{dHweNJB?u|pRczI0C+4%J^i_Z1`nRSe);n0tLM>@Krk!7t15c%{KdQXRPG%V8s#ruy?g)kyYJ54=F +z#%-<~~t{q}iIfBoO@&)&U1d!GAq1E1c#{{HQ=vv*L=?=;kW_is<%LbWkB{^Hd)uV-gJzQ;aJsf#6G5 +PEhnuZphAX3vm9M$P5VV&0EWs4ZOA`0vxKqZQ9ol&y;O8nBlk#yVmb24IG3ugm%-TUayDIp7vz35=qw +%YHT+b)s6z=Ik=~ynqsAQI(y5MzRu#p`ME=vNT{~WtY`Wy8`;yW=$=!Wz%K?`j`1rKaB#%cBeQ3K*-< +z(|wI&h`hcMHLx&P%JA(QU}fS!4`*J9q8%E`Gc1tx*Aj;lfY|ql#Ii?Zm3^0$JlqV1*^3>Wo^pfZu;1 +}716?l`3+niUW-QVDr;9~aI8%zf*26KqJpsN_tf=G(?LB@SXf8gsa!F+w`E>)#wlCBp?OY}^#$iILDXW?YDQ*bvXSwlM=^@BkoF;?QLm~S&e +2kt1{6N`-c&AM+Ic&7&`#_oUvGN7p=GN7@;^lv&CLxC8BbuCfW0&bhO6x}p?v81W*)?!{ROR(Nw;O1;zb-q2j=Qp|U?*s9h;<+vYhjFSEwK=9Sw8MO!+7ol0E2%)&;oXavJFkT6qu +3}uLgm0>(aR7L29H?1{Hposexk$p#+XQQ36l{1*~5OUO{H|r)p;y$39Ca!$s=ivLenC=?x1?@Xbg~qg +*ak+`0(axFGPm1JCESa`GZATTr?vlu345R2zFG#rsdC7@Ge{309-9qmxLpV{hx=uRAx8j#zF9!f^{r* +XO;#PQg&)JA#=%{oTUTwiMN3=1}=i=l&lSx1|7BO;2D^O#%Ff-XuAN4dyWWL1eW6gaW64-py}tjogX+ +RzRl(Ol||TqGj`}s8BQoPJSuo1@Hk_aTY8p{9RdZ?r|0MV%23MF}<4dhv(w5Eb1rUUvBDt12fyguf7{ +2f=m~RYIzDGM0Z!hjM$R)INk_os9gy>V +1}f_A~fho`zw4OqEHcON}be@akOD`@owRx0jT{&Dbv%Ro3dssPr_zG#Otwc6e? +E`bHyL`w(|j?#7YTt`dbWLj1TV3B}|`f9{Iniky*n3*V6qwyGbeg3f)QBHQ8>~RPBACq^y5)%9r#r&Z{#PNao-VtrjND!74%#@$1KN50T>;a~DN?S)zMO4 +AMLUAIptVTKRB&@MMpy}WtF!?yKGJk92HgZe#kju!iB^}n)cFP3s<^^v&v|f<~cycKWVBM@Y6>0)nSt +H`sFj!#iuZtcxJpcluj_=OUFC|uzjBZI7TD^1%vuqfjU=ISxAt4l?58Wz^P69m%whJntw$iBZ5}9%UU +Uo_wAeCp5MJ-MVaJ)NE2r&@L*4M_BNP=;26~KFUae6CmMsM3BIQ;S+WS#9lHvl&uk?VYZ +%~WCE9XsqlYj74Fa?(l!Npm5o_t){dO&6|2r~|$HpgdFgQeoCx$Z3-mMF?!za4}4~YLL(k~h`NaMu75 +|-15gH4Qe5adYEVF1A#>jsMMTA&FWk)+VM0!_7C4*Qlxdjqh*(+7zR`(c+?C1k@J0OhxI+HRP1v@8O6h6 +_W$dZaD(-d4#F^_9EMr +5-{>phw#mz#Pn%T!xM?NoYMwlFGCn1R`_j7C<}y2(~eD|oZAcOn`ma#?Y|1}-5M%Cve-XAYf$adCl00 +@%*r6}N}R)PUfJiF`6h(E+9bF{;@p{^Tf6$$k;#UR84^Y=hQszADt&#EsZyr`(A+1?j#AXA$ag_0^AC +TR2{+-rGwn-YwlFzbJ9`59gn`2898oEYc>eto_^7#lyDczQeW5@>|P|BDDtf&P2x}se?q~*TCN!C``h +EySKn*jFt&$-gCdn4oF$mY}2ru3QKA&bxBxNWzUBTmx4|w7=G0YJ^p=yw-NwqlRBB~Zl3L~k>(;B&h118Hkq1zIB2c;wFsQ`Td0SQHTlA!r~5q}a;=+~RGH^ +*Q8;Va-9d&!-Hf|N}k(7^nfY^@H5JeY*`w-@vmEIi~XUD1Y2#qsQGi&mLzZS66cNM=68;1 +t*jIMk1@Mz~gb>fn}7JHIP6l*KA`=+v9cu|A(gcG@}F^bZpoTHw`5~kCmzwBKhM~E$&cqSd-~e77s_g +o^h|%=(j=#VKHZx(K>1pRv7Vfy^XGToHJ9-}dEvQx&ZS9`I@Xg^ +%9VFPxE16z%+4AF<$>yI+}kDeM*I5T3Ur)eq8siPJM>l0ij@jb_AJ7EH9Oo%~g0< +bFWC_tfW$R#g+t{)uuylOgxcAlZZYLfS*JZc}GMn|HQ*wX=lS8!1fMZ*v#4WRCSjAxZIQ=iT5S2@P$C +198u4=+FQvU*E>NjQ)rna8!onUQ#W_yUUVs#SPKSti~utW;0SGl1O{iGyO$Nq-r#{;TE|}RP(l%%?LQ +?y1CpDj5@aiMWFLiHT*?<0+KUfVEqxe-JP~M+KuK33=wB@@S9eXjux5$*>inj-5-=CGZ_(uzrOejuC( +a}ap-wsSx-qC2Pxa^`9!IK^4|C1)d5MC;j7WRlSY{J-9CiVn=;lD3Y&UI&T<-)Y9@X^Wb%debPS^qbywm}kda$(TXv0Ql%o1dX0+P#1z{>zHFGi~d6Fl6Ta;I#3-n<6 +B<}mR=;SAUe~6xSCHr(`OHrT~c4z3;tuIeDZ2*V1_X3C-?F|qe>Psz2Xl~D7u~kj6m~Gms3w#@_&Ufr +ZNuT~zxyWdelbb6588Q_jFP;3_=JujvgaxqwgBX0%unUM5nSb}$Gre= +?Dpx3H|Atgo_NTdVfe43%h9RSn5L`EN7SH-q7X9_3`YOSP3nE>YO8W>2zuSVH)ZM{R2`NW~vacU?^Rv +#Wh#0}DN6P9flRT+8Lz}!h=_lW`gh{iusoqZ&=y2QBGl_gv13D;VOCRp@|-U~OX2AW8ek193d={XfS3 +9xHv7s!|N*>i2Pob{FP2(M;E-`g_&YT=JYe{v76zm?v_Hdx- +S}m;3go~+%0@Gj&1Z0vir#iK`*52p$%5gw(t8tPx+fA(+59rfz3k-Uh+g0;q1BkSbZNaIVZi3~Xk8H! +OoNfdJlm27daO$R;Scuz?ZNaW;`+l8CNF*eFKi8Xg(()AjaIdTD9|mNCmJ=Gw#16Hqs607&asB819?eVG0DJk{r!htj_0Een%Vl|w5=?gfxch+ei&x$(sPM2!SIz@r@n38ULng +(e$K9WXB&3OiXuGq`Kypx8C26)PjxB`d*pB>IvgF&5REc1u4>)|VraNPF=BXlfj$GW*z|&8i`lw*S16@Ri3((iMN&b<3`L+p4GSR|M4_*Y +d83pF=cPR&W!Xzc$BrUSiK-KHgeVEdGy53}kW0rSWm-~E-O^u%9guws81~s5k?k@YO=OfA%J4%6vkx^ +RJ*{_Gk)+DZwj`dv^e*jaos2>{x7Bf_w8}3rfTPqsO;Ig8GQiF=@YT`=h!}BP=Ij_bo>N!$TVMH&HES0UMtiX7;GiLs+-nvkcXWpcpP7KL+N2PErTl%B8r3RvMXqAt~}&PCe7??7l!)kG{w6#c5!=?)h_wHQ+HR1B-~&oEtEpvT3ktXXrr6dJ{o?B(;XcEICkR0c;Rs0c0)Iyxo?MZCQvu_^ +nw$nM~Z75AXH%*!5Qmxm&B*~^8G1R1PyhXDZ?#6x&14-tg{BpZr=TQ(J%;)xFP)7;m)U7g#Li3~EsQ$ +D?=5l`@%-?y$@7*ilaS8<||x}tR`UTHAO)~42({4!3!eB7OCN#EwUBeVxd5jC2#1Y?7?r6LUDK-6EeOmi(xImhjzQfKf2xx7EH3 +{U|AT26W_?>AA{-ddF&PGS>qlWzOp}b{G@m2!v(|y2SMHn=MuaAGa(y&8d7@4xUMyn}o#`&v!|c7lAs +0Y`$27@5TnkZUpH08`Qthw4;bg!u$!|RoA-by%GRwoSZ$DQ}hta}AP{>ioIJJ?V&SNPL;Q_cA6_eF&ExmdsX^an6!VsVAiVDE~5})>1e^F$eK6ghuPEX?d +Syr)SWeN3715lwzgS=~TukBMdoKV>rF#SMK{3Qn;ep&qgZKmZ8I6#~7%#&WSeSB9a|YC7$eAOW#ALa! +BT%jQm2R@sp4DQJBH`vXX2p%1~N9L~(AWtDj~K=Z~4H08NXa_pV!9cC^I_|0kRSWTAnf}hG)*0ptup{{#Z!$rCd7uDniYf#q+m-x^14wVgmIp_UU<2 +I7O%u0++4xEN9GSOG7~bW+Xi_kab{fB((u0#*EYwu6RY_VfmEm#<0*H*jaH7I~?W|T&uk_z=R{vY3@Y +jo&x`XbF@@}$=3Y967)dXJLRGaW|e0yN*S6kq&=A{d@Ow=rF@e!?m=XdglEWSKWbSfhi1Hb{r>EPjr&jEykK9FYushEutiCGttD=;eb^hD +3ay=qs19R`xq@!gxN;> +xv0J)SDO&%I0;V+8B&9Es(JXs(s1O+|SpoWgZ0z(97Z)R=b4mG4>P?h-pekz-Zn +mA9bsz*0?JUnU?IES>cgGs1C+~8MNqirPp@`*HU{u=J+iqv=rXEa8N}EjQV-A6;!!mPR+F@im4*Rka# +*RA8p4LW%6!*03u6$^8wuAX$@VEje3&+um+QO~0r>g@KOj@i?T-dq`Z|-`eDRi +8ffL%GSQ{r1AKCCI#VWlHBl?v!n5HHgyKfXdKs76RnXKsK7+Y`Wm<|R0ZIVgC4zoo=+T(iDv&xB!ofo +1uQXGHzPhUrClT!*OXE;>~YaTMOfuvEg&SPR~YG5#P_#u)I(!ni>AomW1d#gx<&c~N)(n +&_+usNC5)+SLTKSKE^BV`XKF^6QM3f0#$Vydddme0sc!IngQwB2b#W2b~Voki8+ +;dTmE_QsOd22~uB^FZ6TXk&b_g%rM9C%GCqh)1TSv6j +Mj4R~BKq#y&$;oW`7`D=$?<qI+D3p2TsfaWlYZX;2~t~Wdz$nSV7OPYBTqoNfuk@RfAi?mFmG +vtxfN%GSiiDp+xd>jW3E-d}>0mvl#Jn+speHltC8*!8LpY&Fo1}o7+r!m1+EO+9#&xnU18_@4g_rerD +=~*Q1=B{0Bk<5QG;v*hih|MD7$I{bw(Nr@nLP#-<}5x~!5sN|16yl(iCla +QN~8P}O-gI#?boCk)1PQH&1psC6z7P^3M~&M%D>RGpi-@ynz+Bt%oW;JXe%i!TiDXdU>8`~*-+gVH?( +u2T?TfTP2E$jN0Nn+PH0n*`=*A4;o=!ZtDA`Tj3VVZLHccpt}k?f%`vK@fU~O&1!;|^*^AnNg;6JJ6S +Po}(G45a={pLkpU>UB@!*x6`*TeBqb*mk7%SNkF#YaM&6-hwoa*o*jfttl}bt0?lG9Nh`{O0mH`&`>;&U{IU}aRFN1lc>qb}#ZdA`tQb8`m2XyzO35bSWH6U+mAa^a6I^ln$mzkL +Y{iKFsxo9qd|9YC3`8*R7Y9VF%_ARleZ(aqVWUE7JCjfY$uFqQB(|Hy?nU=6WXlo2w +-|fdf&=&xj|XGlC@XS2Ic4BGDq1R(X=nLh6WQZ7m+5Zn`&L5U#j%pq9x}$Uf}@fULeOMM6>84G-vF4R2-FpJ(Ap3*F29szShTr96uI>Q^m;B2F2 +GeW9ANn6M5Cx6_sTNJzP7AhtE)StWEzMv7MaEC)^YH;6^_Zo6GKqwtM5)2$B&wNz>q-n7o);wE(sE$S +_CiH*k)a_lw>40C61#8gd*s@6&HbcoOOdO~(c1KUhDBB_*jujZf@Fc&uIF=d4g`9T#tZXpSDd`wZH($ +B(*gvPi027xE*JT&fBYAYuhz_k9WYkIn(r1Qgk8LExG=RbhOR|ZFbJ-S7q!x$8Ff!c${ow$DL$+X@z=#oswDkjr<>{ke_mY;&>*p5G9*9KmOt*;O%~WQs32T^ +6P*8Vegca(YeZ9mV`%kNFl`YE=ARtJfG~J8RuBJE$sVjD&k*hZ3>4{BY?IkZue4z2h{&V7_rajQesN% +fYaf6pZ0u{RZZvk(vE1;`5;jdgP!)%1S(xg6hqZfl5uum%&o1;&5l=QcAHE4`oLYMrmnVWk9vPAr!iN +0o`?G!urjki{va87)5<^*R5dHbLMT@2?`hq%&mhd0L(qIc>`FX?0sfLyN7h9vR3vrNO7t|yise+1;1- +SZ1=iPnzdm{L1T+>HHeGi;ZQ83RAR~(wt?5rt4#t3*>X4HqPE~|B0Z~5?Z{BAWxD?54zE9ZF?uaE5(d ++KZv_4ee5`j}!u0AkuNvlD87Bx|U-sRGA+adg3lc25qUJBEni3^^x#apHk0!K|;T)g@BZ;$bI2pEo%l +IXBQ$wkqeij?($CX?>ct_+<~{=m7LZ_?|$&(nXTph;7}@kS;8LSRJv>`q>6hOL#vZ6KyKoGu0$) +yB(Tg_{V{A;y|e{?^&Doegbt)d%kQOFV(xSti0>)>Yr5?7*L`DiXqYZ$O^lB27)1?5SkVJwhIHJC##U +4dQkl4dvkb}xXlIM+W(37c7mAPOfA)R9Dg!AB64KvT0h;#ry-XGDz&S$LM<Q>`@_U%9}mx<$a=?NWRKI#wmFoV%VPZmPu|;Bq{0$?m6#UG)B7@sW6paY%8G2rP)eGi4eS +#U2Qo3r5off(#z$S*zv|E<1h-owR +*fCFf3Q6WXUv-nSWeYD66J;_!Pqa(o7wOf2!_^4_tsBdP8Z_C4wo84pD*^>~fmOkQ$7*>l^!YLtP`(@@AKlyMZ-b5I! +wGAvX1(8We+VU`xWBW6CLQT&5O%>Si>T}sB!=2;CNmW#W78e$D1t9C;c$(0E2i~!6ci({~qLrDw| +T~%0Zt|e1`Os{e4G0qI#JBXu>n^Q$6mpdTi%^USM!DGI@=(z;^N#zed?XuH;Z`OK#$Wn~xLw5MWL;TllV +@<->b{}I6K5Gjhm@JdTniPh}IFZT^@o4(w5#Juk7XXogLtejfDf&B3KI&w9NkA$ndy?hR>Et1e*Ge#% +fqSSz`%HZ-_lsVhc9Q>7A|Zxsbp7DCEA=G#rA7pu5Z$3Hx8$3s+Gcab-U&<4f%d_J6paVEB7F=sqn$| +Z0b8M5b>qO=;nZ-*nA5S*k;Klh{?vKyL^}-(x)c674y_M+jT~(q`abNi*JAU@GqAnRdX2k`!T`A&9;s +jCt#WaJn;)jmq#o<^l(M@6G}pI9-J!Q7^_=rpz(6Y3Nn@J5)^s=MiUWGaos^8oHkCrZb0f1JD><^5Va +m(LB3s~o=iZ-$#dkO5TAtzQcb|xD?_k*vu&tBl@bpQ-Wmpcu&4zA2yTmjEkO)BhL|X-M%{|ZQtvZ@k2 +Dz#{*iV)j4tg;Vu>Zf>H6Wsl{zEzj)Z&g9@r)e=PUAie2aUX8To;Rs&s^)M@8|orE!NlZn;qXO2SWEo +zw8RDXsN-;_AdD)rH?ih*cA#sUzcl+j4?^r3e<#)#m~hYi_UP{0j@-9^r~1hI|;7QHi9?E?s7V-;!;# +7x67n+Y@UPy^j+pzE<5QqrOgjYZ4`?u(nAT1a-_Jppq~JgE_4j8chOf;Pbg|_0~{X{7%Ojz@ico{bbBn0UtGwFI7E|zPxeQL3 +}{*yq66o=jB4EB^aIZ%aQ01b*kiu?(j#3(`xaxdygK~swJyzi5jUJn%S=Y(vq?;6JCdOJEpi9F{mPZN +p2}eGBfH3v^5LPSY6~%(xZNsxqCH&kE#3{-eKAF5Mfo4%xyA=MG?4lb#0Xcqu*Wlm1M +NLwg2d1)cf8^&{uuev)k^tBEA)$GIqy>+R^Crp0}?J@OJ8X?RD}%26OFR;5F~zoRe7IMxz9DUHJ%{I53D +qO}nj<7fNwyKrFtOQSDuxwlRA;x-WGaETXp;HVxD4{Ize2PJThNl<=vc@w(0}{v^=&U;Z+$E4VZAsove5*BR!L)VQ +h-x-HCZhrV$ewVfztmGVe#{oi^b&}0b8j6iN^_H{)c_0iPD#|a82Hfb>JlCzON#S)faj$^DhM*a0O(s-0D!5vF%`RK1|UCRgE>Eqb1bQAtLh9-|q?OzR#Ms3-K{#>=J&Lps@sJLyOY#6-I!`ik@n<73V8`3NtRA2Z*Y;5{ETf`I +j*^fEno&nMr}2wsA8!^cZZ(R}cj-gwR(zvP7y(9Ol1)E~F`=n&x8jp9oWWh>(8@ +VS~GQPOj?@IU|DUY~9wkI%q;&ocEJ>U!5Z^VrHOBFlgh9_09+!(Z9QUarh8Cz2#E4?vmwsrDH?bwbVp +|EPSV<_ln5`Tc9B$}}Dp-QpIR?dBsf#_CPyL%AeT_dRIAbKskbrCzG@-#SB7`w(-Wa4B^L1Qi@*`QnH +5mn?wqn-PR4x}Mpow7*Bu**$ZEi5I3&f81)5736bhTe{5^u!iBzJWLSz~ssju0!l=RXcHiIWKY(Qn%m +zA^#>KEkSDFUIAhk3za#xU+n3Spx7o2wTg}(0*41`*h*dB&d}Kr^e3J%;XbQq4x>$-2h#v~d5)_+?Sn*>~-Ac;OHFg?aa!NKz; +Gh((+=_EPVMZLF_c7?`3BH?D?qin5;eIRr8Z^W;mMf +Y9ceR?6p$=45|ub|w*0-edsFhnJ6p!E-PNTa-x$?C-@u7F+?|j)BKi6Vxm&3nS7uOAlB&;q6EOs#41= +6Qh32U4?2IAEr7Vb}j;QZyxA)~QEq0XOu>_}gR9&GS1w;zk@2-hQ0%t)#aB +h>8ID}@!+5=#GGhH{f!wz&uo3h+ZrQ6IY4l&l74}n#UN~`G+5w9F-Tgkal*r11c^w}6kCpAWzYd$g*> +j^m#^n6ta3Ixy-P9BNJ(dggSNXH0$)5Y3aL2^@E{2dmMY6_3l|9Aa-qV^7?v`l_5}+#sPXmv1R@6fg3-ZYq^tPJLnwt`>G&neMgxrjvlcKkA +j0y~C0$;e+Xk`U?YdQq9}=v=ztE3XuI@P)h>@6aWAK2mm&gW=VrM;w>>1003Q5000~S003}la4%nWWo +~3|axY|Qb98KJVlQcKWMz0RaCz-KYmeNvwcqzw@Y*$`NoM6o+Msvay@2a%ngtxkSg-qlYs_dQ&J42}N +tdE_J-z6E?|G0C^_rd7#zh)LFuWRxJUl$_b4co;IQ`;OBt@$7&6%jp`the!-uYb6DgAbwIiQ1KgHewrB+f1$8&#c&NU<&SMQMt +QnTN{-%zv@+~i$qq6G=fNQOb9n40{7>OcmyK8!IB0nUuG~$vTUT9rtuTxs@cKgLt*A +r?Jxu@T#%D@CJ2p~|%zD|l=85`Fq{O0l~SAiT>Mj&i&R0+H&Wk9{aP0v_9rJu +d*JQ4V?wl%<|RD~7mGaJ$;D!Ja`Mf^x6j|cyk1AD8=5MI}j2ROk);4w~jy7tdd +QkInhG-0{JVsr%>2cFtybxlj2U9EeP +=I%eg1Y1j-I3Xtbyqg>F_P;d&1ku7cC%y53$^3;1WglRz+H^nylQK!;apeD(LmZvuvp%C%U)OJx>|u# +(w&j{G`*Rpio6$)6Tpm(W(lnW`ix2~4Ciah}NNq-k&l+>Un$<_zc{#oMcwqFB?k2#H8su0>veI+QX|Y +b8^jGqziUULqBQsz!yW26c}{(L&rK7!yc={{x&3%e(DRBNku_)@oC0vJl~{Z2@Ap18L2r$%>5j9S}1hzs??8|nvtc@QFl%0)=x7|g9$1|I40(lJuIud-pF@>^g;iXv8 +23T)c`OgyRr@kk8Op(mwP*2R`}8D@Z-?l!8bYys+poEdMhDK}Hk7uy16HTF`M399mkeg7>||194dGQGDY%Ge9AbAPr&!A_=da&9N`upnwA1fC+gI3LvusI)b4@p> +ve!iXFbGm_Yyx`GYX~?7^$C-~CG`FyYqlN5J>wW|72M7QO><0<8sFSHRBTJ(|R{sLeS}dcv4aU(i=-O +?_vheL)}*nRD@E98&_)@^@ST@mhiU+zj4Y-}J*9&oA{aq_Sssz)~;Ju<8Vqakm4RBt4oiJb#vk>;zgg +^b?h^orp~;H&Vw5F|;wJqNC$gYdOxeG_}sp2%rTsZdcf~x*@?qLSW(fPzolLCtQQ}h=A*XI9d$!jR02{6;N(lq^ESRv3w>t0-paV +?iF$YwM;39a^W+h*uTg%HzfB4YWQiUXl2FQHxz&VF(S4D`1i@8^YHMUrc;CSjjbNA=*&Xc7vj}lMpba +UKH|t6RUjgNdPpeZL%;Tu+uSxHP~9F5W_*>Q+bU2+)}ovfECgSP)BU$UCHoxG(_+Ki(X)3^piuncj-; ++SxK2AkLL8A!;rYOb<%|*=vyF^8K)w=>nZ?n0wVwlgF4b~UmO?wG~f`m1_X)LiUi9O{Spj>FMU^bR}h2^ee`!_%pc*=1*s6Y(qZaiuGxiw@Vspo7UFtT|^U9 +mPv42^D83cBJz4x@Yb=1e>nXO!riEx)(VmQ7ZGXhLoQU_st883S)(fz+4|ZjhTcA`*GMTLHr8-ksxb& +<0go9RTBKH2VUercsa`>^Q1`S!afbtNEx{UOy=U^t2NM%|a+~30WJ*lY|-*&lKajaJN;N6xX`$+4l^9IDP-vHBn{m5H&k@~?x98o;(-?$qPrxaX9}H^zI +~W=}0fzw(*Zh5_g4dBp#06P5#HR;!6`N$sb8Ds7&iP5;jbM;KZVe#X-K2Q$Cyr})UsMr_WAtO8^3Z_1 +xCbkMiuxHkwVjDCMG(bR;)T9F)KUm2lIjt&~cI;V9XmU=}$z!Rmy`Sm#oI4zjqvd^C33WV +D#>CjXH3anTTG&<-yAJ~-^%QIB{j@o11YV#EcEcQm)H4$fI{9?<CW^XIA-l} +0HFu?D))>i}{)AP0KUxw8|+dWa0W{3b9NKv^!iq={7@vO1p#N@~5Fur@b$vEHEj|Gy6GfDs7J{OIQO< +?D<2pcw!^)a+lrVQASpZ50@!cL-W>h}?tig%F4%8q4?oGeD^Otn9&{vN5Z(aG@vk2xXyojV;S)c>!wFKn44F)L&t@7`N*jAsNnJqbon)Q{C|xd-H;P&rfqaM4eFD^#&}f~88&Yi>ahT(g? +7Y|6(Tzd*oLSObtV>A*xjoQNoy0(^>e3>&zeRr$1zX4lD;xIT>S6@k^PB7b?~%BkR~(j7#^L7{~D~$O +_e_pY@6G~K%SIsvc%;#5gdbMfVkMiRwu(6jAcq|RUmFC;?%b*u0S=kFl0!2Y~p95s9|^93UVG)Sm#5- +y|;BhcvRFHg#0)w^_GwX_0tkdj;-x!cOd*M%9)-?WV((R#R;S8>)<^Q{)5e`6A2y^?>ZA-N#sN`ajuD +}>R>uOTsvmV3=vgYCm8?W$_Rp=3mJJR^)HA<5f)ffn80$m!XFDThcffyQ#+AHl6fXh9$+$d%NirWg*2 +8~_=^jt2gqrPNPG)}lMeTH5@8<0ux*}kSJYX002+u8Oo`MCWAy^JQ{18Dfh>UfVhf}QH2W%gHZsXyuo +L`wtQFWYsLTE#L90yF=KjaI4TP}9U1P4G+4OI^fBc$+=fyi)d~6{__I8E1x~{F@49mN=hyaNVvLBIe% +2=SV8L#coKA;9=PGnnhdrft&bT+Q!d*_w}$VKfkYc8r3BUMK8^ED?w)>AP8)idxfL`*k+2Ppbch~ZT__ +1$k}~(>2CXA_HF;>zSpKD4>W3j^wWNy7?}P0zrEbQB>IA|B!q6yW<@OGol4hXp$bJiV-_c}*Nwh +nvJkiSVD~%oRkFIvffj4RpYjd*Ky0bd3((0cj0Z-d{wpO~A6WR1EG7H1dxKF$g2*c~o%0zR=0H7ijQ{ +wkx-2`q8-nwt@DDKto9^B)~|uKMVwpS!yk~^IAX(>|&kPsPTh|;Z8l?XaGhj44e;YaP|!RsF&b*ICQ< +%hbdL_<}_nj3939&qJ}!r!Pn|QiqnLhZr6xFt+O^hZj}bs{ubWg+3WR*O(lh3f@ +!I8}OID0^RcZ*EQ&)*PwfC?Jln)6!){O#kN+&T99Vw&tOB2u^@k;VbOv#HD)v&zZ#5Rw87A|L=Eb$E! +=^{ut$>s2~6w7w-8s!aos;yUzmzs{F#e7Z|e(gwG>as99LcUdUrQu_^TX!xBN*C*}Fbrg`>YH;SQ-in +Tw}K#(+Glk6)j-XJx{kV`@!PTHNLRrHNW+KsyM8IE&_#-mXgExd&~wMR9Y;^0iIlgPcun8YpqTr**rTXFJh=*m(i8A8}JkrfxVtJ6qRza)!rofcjd=TL}plJmQW2dB+x@;-|63y`U +={<3UM#ER5>vxWOjNio41(gUZ(RXv&)60fDrp-7szQO{*mlPDJXkwV)RZ>Wz+G4}rCPZBQ1a$iN( +PQQtm>_V)0&LzC8nk`Kc0N3`ma<%8tu9zDXZ92djSBw4!s_#`H=|aS?M6pB6H<|G +jEQbfV#g@g6XHqlVx@RAJmh!76SR1B1F~0z1JrQDa~H$fHEvOoP*5! +=XV~WkqsRsefWJ^!um({cNO6P47;hj+D`2jEA0#!_4d5=u6On2ez(q3hdvQ?E_S7i|qK}V~c~zO=#P_ +d+@@-c*!u{52uD9P-|gE0k`i%hxEK9$(#lr0-ib#(V4#`I~DdDh?B>=QI4q9^a1bjv)eoiV8oZ_0?5f +jjSmCDY#!WisJj&?1R27(Jj2TvS{M=2hEL8JC4rJcvsFd%;-&Y2@(97+Sn;+Z+1WMX^L&uXDrd@@Y!w> +Qp&}YY3m7YS!Ebt!`K|2xl%VkLKKf$q-ob?!Vx5~?Uijh8;{lOsoJW$o7x>r?jOGG3YY8K926VtG8+K +(zoK#kK)-nlj6aoxU-$98oD_cHAPn+iZV*u*g4}M!p|_;qHU;|&3*(}3K^@(q2_^Hiv_T(DDfsvRR-J +5?Q_-iH#&!o|e`coe`0o8lrwOh5P?3?|4*S!TT-AH%+h~fx>1iOoY^FNSyD)I^ +9ry+M&;{+m0|a)bSSt7ft;n4}cvL+Ab3V@gn^}L)?)X@%VB*l!?O@OEtjh?w_czZHQJ5!LpE&mr=6<6 +51cLmb!D*U4VF&lw5tJIG66^V_C)3S5`_sZ(d^AUBez#ST@|V#5q5qNFRSg2=6<-ZC*wvX)`0BAYbqD +|4AFOpDO&-+S_~a;RcPu6S9Y!xYX$o#Jf-ISWY(UqOh4y%nHRe~It&XUei9O~Hla8;Cb+WZa9U>|GP8 +ohQFE)kl*EhS>1KYUsDZZ}EQ45?kFMpr$gU(r~-uJym%OQhrfO+5W^JZw&PU07^zKWiVFLXB`B0K5cb +a6Xw0A4DXo%|b6O9KQH0000805+CpNzui4ueLG(07b_D03QGV0B~t=FJE?LZe(wAFJx(RbZlv2FKlmP +VRUbDb1ras?R{%^+eWhBcl`=P8ZSVHf^FroGn&Y`9>C;H&1@J7H0& +sKs2+?5b#@4r&Fbm^gm0V|&6kbdHRn{a3L)HIIzRS;0bEzkNmdviQbh55s2C8O@6AQCFnN?W|*qkRzm +?GF1n<|^s%cQ>Y4y#@-^JX&7ml-e4B5M%hKVf1f*sy|H!Qf%KaG!YLa4Cc_f%%*O_SH1x*I5OhUsmNi +=wMM+t7Mt~!UffwNm(^6>_H79!`}P=-CyI|Ed2+UqS=;;w^v!Fr{lly%Q(pE3FBryU1kRdxZz;Q&(zL +~0s6P}E}C#}C!>RdZ=SsV=Gm(W{(+)ZM(7Pw5`{lSZ*M;yoki!#@%-WOUoJi#g`-1Xch +kTZGC@sh4awBr!)9Jitmr$&!56EmV7=s_~y-b-%gO8JbUqG^5%cPeC9NVDEQ#2SuNiuYgm{WQLP8>qN +`@~SSI>Tg%HdVhtn1SU57ygt9 +x*2(NTS->m-hRk3C)qz7YA`cmHX7WkEHGwtVmeqBTRLG2g15Gyzn3kX}SDImc5}(BHpd-r+z&ay8!YQ +q?ux_j3#1g4d`)3Z!jNlO1Z;MWwgWc6Yllig^rr9jnAen1|I@#9L8Q!!(7)pIurfIp@02P9b3fMGjHn7xNs&iFtmT7plW@Uwoy4;QwW~?^LCSNZzcd}{&N>rD?gv)6%g<;l!zrmt}4TD4Z;nj1P?cfI(@jR~p@ws- +aYZuuqqcNhkev4JFvn{T76fUJ@ASdCb%0puWvOA=x^z5`lsC6S!;v6bmbV^M@F1Xfj0jyN(?7Md3m|G +F(KvP2-N*0K?`pAT+ip7F7XF$qA8?f%H2p18oC6e#Sd;`P`UPhyF;DQ$LS4o{TO%=&7VZN$ty-a4=gx +|PRhmVwv?UE79kiVI1S!caaXkwx7Tv3-2T=LM3cwhAO%O-=5Lihu!Yc=!;alw4?iTmPzx-U)?HKdJDR +#7=cX`w^-h&FLa#Ns8Fu7hLP*1(C8W+V;2&MeCBkiNRyRInVt89|uApP@rh7&l23FMh$TKp&^SoT$(A +7vysOuF6b*33>gdpgmOE4!mr!pn}=EjQ-wUEu{iT+sjP~l9pR#ozBCt%<7TB(3%8B2Rx7XH^|zzSNZH +JAZeuzw&f?$U12^1^=3L~&?k|j_$0EPRFivb-;7D-;z4Ut7^qm^`m+q}7ATDmC;l<6 +4|Q%oZBorZ%F%2(VLY!MJ!xQ`Qp4FoPxi>3%VG@cZ*3?U@#Xg5F=foQI`Hz-9X(;WV(W>+H_cXz-9&S +*+#9#e9V1C}Moyf7$x!n=6zF)jkGlUf911CvQ!fJ8fy9mMqIER^{*H@-qJe4axckeG8oS(0jape=P4; +fA4|27eRwr;&PDme+*ltFlJrZH97(FlLxrnCNZa#w{{dT~P$06;%9ONF)3NO(B*5{jJy8ET89D-3JW; +%r?Nhp#7K6ULHeN$`wfMfWHdhG4b8Y%W#=3lG!%AyzB#(GuEgciYyKr0+t>T+uF5=F)z0-pU2(_#?^= +?q_V(T{_9u!2gL=Xiv~+oGYyCaa!;*gCXp^x&^7>SR0R +Lr!0K&k92<~rED+lrl{#mZ?ismq;b>&E`h0FGRnZ99=nMoQm{U??m;xd*!;bS_uQUo8fN=R?k5VNiHH +k_F>Q^lm5Cx7UCM7EU8IjYRimNS>VeAQr@-#2NRuvjLgI0ZVWE1+0xB_lZQrYAGh5tszcEq7`8QPFN+ +fOMR#WoOtOgpZU8(6OyA$00TtSYNvUqc7ZTR{dY14%5(#_VI9t=7#p8ugn>)T0eA=0n(NK!brrUxSXF +jXFiSOEIW$u_v +vVw!;@PfB&qavTN!iF*iUhj3J&pc$>Xs+hp7g5);Y+Gu2;$;jJ~20e+Xm|1Vq+7R4&GCy2hs7+ +h1w(E_VId+=W$JE|xHw@8)||Kfa&*2-X!-@qD3B{JB+OOQ2?2!mh)YqegJh3 +^J5HDsfj58?JUO;D{sF2n{TFa3_$4eM!BvS%%c)Bu%18oZg3XlGRcN@o(bMAIUr;Eip1a+`zZKh21$p +-7ZS4<)k(PQA(VQ|S!a_`2j~Oi_NEWao%VY~!RN}<0{gVk2jwzY+Xt=^ +*xTHC8Y{patvnA@vsP^ZD33d=1l{m**7X~0#wWP8Z5g&b6A2l$uVX{KjO8sDXUN%zC$|@t>n^6XpVn4 +?G9dHFjX;k48t|z>tl{iRVnO&77;Ox4}<{5H%H2$>G?YxV4%0lK}(8e@8SUNlEqqI0@t+ypsFQX>L?` +>&AwK@ylR0bE$>j@j4&osyw_3uGPk~>sy&(0G +3)CwC7wXnJhzqI|CbT8n#5KZl*}DXZLpx-#9RxRZ9Q=~6M;7gA)hA6-*xWZyZa{OW17&gNL7?zRui(v +C_pilYWQ3>{aY0xMGyvjDR=$-@BFj~puVNKu +e>qhl$De4Kbooph{l0PZoA?n<_1mmaybM8D6wD#xBwuJ%+*;mlDKOoVAjvDqbX=qpI&<27xBNqdyDfO&M)>;@X0(8EC +qP)mPw#*7Mo5TLIL>cH0&k)q7<-g9hb#REoIUEOvGPQ>-O*vFkcSuWc2(xhb*H%Csvn9^}>t7ba9CS; +X-1`yBW+x+`<=t_ra)l8Z)IC3(j1IbV!B*-;UlBGz&U*3zC#xDA@>vCP_Z+n6UOo$JioeIp@)k`YF$j +27Biu1tEY4ipyS?%5)u$SlL53p{7QrDMKBZ0AXRHb=q~lJuy;?zk4L2|AAdy`LdcLyzmMj{@v;Jl(Ff*~J9`}7(S2tS-3Ke`~#$OFeUVpKjqg+eZbjyz&l_u4m&`GTNMg2yt@LJ`S@vh7l5^=sHd@y&h>O#;Pf}7_tL-mu@jyUTM17C +qXWa`Whdw=Dy(9-mLf&EnkMVR^fZ2UZor6@W +nqMP%R(~HrFSjY_$6rL4wSX>PB<5%k!G2H1$D2yY@b{iA%5fXQsROp(C!o0Wv!pxhTdc_Jta1Z5nd+U +)-Y42&;Z9RUHk(W?tvB9hQboV+-&5c%Ldm8KRhfZIia1S-GX&Cg6%66U6_-Mt}5m$sc?X!i^7~J%4U{ +|OV4;fB`fPWyE=v^iA874`Vv<6@h2VrzgKMmu)Ta*(6JxqdTGd@S=@;!UfD|{5q+D$*Gbh}^oqE%GKp +jZ1*DysEwq*nOcnPTB{6iUz#h7lsos!<&sl34eCVvgtI)LiOa~b6veJ|X`78HeXF}!qXMVmKPiM%$FgA2!R7veD# +Ln6w~VDGg>Rl0$x{7D=wMnpN35x}_7bByYmeeRpSARtO_HtRcvUXbnz{(OlVy5ZEVHC&T^pLEQf!x~r +-e4hDEpLYjq>Ax@MUZ=UYF~L>1{jxN*OYXsI6_OE;@`>t%|+c*b{B%J(t2ZyIrNUi|a;*ArGiI0#64p +M-FF`zzf5@Kiao3daD&E{h>8&3;7^S(zQ5Pj1ZW3!-cce&O@$NhZpDYyN6<-{+GrQXM*59vf!OM{WnW +W?+n|h^*dY2y`&U=fF8wl)<}p-)J|d6M59rhq^Yf8)BK2!NLqHss@7NLxZR-QlGEX3I;b1%x+?bcj2+ +uOzM!1#k5;IQWp!0PV~$$FqGZ4~`ly>VsIi3D7(Zf=u<80UXgdfEWf??|;)kOUx8ORfu99_cR17^_qRUIvK`$@I=zuD3@%LjXpuJp!tv4llJ$U-lIQYJ`4BZ(NTFVQvd +%C71Bf9#OJbtH_rrYgO``b`Bf-xcQxx8cF1v=!)34&=qNo=ybh^pAzj;&irVN@f6=w3Yv#|q#W`A`&#M9Grl*3hF9S9Fp&Z9>~^wgXsNv{aq!WZAMb~?j9&a2CK3+SRG=cj|b(d|0*8@70Yr}-8O< +NG`JJ73q{ULfI8P7CH!rhDDabBTgab8c_UxzgXS|Jsi)YFyS-RTaxzRubEZ<4cc5PhJGUQd~*2wEq8(yDXD~G{%xK9RVR(2y5!L9hHJGE--)O6g5i;i(`o(Y+Ok6jlV +mfGdaVu%#5E7l9{N2gjVYf^!8)3mG}P2ANE?aGo`i|m|FsN(EhQzf2VEirTaGs>y*(IYcybJT<=S=$q +e$x~F}U%!s%yCY56GOQhnN~@4|04nlAFgw(W4n`E-u6b#fl&@3&=1P@pTJtCG_=RqRY}d!5Y|d-zY7) +MWUg=japQLvT6d3Pe(#Xcz@d& +}P;f(M4q=dp+2xf^))=}GX9(r +EPOWt|)`NJ-+Y&&II3VbFCvrqB977wdZk3B#=$}XTS0&W4sU>Z(d^b8iC-6P-*-E9Cy2YvRCeoKfCz% +DC~!wp+z_@A%8e{olCi1orcz^X7SO;*hl;3>cZ;U#Q}EeKt!Tw;~pY2 +T(qk=e69#7|;i>6Ek%H&-x#RQS?VZlN~^ZAInjh7GC)8;~w@|RckWGXr+IEc|gz>K}jt*Dz}~djw%Xm +uhjPxuac(``piJ@Ve1t4Em`6o-Ug|uzp1CZ+s2eCY6 +HqAZ;^Hb%BOBAAHtU|#_N*%iX$y*mpi2rT8G~vmXvova-+frVY)HO5ApH%!0e0eM}0HMa@~;&-*sh~^ +Vli8mxSuC<={l8&>mgIXOB(}PyP_883c7#dgBinv+YgBdCv8wiF6XGD07TeV$;i7rw2)$^Na$OK;+3% +vF;gkpvUwB`m8@~1E0O3LRBX2fSL~Qa4fZsq4uPwf%QYz7@AM(C8ljde|nNv+hY}^QDuwl9iP|Ym&@CXUF9>#;r$T+=TN)1WLkysEPKVUXoS%k$MLOY@}3pyf4sCethxc%}U-cNGSNX^e +tHAnS)MRL;oIHo_SaPP~<3z(~fD8Tn_NCfziwiF+)y`O3OeF1to5q0TZt +3M&G+e!Ih?1SQaQEMyo^`>QErO+k!;GM~`IgCU`cnm{jg^gy%mc$G<#0{>z{K$H(Ibr++>B@;~CEdy} +_s-ydJ-tY`$`Kb&-SdP#8q@1tAFjMgfp7;P!6%c)Fg37QgUH6J~O74n7oB-3(32JF0Y$-;j@19dKFGf%s_l-FWqlG( +SeUJlA&-*R%|ISc4wrdr}>fZYznbw%gV|gReit~H+ekAWIM1d1};0nO3L}nXp4biQ5d=-M8u9*$bS@G +Al>FKC+3$==!Z^yX$HY484az4W35JWHn6 +_paVg8@7}$WcWAl*#W_+t|KVuV8`VVO6nh$A+*US}|H{b0DaZObBJipt$1z68RP@0KF6sou94Rjg(8{ +9mU=6!a6@2ue%5a*~pgDhdf&D_L*_my|_lrxf$yxPU_UEvP@QJn$@_uK*scr?Q+Vq@h0wD+9I?;k8k5 +!wZZu8G^+SXc*!{aPGfAIZZF#?LH8S)=IP1m4^Q6oJH7G=p|5PV+e>ktJ%@@Zfw7y7j&K~-5@lb%bmR +|4{8xq+S~^_A`pj*@V=Ro^eh2GG;;vl1GYJs3-)DGK=zxNm`CN?j_fRf1)=L%ITP~2xM +AmMQ5c-N1a|7GsHcE7gJ2iFc0{(#%D867$7zv^)MIdbnVf@JNssb{IT9$|GU`Ht&(aE&(v(%KTnWm^y +bZ))OgUZ4R4vZlQ`Hl3 +8(kyU?IM{;b(af=;bCYpu6&7`&yaqL;xDK2RNe@fP@|HkT*as-y`3mSiK!;VsZ3y6qK{s)}->hL=9}$z^egez{VU}}O;W}zq*rqbNtc1|kWnU(*7a-4bm +d-W{;4KO-<(iEgAZp+*ym{(m%YuX{rcrk}H4~cLvjjyV>7ccQ?O{VTCmsb<(=;-bQQ~TD=Yv2td_=TE +H%%;Sm+SZS7IF}jvDrPN)c~E`Ji35&Ch#oiSoe3jBzxVF?Q9@}(FxYNKeyazsE|Xcoc-gA!nFe!iF0v +SX6R8mjI}fIW1n&k2H-=7jFz50aaC*EI{rS`bjHf{X%+ZN<)@sa8Bzug)3OXFZ$Smii_N>^D1V#&`Sb +Vh{`~pm^H1L=)e1AxzuzyiwhC`ye4m`WKTcNZ=bw(=uaa3=zdQc&ZTj)(?bNow5Sn8oai?!Pvps!&*X@NeSlO`%xG86#9_U;oJ3Ffqj}&d@k$RIi6fvMvj#%kNy!k?^Y +ys+8R+(lbm2k~-e$C9kX`fotCa2E%G-xU$nZxKnOO&}Gnla87oYzQ)b)I$7%gQ#nX+p{4%M!JG4UTH= +$c^U5iLM<=qM@wV({32Kl;W_qp>#4traFYK?_7n826VvU_^~D#a`4a`UH3?&L6(UqrW}dr2k4;|ea9hV>olah0q~`nm6EbBPDqLu>}IEksB%+j+p#a@Z&*Vy)%P;EZ7$cGsj4h8R{m6W +WN_EAbq)}GHc%cNr!HF88!2h$!c)e`5tCdmo^XPP0gqt=pnG9mc#LNl-HB>MiipJ=iluAAw*lXFLSva +JSDmIj}`gj0!uT{sXk6OP4<@6ZMx`{GsqJ>a3y6JgSMnyYe^Ap+2u8reqfp_;)7-~&}Hyr!Wf>^dXe9 +KPRmLVKtWVaA@ITndEhF3L-UeVkJw3QwVfk4A13C*CDclIxn18BsPK)H#>J$>-^!>VAVxN**J +82ewJ8{@re&^SdB`tDRRi3PT~GlLn6NJFX#AI}#9l{lhRc51rrMDB4?*?_eXbWBP4kSOI%Yb9WB4LMm +98#a;x;#P8U1a@5~hRO@1nRq*<2;X8T?p4V~uT5bZ2mBO@Gf3l_bOO1xxm*j8i_F#jyfQ6E5%*<7S?C +1QBpjfJzBeF*2;rj5poH&^*vOI0Q6vFwPca3(^se_z96odHbw~1mspin(PpdO{K#kan?EY4J*l`@K)i +Tg&U=#eFb|RhGyDR(=088iH(Xz=~dC;xjVt3AsUOh!^PrWgF7qiFu>kPx!k@wIsg- +(7G|^P^xnb*;bha^Wu1wtx6E{Sru-{(2qa<7`*xZtM5r{KUFFBCDm|&KB!h+Cj}bMhEw!-QrDXmT3kT +X*Wf628Up}sOBD5yu7VH%luELTqQ`qqhjlp_sy2_R$OPOv8d{Oz-Vs|}wK1|*uvL8`)q9L`M=I~>8s; +}{vL#(Lu_^Lqi+b#Xud&L&Y|=!RnB^7G#$@%Rt#% +TNi99;_r@8)Zqo9`Ld_W_;k-X^cGc%-#0qtj_w(qj8H)t76QbHtyW$6w9i%TivS +5FhG#17Mj54sVM>S>!}1)^=oxHC*XQQqV7($Kk{r&H723^OKpx+s^zLM4xVyqs->6pS1K +ROFOefa6lbQVUa@z+k2vB`e=^D?O0aql3Z{w~eq63u?gc%tJ+X|&WVa!WqM&(6am(aX +Ld$v+#zG%~W+f&nQl#pGh$|I#S$}bh9Jb8pj;bK|uoL`gjSOec8@NKRCKo4reG!$KK@-cZC|mnamt#B +Gm6gHzNWEQMuT*NBoo|23Go8GOh8ilciX8rmf^rk=^uoIER>?GL<{bZn)jeP%w}L?i$_2nk4zcyO%yB +7&}X9jA}U+|zw;=Lka;FgpxgC})xOVJ~og|F?1y;I~~9uNibe$gN|G9uRK0=Q}fXo^R`L*x|G2bAF3mJ=CuB|MPc9^BJseCuXsx^_KPSR;MHxiypF8Zb_g&Tpvja>)x7pzb_v +-?F)zl{XpeR@FAU`8dylDy^TIFZXv2k$%V#49YH#}{K30~I6I8+6jRy_yk@=XPkej7!$$lC1PR`#QN% +?&VZPnB7e)W4^1*oB+GzEJ +4RIKWJToBY4di-O~QQDRn87V+!KJ9Ii2s)haH+gxrAq1>|wdws5qRI8N8%g)mJqi@Q^4^r%u=09>kFN +Rt+`R2S4@6uPprtIqSCE5Udp*bp`I1Eb@X_YtpD1^-|rXYvytJ?(3qE!phKOzm7&|q6ql_)mC +Rycad5q-6zGRoW(d-@G0&mxqcRkf4e*)DW%4TDf^`vbut6Pa1jCI&){HU9kz~k@0xzG?(vlW7_HuhLS +NP57$m-c1qD&iBmD90P&XO))w$zoAu3pzt0ow(eY@e7;&O%@c_2BHA=)jl)YQ2TtfnYWe^TrdfsYsg%kXtNB{*Cw>U`e3DL&tmq@lE +ML+r=HC63|X%Z*YG&Gdk0{h&VKY~BJ#)xP*h-wO`$D(d?W*PLS4?*1C6veb>fMc9zo=-2Be>OuN3Q9#C?wnbVZ%TZSYe+!|Lf?**c+8ajchIGzxg+ZrHeocal1 ++=8-SlsqhcQ>y~ypjZHaY%pp=55G+BL*I|+}(p&mQ$sq( +3{g1ao*`rqHrOK}T&C@TK0Wy+^FEX|cy5(}c9xQT$QEqr{y$28xSH8f?pVmTCVYw_}=QYHP)gOEbv8v +uZ5n`8;i*E*Yuc!BW+)cChFwDoc06QHZNV_c2fq6T{F!=xHTqygA3*IOOZk^{Oa&5nG0IbAt_r~Poe4}k*w6{IobG6YX@2?aW$@|A=fMO1^ +y$O+zzHsg3HB(7Ud%Cl4n1Z+f2t-vfrgRl+jSoE{itzSEgtYSBoFRnku>kl@YfS_W5~0FR&&Ysbmm6Z +GvGQng>NIwzIcY|4@X}j09dQX=Rb| +G`sh#CE3t`bgE6Or@+SuURx(zZ#zQ)(WnKQFtMuvNGHyzrbSDLT%vtfxW72q~k;BRRE~V+$3tKEypD4 +$lwMur4-fQD*y~fZ>k~Fm~O07AsXAYjEsT16xGoH~J#cVI3yc#UfwMl6Dvl`xBl`5PAH*C^$Y!fM65% +tEUohSmNJtyVtV0E!|TD2*rF|{t7QaRz#$aHNaz|@wwdNSP-Aw0)_I>zF*+__wXV%n=lo$_>#w{i-`Y +7T7DY29BMsJjX&9uFj16+;lMy;*r>__%J3o@9#Y9LxXV*uDGPo)SGQRoOIsb4|nK9obL}WUI0j=y7+% +w^vljMLB(zb0^ZZ)=?uD!f!`99?L#>Mo_NCM~n5rh^MUJ3V<_kDiiZ^baBr +tr6LTvVu_wSrwvQqQ&(v+##Y(SeHhC}kJZd6S)PO9tovmhWJ8b=HQJVH3(=t%E(3VfzHjeUb(@UL#J{ +CSKUIzu6^|eQ;_n#1WslXeBRv||j<#&5y?Yd=N|)D1A?nR~P029-!L9CjD&mL^E~5OAG{-AEG63r;_q +b6;C!`9#s{&+uVQ=J^S?7S+@HlK+nn}yb&JPc$U<74ztEM%O<}uFAVgD&dbJiiA78O=iC&>HZUc! +*50~TL#>}#oM}Rrc=VnaVzbYgb62aP#$D^y@WvQyf)#k5RhLTmD;r^1YP^0c-d-v(Oan%aRoNP&AyiP +kz#X%tgEGt*RRRE#S+!m9g!qE~9^YG%_~j*Axb#JXdNke4F{@r5exWCG?@jC>vxM-Mv*CW5I2Bc}XLOYO +)#YE*(&?nHID&#|d#^mBit%<`<{5!-}Yx4usGLpnLd1miSc1|C|1|F`G9?Qj@T5621CWMg*f@Xv3t^9*{iUrgXBzG{T5U5-upoi3MbN$A~n&{;DLPxy|*?Gu}XrTmoJkVGni|n~W +oepZi?!Kk;pn5IazR*UoJDPcIe2z8JvNEY#e>o)cXAmn1e9JR81=F_FYl@-}l&X6R@BnY9y%L*EK-HM +ET-&8?x?e=xYAZrQ|7KS^l2nnJ?6kS~RfAS}g_W%G*r?MXdjs|mAVk059brwRJ2rCU*1eMl9a+e*YXq +{aU6qU~_NEW?paG3zV8M;npth+zwi9J2khMqi?AR&%9Lt}wsE1>rq}Ix3YO9VZ=5fMTJWDQZ<9c&8-w +(-hj;4x40ZF?PoTZ|J(Rk?<=2U+=GM(6%w#ww>Xr_a!d+W9u>`J8x1%6KWVW49UKACdY%Hj<`zxm4i)Cx$*w{^~3Y*d`6B{#$l&dl5A+}lXXlYbJM!fOphB6_ +ybB?L(y(n~XSUe<6u>?l4#mAEVg#SCec4k-09qoK7`GJnU)tqFTL9qy->t9}mo1%u6YqSN2&{HKFm>XFgZW +DHo3#O`QNO%d9II{I_H9SR`-%(^+BMs%q&C<^Plb-j=)a3b{C^^4xb-tEXh&*7v0it8xYKig1r}s}Ox +Y#5zwxrPhpe#I8$tLO2pOY~X?Amp0la4K +jhIl2dzc&Bz3PSKDRp0=&&q?3lRT8S(mhPOWLANWmA194D-bvhTCM`OltmAjq``(pln=&osCB>|o*vzD6qP7#2DV;*BIU*GAD&Y?l{AU +l#u?o|>0sDwdIn^@r-B}yDM?C8YSzT+aKc3(S_8Q)tvreaf#eY!5o504JxmnckVY&3o(=Cr>SBArNKH +_N@NHXCVAt)BPV|uXdB)KAGj1?QaWk@vp_wAvJNyj8WZCZ7idwC0Hs$kv8$Ef#5VPjEuloW@NZ8?D{( +kY}()F@>|&2HQTrn+@Zz;k-9KE?fGdKR31WP`-mGoJV4X+-ucQyt!`^#n*`_GocYeSFJL=* +1)1S=O;1#TvbHL$a%`|3vzAJqp~~!&Y3oI4w8SAR*gGIgpg{O7XWDquLwv{k(NOgqp+sD?-Ow>*64(Z +qluDFC-O=}2AVxc5U6$`%DAcJy&xDz+Ql1u-LD-bpdr{_YQ_;Q4VxS{CvjxclK4mWf3t8L2g_9neD!w +VuVLgAv;ee|G13}O90Fa=!)`HmQwQz}`Kx+pU^EJBB$TnaqMD`%C!SEe*Ripv6lolHL7{4FNuC$f+B!e_nKBlay +Mi($3HQt5u)ObIR+wD;dEvCg~mgfO +VaA|NaUv_0~WN&gWWNCABY-wUIZDDR{W@U49E^v9x8)r$IXX|NvjO` +vfw#!f?B(bIll^`u^rayk)djLrAkfX$HrpioA5x~Q{FF-qNv^!#vh?8tKW@RxQ{Tts5b_P4_KrGjJGM +g97J@DAxw=eca@ZU>zwl3x(V;5pttiqhL_oB?=ut-Ga!>S9;*@vTp!;_0czql`0n8obi^yKpV=s!PRo +}OReOPDu!`t<4GAPuEtIbY^n@~i+HSTW};O=Q8ulueVAOO|9TWHG$TlS!#|865szCU;>9Ygi#@5Jpnz +;|g3oWH1%h-@|$-7Mv|}F-iGC`m}GdSc)9Rvqe}$bMrM7vl*aZz6xoca&DgFS`G%&Tr8N+^s9HUU7Ab +|?<2lM?DTLX7R#_OlcqA}z+|om5m_@7iR_N&MF6wsgTWvO!ZZy6w$HAd<1kC6To%sFV1UT+9A0ZI{TV +Ml&^tE>vT(tJz#9PjLw3!kB2C4L$854z)XQZU0Vlp;ho>I~!NKW=4{y&d4ui9|mzRg4E;Iyr33-tl+exNr8aGw+Y<3?BaB>4oeM{Bwaw0b1`$j*>#@#>sTba +}*s&y-W*KfTGMZg|C*0U*usX)3D$}w&E<~JO(HzYr$lSN|~-LNFZJyP@)1&MQ${7&;J*x-%Edw`MwXk +Cz3!JU=z+JxhPS^LCdU_Fa3Wqk%4x{5_L5=``_jFrzgQrhvyeZr^ql+1RumELEu4>O~uuC4}=tvJ{z& +QV)7f03U54M@BzJh+tTbwnWP004LkDtWh!!G0W`jr1z!*W@U;L!kwFA2TrSf!&b+4d7X +)X_E`b7k0s-Z~0Fkc|FGV3|;4FCV_ils8__T5#%+E)Y@WYA3zpnY7iF`pXXdZ|R2EZ1gRqT46*8~NA1 +$+RCs{;HD&X;`IoCr3jM6%D23(Y|@B6;C@isT*jKRYWYX%exwXGi*V#bD$Ev~~wTuGbh)tRYoG!vk$}ajr +LL%tEurndky&MH4zrDbtju)N1*gNHT&pq(v>5N;}@(i6jQSN7tkn9|8X)8;#g+B|3tPvsD6`5Q`xQIL +vO@T9i*ZkZ37wjZdz@#_LR6K!{QND`0AXUpsS>sgb*j<6f6q{1`cFDYzzp)th&BhsZlMs-$3(HfN$Rd +iBtbD0_>v%8XKEc)VtOV9-#f;lG2Lzh}Q55Z)kmBdugK7Q0MhnT?Sd?D_ +5-)cRp>x3#Klq0Hf0#~C+)ZSdqMVZFvj;M|VkwAUX8-SQ9*%GJ|89MN~tOQJs-<}-3KfJi~lMF~9yvE +&-PoH^FEXU8E$07oipmM?&`RsWG?YR_X9&!Bc&x=L61N(xzjb$(6A;%1J@TsaU&VXRjFmRKsTn?4F$u +d_HRJER!iwQ^sT>1*!nY2IwKd2xWQef8FPYZd<@4!OU3ZF42jIfw>a7mc1!nF+s6bUei$AE+*b-j{Hw +HUWGxB{G?Nk{ZMfty=!ih0h#Spf1HBK*Z{Lt;Th2`?e>9qt3>05Vj{W`Qt;&ycy~Q-Lh=$|L2%*ZPfD +2OkA^Xe|f0Fp~^HzcdLgROTQ6%VKI<8CaN{{s5VvSYhRLi+>9&!)hXsk#|r*#e^eFnum8JGz&zp_zW+ +Qq2y5rum%d5q=bsk274F+SKTS2K +F#n-Eu&)hG2EK*x5ieB#?Jl;-~A8W~a$poPHRskMm^=o26nBrlYT^4eh+m{%o%fJ#6XY3M9xY^n@z=t +9y%|!3uwD|p?reUwKVxg6&bQ#sdBST8k9~D2PY}R(0DO%=b*4Cf~MQy!!6h(bf?^5|mGjf{ +2&L*^`6Z_PZK<43W5srZ*$p7!G+>+6-T|;CX#vyORju`l5i8**(UPPfjM`%IN>0`kcOFYg9Fpq22rXj +Y~+s8<5he}AzbONd51H`ds`b)blohNs&S6^Sclg(~d|NVqJBS@s18RBgjebD|84f*{N>_f6wn!FdUtH-_9cud;yDm{F>JJhne`WT{W5YWdF}pppfBtJNWHama) +9v$fTx4ZQxWhKyMQ!Az#LJOZGriq}8g|wN-qvf@M2lQ^B&Y;IEP%%78Ze$3zA>pYi*?V~Puo?OujOQ8 +tsz#cMI;BAldaN`C36#Z$der|$nc)Df!SQ1S!npl}4u2-%NWazB#Ani`vF9EG4?E;=61kYaUM&y0d%U +k*d!?`2XbCoJ)-4D%jHW%z<;g}SnVLyo?;QTyeEh|3f*0cY2tFzdW=404&sMiP`L2~!r$A$5pgN05c8 +AD`+W>wrx%%$=}zJ5n7&*n7-m8p=7g$B@47uv?CzrMIfVISHd%GpPdh?)2jM&q)@GmHduo(K-Zk97gQ +)!eYhI6dMI7V(NnyAZF%T(a0n9QSCXS+KNJ$y%4#54vr!vte@`s%k@)r?yDw0oeDwk@Xiu)9A7-2ggL +(S5seCtjm{JmXvij_Fb!78EwC**ly=fWSuPE%`nVN@YT?NZc3RFGNDw9+b6G0}{no +9TRdzh^YO2-pC7A#hr*U|tC7DF5BCXLA~6L{|>$<*bYh>j2&gc*aXL^P}+klq=}QJ*zDQjeOc248A+O +E5XuQQZzQhZ|ae=(dV5!GZ+a*N%h=uF1(_<0Qy2zjTPb!*$<@q +a+FAmXyqkf!1xK`9w4g@6ajJT$hcmnk3P{?VOUVrH1gzu8zVdHmtTHic#@&WSC@{$i2y}inf|tI$prC +Dwchj)$k(;=Ef8DPUZ`$+ZR&p+_d2W`XruWa^E6xo@u>(&53!Um2Vi)8c%tP#8`-K;!L0&`-NKy)-vU8!?kSbev2RX~5re~=r|Bq7Zms;vw0R`b$cPd_uCPV!kryUvt}?;y%4a +)3J#&8B99B=q61tL-D(klxG5-A7jr2FF;@jgX_nd1&f9o5%AniPl|-70q_r*rCO!J1rEc9j?sW8so1L +P;THHwPH3sc_y|0=3a>({N&51a{JdH9VlkHfEYcq72*tZqi#acWxiJzoSRqj1UHP50p($7?k4^sQdJ% +MHnLH+ma+p#Vh1&{|-hV$-YrjeO#ZWwEx(*sgSY?o%mzH_1+25WE_XuuyNn_inb(?rnf?6t`KsN!rzT +zp(posGhHo9tCVnO^9m5VV>h(z17xc<$BX4_n+AGDIZr7?C_fWi6`eT`VBk$QNWx>VGbV +X+=4`wHQC2>{NLZb4Hew(9i^3{2M=hr=uu&d%8Y69#O#eyrhu3IDBHc_2hxatBT)&*62h~`g|XhS;Ek +W3eu?t$nI^{uFnu&Xg`acsgPytnB1dYWI)J3kz%OOh72qvP*SF?6kR0UQHGx8dVeTc@A~jgTr^Q+!Ze +tVFfCh88$#bFD#A1<$C;fPL5cR1!hy<>dxms#Ea>yfyZ~7`qTSFPm|?iHaRN6{TYkQ6XyzYaC&z1*qD +De*duSwh9ym%#F$%FBqrmvHnp6`FTrzy+Pp<0bz%&xP!knl6I?xP|cEMsf~c%4%H1h^%Juu4E)g&5v{ +MUn{HyUN}{GesDqCkehkNG%Z2@4v@D*zmtB4jvZyEV +?&|A@v8?n|;R5J3D=$eXZ4tua*l2G8+XvrTsE#Pe<8QZf)Bdr_8$S>FLuRh#d75Z5d+EnEI#}Bu^UjO +*p?Z;nla1-EWCnqPLs8m2~4J42&YaY224H6=IDtAmOvga!)&THCiI=W$`Vr$-joV+2Qu0D}(zWuHMI< +pzyw?YChrTtPUzfy;O+16A8xBYCkmSRtemDsmb6aUp{UBX*!v@r@Vhyp#EO{otpQx31wy!KeUDIY=d* +{m#SU6&=fBzGBaG?T4lI=i3EW~-ViMXnxc-BGYtE*}11D?MM%2s|i1{=OqM-*XMhF%M`g<9xxMft*qx +kt%vTvk)zl2(5tgUuFlNjQuxTlA7)xDoUOg*;Zz&n6O-&0EeYeFR@F%lc3{$foF4i!(VD$yZqWM2rY(#I2!gV(~p2HadsJwhyl>i{l0Q^l +Fe$eF=#`z3GI;%<3yKVY7c7P12ZFQQDiGLlMGbNW!T1%V92LmC05Ppl`dx1nScP1YR*`Jhe!TBx?>I?qV9AaCb)Zvtg9p~{Bt(Zxa)xC%|=bSqsZAyqAN_ +m<}l!5I@3EFdAmbqf}dSR+7d)Aj9 +M8jO2z{l4Le69hW)0!&=zJ$v|%zA(&1Q6YOQcH5ZCaPsCzUHi25OjhfSlnwNcHsH0#rW4-2!=g +vTZp_O$rlAI98t&!zk*8j*OwSbiB7HKFQYsK^tMSo@{!Z9C!&DyLT>8CAUZ83 +aTv@^LvNh<~9#Xc>&XIs{+0lD7383cyc>`Y=_=7I2cR+UFW8I{htoIM-u>j=&8?w9kVe{8P7L5pwf20oN|d&G^%5+Md*_3+u +6?mU)CE~{umgnLOA+lFB*e4#uWh{;Tb7D-^5@T<+UL&@0&FN!6^9x`4+zAhgqE0A4ZOvb&zRhj4!iu= +M^P{%c=UM(Bhtn+hinhuu*RbavM&)7@bps0)CUrGnTN>kft-JdptU?q(TyiBar!B+X?T@hy|Q%Y5dwQ +&u~w6t0~Dj@E3^_Il7vvGl2JWMSXQ`Xoxn?qwJ4yQLyyE4>kHz#-hkMLkh5x0mS$2aOIV@iu)zK+^8v +?)bRe3~j3FmNM|%V)5*T{Ru~S0lCSklOvfM#o|D}(V*VusPS!~=|eYGWx$}3TqDT7Xpc~U_`(PY<%C$ +fb_6 +A_lbAsChz8gxm43Iab6FTKMmv_J^%8P_RBkD|bwf1T{kUK!Tf59*@Qmj#o>)dV;BF8= +mQHwV1)tG+YX$IFSm^%YKRVk#eE}|U@45m89z(*Ov;!OMk@Vlm(#y>I;(qV@N&K*JgvtrK?Ft;eUYX^ +DrCAK2=YaHoFsMp)&{j{w!hupj;=iqL~Yq@tpW#Oh=%i1?FLmIX>|?^8<#vqA)Py&cmM^-|kb)ER4B`9B*xcSKFMu~&b(jNX;-bZ$6t +6uRoJTF9Yn_Gz^){+l%bLm@Q=9M#+ug*tTNq1VNp9g7?ufwv-%DoCsY`Ph@}Qt&NMRzgCFY084zKUc- +~hpC?sU2~q?$l?*F2HZPP^f*dV)6}(!)wx;L*9w;c)RcP)h>@6aWAK2mm&gW=RdEZ1J}v006O<0018V +003}la4%nWWo~3|axY|Qb98KJVlQoFbYWy+bYU)VdF?%aSKP>v|MMw25IgwvM>Z;Nf8$BJdX_@84)gD_mm!to}CmU +NETkLtcxUcf7>xRY82W)qHXP2E`bN2SWxh@NKQeHN9X~o&ga#>_)lb6L9I-PLNUL8K49Gy(Y&BunNMa +G`LIXXQ){PNxDo8uFF2<Lykrf4f6bc|z@_Z6tkhVGbb6Cs@tVDzysgI@8z;-fq +O6*lrL!5ETOH;pJdAh7+e5Z9-ogLu4he8#$^kT3A*v=-g?Jk4jS$DG$SV3^>Wt>c;Og>K +e0*NvN>sq+fK{*B5hQUlcoZYhi`_grr(n0e!=S@Yxu{8ewV%GX>|jDRJXi9k2M?vopSKV(&*EQ)RHX!QclL@BoPT<1(*!X4oLF*bB5UKW?LeA=vp+%$Z?X +joIi5NXDM8Sg4!2aDZuKFez0Sy&9*2U7`ona;+ck>3>+pO#le{&${zD=4@MiFd_KQQj41Ohx%(Iltgl +aG1m5Hl5|!YRVa)>1@f7Y`N%4P`B7(c>&X52X7C>)ZrNvNks3A{vgqwMUnPe}FW)4 +Sqvvm493Fk;JbZgRc{w>gp1e@p5uM{OlR`)zwya?lanqv|fL0_>!NAI5%8_B&Z=d}Rr(X-H0#G=Bxxc&SutU4iM-)KF00POY!= +ni`IDDV%B)jmY;82;(&z_9)9vz_GS;pEke6KED|f{!E*A&rk<7vaCwqqnoPL +4g26F +-Ffy)&qJ=)$Ta$=%nn*U$32*XNT7Z%VAIaZG#kA;euaO(xv0w-Z+IO5^0q2(^NbT3$3mFZnqIFDj=uq +JBZ65#I(oJ6Xb;uGi^h2NyMMDad7Z-12LBfeVg6DbtX1>+uDOUKl&ayC{2QM(s=Znw+1#vCSAYFpXgy +As$wxS^i*%+}&E||%BLzVFywRRsXz-y+Umr+_-Zohf`)9lV@&7#ce~RY_aDJOM+$@p@NuipJz9gcb@M +gIfd7Owqiw+PP`w42Bnps>{Z{gwf8n#jKxpXCJIP$@(SB6b%-oyj@*?74Crsc79I)~qzQ?KK_mcZfnX +14%RllP~`2cT5D`a%^&5$WeY)KB;K;XmGP^DhRQKS%Ie1iwWCXoPBZ#xI#NDRxPPox${D`9$i6 +`K8u0_esmyj`lPe!Dv`k1+!*OulUUCwG-%N=+V_{H`Gg0Dcox}h@qh!y{gi@=Bw3lMG8f%3tl&hVzE& +AjT-#|*lgO6%8KnYQW;p7Zv;S4K*^^fYL@N +>`$T!g?_YVyLu1jikx3#1y-VIZ(slpq{0W?a#qP$PaE3I-brju{FTI2XOP0Luy%17tu123mEG8h_0>A +}Q@Q)c1?BVT%+DSTJt@L*;;wL)r89i3*VLIfBTYy+Gau!Vq70_`6i_UXLq2FK@vFKmdcT(JW0`j<)l; +qwVyJW^_b3+V1C$w%a|Lr5(^{yPr$RU81Dqi*_^OLpZBz_9K|>cnoV3vR0CC#*5ekKR~gwt*L4wj&H*^2%uEIEOQuKeUKaU}usxNOs0B)5k~J8iJIbC7QkxdTmsPfrGBB +`q*?te7biy)ft%kLmY_t6yF6e?~=?w$5kf4^uVyXl7h52jO`U{2|u>W=zwr>f(FPFk?kr%=%hq$5V@i +#E}-=NP?h)c69cbr|Px10pc^tuGK5S^6UL-a3^vl9M=ezG-VBYX>8V501zDsOnfq+%=O*u}D8puXPJ> +@IJv$syX5<*arf?BIHX3`}p!JagXc0+^4y)<6*)jyB7i2Bwl`C8^C;ADmU1W#|m5;8^1+x=zJ9z#!;2 +VFkZaG^cGX*b7_eKX>gvf$E0fM5AfBoMlDS0CvzUE$&&p;8WP2Q^~-#_~>!btQH({<95T)+(WbQcD!% +_*==@1ZFVEU0qO}dG%A^=r^mY_?tsgGq85?b&kEsaj|Ge*(H7mO_+A)H;+fU0)q0`Kqdm`_inQ}9v0H +^qE7e|@S9_MFCEjF~wY3*AzM>mtaqZdGmw0y#7Fa?S*q&pKiMOdR$@YwKW{yG$!|aqt~n)*=^3!Nh@~a6Nm>8MlTMZADm8Xhlyvm`kot?55TaLvg{-XM=h3VXE)PxC)f4KsrAZ +sx43?cK8L66uC(2l>-aj>b#t|Nss+XNm~=RgI@vymkoG*-E(D_1>ASbDCN|0J(b3H?c{O=GIXXR2hd^ +veM1245=nw%WGY&jF6v%emU{*sRVzCHT=`1}jwGr +(Iux~+qQTbsl9V5l_aA(~5c`H7GB$*44z^07GiQ1L_0$;7_;QqyzlCRmF+=5hnhMnvEVw2unjD0+P^}3!S_fmh&=`M{rc&Uy5p~;FWa}hGp<_V?=aD)>?#LUUc4L4@*6IJ+vE2 +n4IUY9;Q}Wh2cN^pI9s(O4?yr*B@oVOcq)3DPv=Fm#2BWRxBm^gE@?S%Y@>hH*qCd673s64!ioIV2M7 +qvK}CnWLeEsQd +FTk()OZ?*JJ7!gJj!dPwF2ETewjVdk{SJ(ABB81xZ-Xz#|-?X)FY=)xQq(_ffOK)DnzpWkbvOtPdL^M +k0>~K{pUQKuB?N$L{gaRQE0u0CabG3_P76*Re?%J~Qq)pcx+kI^$ +oYp}s&}|_Rux@06ZUZfb@kbIK|1rlZp0!aD4aT$bj#u%ZJy**GpgBk#7 +S=VOUIr2!~6zJ-l&ttKE`y!Aw$9AJhCQ@+$spn=c){OJoIVf6d3IkhrV`hm-?ZSXKq +soECWTUyRsI{a;OR6|H&S8t^eV9IWJR=Xxc%*Td)hFGfweD#q)JP{#ux1nlDprwH8)xM%7l5D$lN|$l +7O?^jI~~nbF2nuyW%yptdDK>I7N+fGPKK1*{&F#%&dQqGDv9ZC>j;mSs8G$Fsm|*wn5!50D|N82?%AR +80H`zV_#G(^)VbMETkN}QUeI)acodT>eEsHX8Qtd693pCf-2OP%bpBalHU#D~^U>5)(1?^| +ok!?t#+k8(}36m)gbKKcobSq^|&p5~hh{5(4cHZEoMqTn!1>ulCJ39wtE$_ZADUQvZcw?TQqT&o}uZS +&F;L(DCveMO8c7PeoRj8qC@v=I#+9Mp+UhV_bwEA#p5dj#&cI;~~T_0nn7yz=$y9lIRjgE7yoHcBFzI +2P95YUq-bQG`(ZAUo*~fn?^CFg8*Oxi +{c&H$TK5?iUW89MMs10w-$Ewi5)e^rL>mT}emU)2BCgX?0b*65xb4VLb$e0{RtOp;H0Fm7Brc%aIdnsPxvul8g5w(kE +nkf_s0nb=P`#CXtO=EX(}&muoDHyvd}+_^8w^sT#G9i!+bQj +3=Aol*w|hN^AgQMJQ*#tJRM5Lh}rk~TH1B+5rPaT@)-N(GLaktWebtbg|{UhA|>h2hdGOBN?!|iy(SA +-BG)$vi;o6xOkjp|IbXMh35CJo1gX&&o5TTmBgiDV{Osnu&o(EJFi{P)8{Dl+2*K&y(Bw|=A{4v8O3! +7lgAN$tInc8zN#jP_zVX;?{1D5~o=_ZzJv7>PgC~W)og5%%Ig=7mG~x#7d}XLIR#w@vY*qKSYDG?U16Vek8d;78F3?xU(JpY(`HgXasLM<-CR8M`*S5Vz3#w?6Q9B#RB= +!zKazUd3pH$^+cpnRveqx>P~J*ZZaelWnBNM#b@@SwPQKfT(b_!f^32vfPn;wNCXHRa2+%akWD$vl#= +=Y0*2`*_NY(GAW421iYTk;Uzie(UZ9BJM2dKVPah=xCWjJU;@}E6`rDd`66_ +?^3v|oMh+1j49w90HuJ@Tk4aacWtl}{YiNR92@%J@tw-LSIRLl@0m3Y)^AK?KRwLw9?0nWJltU^|z>J +ITL25>Hz<>G&fJt)9c9wQQ^HJ~@`k9s#hvq1kQ1Zn0AkyHPFbO_=bkRm0#oa0JoLJli=R1eYG#Z*(k5 +kH2F5b$PHlV{?n8uWhv62S(PrnT~b2pK-Kl6Y^v|r^7$LbUk}HhQiEY*tBTIXo3m=_?+%uNVyibWcj7 +p@FhdF2le4^RiGAV5i*D}d$1F1i@ksUp4HbFWUjRoZeovOi8guK?l2m@Oko^DC0So$$m9Va_JEL{5hiK^H6&Lra5J7u|34|rV{3VshD89rF?g=4jOkpyjEjonH&RtOAHX~9kyt*0~ErGET6e +dQ_71^}K_)flrQ^o^E7`8*3c@9%(W>JBh*QddmspwwYZB}78$I^w5<4uqIjk$yr` +S|nHA*+tU_giF4^_{0#32fJpTw#sA-&!`Iza<7Q3;QdxNm|ajo-AM(ia!lq~1ky0M>6Gz{buwU|2=nM +JA;gZI_~)d`_C@#rcv-D_jAeVpP8Uc0nailM7TqAM;q89-j^nW@~OOVqU6*m+FtnEH0x8>@zdj^FoME +vyU!j<*#)NNMJpseEG+j}B}9F(sFD?`~sDAwhQo%B^Kb +8m@KT`lSN!$Kbr{Z3ICvH^IrvAqmL%*h_Q@)Kls2$E`vdfr>7nzHVxlpVAZR(@GojQ);?K(uq;+YAvD +m^NwOCt6H0_=_S>*db)?yO7`6C)^0w7MI{)#*g@USNgwMx(tG(j)S>@o)dpwoG?&8fzEpFt2RUz9n=A +IuPUrsF>DWIDD`86~Z}oD&Ti2?WZ{5tX&*O@ne;8M+C%lyJ2O1j%Ce1RHVo6yjQkAhE`O&ivSU(kN70 +EkK%%9PQ&Qs9po-)d8qYQC1Z0!+NtC+2#W5LY5fKF&%+lS3GL6Dh6KR4gvtRH7F7D4P|!94uXu?l4=q33AQI5B`wY7$<-j2b9sntr9Nsl9)IwbcK3PG;@-2#GOe8o@e^@ +y#u`Ev=O(V9dN|ewuUxX4K4vTUIeD8g2w;&q-ONL|EBZ`v8fW$Y?5TG%6^J5$K(`VWhPNeEBoyADZ?bM!-E!!nDy(~8R_tbV|IXP_bDyPb-b~#%x9%?F<5dY +7~n>7 +vZl*9WK1zn&bovO)j)L-s}d!x;WMc=~Hq#sbOM)&6XI^!tO+U(RFsOEMmvKUEJ0fBJQV;%A^C#`3 +dmx^lXtIQ9~^(*G3xlIo#F2Gv;X|0Fl^6G)esSHznUCPjt@@XAeblyQw4~8czW*dMUXNZ(-m5``1*Wf$q`|@@6lNJGOqf0_3Tz?AEMm$ +^VagD(Y*NeW2t#sg4N2w~leZH<`sn%h25nI(7_(?~H38OOLYMyQVwuk}^Ji!@IV8U|&6MUrd~F`vx%f +SxWO)nF#f#g#DhoP9)HF`MKRP{lpL~1p>X25twa9^j9C6q78N#C5tF9Qt-ZDd*13Eaz2OI8UaaC)Jgt +|yZOOkq40xc3+utc?DQKBmO3V&4O9&G>i>7g=FIh5U*NV|Fcyw5FJ9ea^o`~m+%UK}i}&11)kssb6kb!!W^uyPh%aWLW2hU)Q9KYgzH9X_?l7BYKvxhQ?7iO5-{>^t1ga+0LbWgHU&VlVPv{RB +6YM=w+h$9UM)ghDtfx?>9(K;64gZnAGtPwUuD__GB}(eS;Mn~`NDC+X1vB`-kT1dWp7h|QoZ&hg$m^} +jmM0Y_+?^4?Tj!vz6bzHAo&s?gT>SlPmgZq`%>)}|ZSv};23ayq5kI+X2T@=`VwlS_dr5l8q#e07%=T +~I`1T1k17=@qPD&oXz(HFfx@&oBsnS?|)PHBP@k)TmfOks1LJ=b)_0x}6xvYMl3$o8Izx+s~9UKyY^TH><_U6AMkib}wA4n?Y~dW$5t-s1YhHt2k9-6kNiPMxMUqIJ2frd-y@irdwwN&R +Y(sjU}>%6VJ;J}HHAX3f;#9Z1BcL}{&dVsyNbm4fwkRikl7r^wnO){!9ib#-rxul=&6(&xxCSAx%OP< +g$f&z^|)F;9>os{iPBJQ{OBrqcC$`8qq>291X6A_* +w}FQ(CmYu*-=Ah`>YhZ&Ti-oYH%h`TE&%{{_y}(Zi&K`>5OiIWsuqAEqnI6-*V!s`cCA;xhB=1L}S{cNHQLm*XQ77BL~%kc<c?rhY4__bn7}=#*qE=sZ-HgLyySLJe46lA&2bi=?db&wGnTr3Ss00TAh^brf%<;hAAF6<~j$T-jzK +vqvx!$sA{TrhZgn08438K3fO0pA5zrzple8V3)dd%;TqCeE2Qnbhx2=B22a&;m2x&&Nu +IA=%b83u*LL8e0*z#h29U<}o^!LK^Wi*Cfq!ozThh9hS!Z +Raa>3FG3L-}thY~zYU}LBmT;6L*|$C!9Lr~b;+d@0Hx`flfWAy@J6y5Q(IR}Vk=mb`_&|_F2=l7T8M7 +>aQB)!B@BveRNs^)9cRrNWO^Y4`yAKz-*%9O#8KxQmTg~q6r8O_R9Wwn0_ap5B$h3zDzrH67G-orm<| +})yo+dTRu$Fm>ITd=B4`r^EHRDcLlEDp@*1C7QEcAEL`h6CL2KvL;vFJzgEvUZs&R!lAqy}d(sIdAv; +oRqYY5BzB;sY&#jNjrvcv%rr?-9{x?@7Ifry2$f2GHYX{lX}Ucj`M?9iEvjhM(A;E-MU}0Fz)g8`3v| +@zx2|a-E&??-djFF7zuiq@V=jlCVdQUM2oa +XmD4V3HNruJ^@;DN$VPC#xrBM~e7;Cn?wDO}ftm8~)YgtApnl_Wky)_{Nu?pJ0CdBa+^Be +%+AXc7FMh-md)mBeim)lKjskezIg)Q+7x)=}VjP8pHaV3iUksulGF(WkIxk!N?uLQW6~lwib$J6w!`x +>^CcJtwz1JX(i+9xNQ}Btq?P+jzP^keGVwLacm{R3BSIpbD+dH&9b<9j8j}2;ZbL*1=*hcNVt$Bf%n< +wlX?>sE_%=lzPMds&aY?nyLh0Nn8+wUcm|`WkFocMM68bMa0UXnYb;On2dQ+%mBym0#?+6ERZ+${-^K +UGoYP(GCI5VH1-6=@in)8w=SbE9%e~%c1HhFR#23-#8Q)Yj@c-T|{o|o-7zF3!~Iat +eh;qPzM@lZ4D4qE$t%zok>7~$3#_@R?&M>+=woZh^7g0G +IL~<2&i4tVmtdSgK*e8q=_j5ip1SHZ49f|>t2yvI^DCUuqCv=Sn*~0+5dNsa8dy1BM^JfLYk&@3A@>u +}P$2BU>c+N1K*>=%^K&TSAY0BCab_i*fxfe>c#_uBJSTP?g0Mmt{QhpAk%}9RqFVNS!#RvKW%JnIv9P +{jp%Pen@{(NaAB}eicfH#mRj^?7&E?pG>p<+Ym~A=Vc^~YU5x!G6o!zDP-d7y)htxqh638EKL+QAX3f +w)3?&507xelTi;ic3FQJY|si;AZ=ZO)ecI^&u&+@GA!YTLwaWoET$JkASLC*tj)1hx)iS9p~xv~AJJx +&B~3)0^;$yO`VktTPR|J7I9)S_F2P*g}?%jN+mcHFS;sYCe-|#{^JoXsj%y_PJcf1QJs$|3$} +oyB&m=z{brQsI9AP)h>@6aWAK2mm&gW=Y7mMVP1y000gu001BW003}la4%nWWo~3|axY|Qb98KJVlQ% +Kb8mHWV`XzLaCxm-dym_=5&z$xf{k&oeD$iEOM57cZrfy=6amuYkWC7-hM~|FZ8IxNf++8KfIjK-reyDrLOCAYhpMb}gI!{zfA7x3SY?B6oyM| +Q)%$}$GBcXBOqB~n%wtlkOs)3M$aIlCz~^*yfyds7_pl-ClT!G)+8hw<{dlB+{qz}>bIVlVO)5xi5>V2Kf@EB9ctjqT-nvjm(Rc +RAOD*J6YJPtk`a0=JvKw_Nu(y9%`A{TeS=Bj*hNAmcre9lcl~IX$51e*FU7HGr4;Guofj6!n{VAmSoM +>JCP=3Rg|Ktk2AIvbwUr56<1=$N?z}hx-idDST7;1Qhat#Uo>}X9ORibL131b2)TRY0L!?S14-1S>U8KONw+-w6WfX}vI +iQGx~+sN_EOJ4E4doyRBfO<|&nt!nxe_<BirY5)paqyb#(a1ATB0W$@4Rgqg+L20y(hb8j)DwR|x97J42$Z8bB~Ls+rB!z1t~{M{S +31!A7hN;?qA6cSz~rzL0h6ASsiOEaIFaPqZVrUni8iY=U!q4mm)W_oUzIMYBFV9u}ybW +{B2?y+36kA@SWt-;yMlB6;{w<^%eT(a0AdGJYy|4lHK$>u%f;QUz*UtKb?^yUj-x8=F>~2X)6JtsQ^7 +-_2W=x@{5wMZ~0bu6eX}0hJ4q8L~(!l7=Ca7uB9;+0hh$T2gCV9oa#F_6RGW&mC%3fzR +Oqyx_#!t{`t{mS3Q$N*Hy|bI?Tvj*f$wKv*Fh;xZ>Ay#d%FnwWV7lK~W!D$rmL;U-rSz|FBKk{qKF`u +LtaaiTy5p+?5gd~s7BjY-HHoLMM>afwODB;?uZP8J884zKZEhYkwM#k~>OlpY9VR?GcBIW%GC#R!!^e +>PgRzqhcFn>#u(!5nPQeVY|4p6N{T%ctvJ-Rf!4QHXmwNutZU?M#m;NQu@~ZeZRX?ITi^{3gy6+K_gE +oejFaG;0MVA%HUia!_R(c;_0UMc+|gCs|mQY;0K?Q*Q`iVWc2zuSL`TRg;G!6CXekml>~tWgkNosA`4 +fHky3pcYNX(wp&@2Fj4VP!`cVRv;r$dlej#tCs2^#Z$W=a>xqt{u*IAs!9$y^db=;uL)NLZ`YFiK7va +mS;JOTheR&OVSQEimNuu8+35-lAKICj6Y}?*@&v9oc*X#=VG+T`f4ZF0$_9%Vb&3iW9Jpx1?yJFYZdVtu+VBKq5=x#`D4}E$rC&^>vQRM!)R^hCp +U$-$wJQ!;3d2Ba*>UiB&RSz>LziIU)#MM86Ua>y`7|YlsD~vLBq4ezjx?%9v)l?7-1N=&3h8u$nsPf3K@gS^~9Pu3(0-|W0%y_B)v7oz@n( +z3BO|HAwf`fA-kZY71gm%U?8+x$onRE2FmS7d|Z%biH*&I1xE`_`rh~KQ)Edk+(vymtcm@Wd4+d@t3_Dz}RDyR|R@{p;+H^vTMvOM>cUM?>p>0sABoo>*gV +-Ec3Wz+_J&hu++l8h*sa{8mjc%j3%7s~GkgvFK3nz$i+~~Uu_e$0SQ96JH!c^!pWI%z53*AVr_X0|J8 +U^c1UlH6F1cpayfy2pH4Kg`V37S0sjh(ybvM$mBge@%PGI$G1g-j4lZ*p2ykRUFLGP<00$c|D#ld;5| +*PfEG?~MKhqg~KD7FwS5#uEeu5zA)pDt4jWFWu;ahN6LnsqhEuio{6`?p$hW=o*`+A#gQ&SQ$XBEB2iIp21aQC>w!ez<)m-Sy~8{PinwuAe=M8vaqlPgo +}91ZSA9mSYeOF0TzSE0QHgi{T&>?W+L7j#WI9fO-{qQ6n^jV#XaRQf3ZPXxYVdlLIO +@uaoz;SVE8X_5qzXrdDpz8zx^nk;n<*ND8wnJ&I-ZonxC#1?Ok~a5?eHkLSAgzi1+sNp9D{Ruwy +hrF5I9zi5t(v(6WeMp#pC|=&)=way(B$xV_dH&fEaXQPwVyW4U;-d@>Av;?Pe?be-K-?es2n#~{ZC>F +1?u?d=Udr4(qaC)r;}d_y2oF;Agfo81F#k{NqGU0g1w4BI4aV +aWYnq_{V(p+zOa6AFpueEwMChUotP&>?<VQ~y&#BzNu%AbI%@Ev +)pL}MZaQ=GBRnuh!2Beme9rlbHed9Kdl27%PT6;?<5L$*{-~XGYJa3@AcJLGOA1fklk~9P9}^ce^mSS +MFS`ANbEnUk5<`~IA&Zy82`HU3=O$0gWCY>*(ApeXxU+Th#UAZonB(H!4~u?FW?OEnZg=l|48faauq4 +lqI{0@*ajWP(2~r! +i&+d(tj2ag$i|9U%8Vv}na^5UF7V{tr+~0|XQR000O8HkM{dy8r9j3K9SScsl?99smFUaA|NaUv_0~W +N&gWWNCABY-wUIb7OL8aCCDnaCxm8{d3#4^>_Uhh%_ImMxyhv^*Udb%uVe(?cBr{J6*OU<3S`OBc@0W +0Bx(cKYs54APJC^?Q~^wiAVwu@B0hjgv`I2lcY#_zBwY5TF-yLC!@(|Lf#bRPVmi@BH^1UdGYM|%Q^h +>7xF95>5g2`ue^+4*cne)E?G)cLDUr^=R0*(>+p-Xf{IpX{F5ivpZB}eHKu>*J$o +iLH^)IPJm8j-!Cr1WmloZ>ND$>3HT-SUvBPmlXQ8CL6vu5O9ygcO@v-1R#MI{m@>#1vw#M-x&;#vJ7# +98l3CMb|UBO3-l@9+)4R$@0p?%XiA1w5{1BhtUj6qZzqt}-?wJdbZ!els17kaFPgqGmw^L(lZHFphJ& +WpNCn;-61Wk3XDU#=jiDU7ns?T*8DP2u44?zT0L5)|Mcw#rS#jY)oo;7vm3?r}H1iz&Q{K&5E2Y#ycj +*uV0ORq*Ai&D%%m5pUcI#68Vu#uGp5!`IaZ5kf026VC@l=+vw)`m~3gz*G#Hk-NjywNCRq_0yntYdFb +Gu@rab707lC~9E;?NqgW~d*nIrqdw7XdF2)BEeyUvwKW};d^2PY@)d-+Jna_!VyxwVLrDd7%#Av4kjt +X2-u>VwCXr+`9na>d~&=;we`MP){jW0DdHAwu8P=R8Wo(p~hDzIVFdwilL3W%Js8gz3S=IEA@DK;rI-*PCb=ejU0X1hB%xUbmJK(^tTh)B +tc&N2+;VjV&tM4XF6cgrXmq-Ke{mU~E#IER?@vId1k>gONQJB5-;*cNccq4W`})(f`Cp?i--VyZXZ0o +eZugGQK?d<^1gU^28|RWRHUaG;56}3m6&4TMBj%2S?gsTKk=$)$3;|gE?rY*$oS~MOv +ZltgAek9yL}L$7W_6+Y!^|72E?#05LLea@PW*$n8)=KRA~b4$?uz=H}D0FGfP@ki6cl-Lkp +Cj-yD4iL|V&+boj#^ZKT!7KAHaMtxCvo0EsCg`1MkJO?;gn3sTks`7sbT^&2^5)7NuKGk>@H!YA}9Jk +G*NiNjtI;ta_}~?Dp6LT8MVs3T96mf_a2c_fg2XlE!YC0b|620&I59AKv)N#=c9TGy93FIWI95pI2vi +aVflZmLNUkhhV4(QK%kQW`~ji0uUd{z!0BBxKpJA=Eh8G7p#yEJoq_WcD&gH4yzh-OA9aG=(QOHX4l5 +}RS3Ez2A!K}*a$#&zmK1!1e)CoHWb6RoIXDWMBIL0L;F0qSz*O9F!0q;`fY4XJ0m57Sf#ayM2rUe}Rf +4In$M9@M9FBqzTrkFf2&f>v=Bp5kBJxJI^u0?@?^F8V!ge(94h +3i$@r+R`lV&~~-lw{z)$%VGkUqGQmSggK62()XA$3|es#0-R_EP*_Zfa)ZIQBXN!;F9Rf#3U`vGaLmj +zd=BjEa7V#AZ6sOVCKY%fj%PK1?f2O(WpnLHg&7X@`|l!zLAb|j(N_}^-7klXBM{@RC7jvotX9L-!x6 +*jDq(7Wt59cQL%w6DHXd|RQci*LnXL*2tq}Fy8KT +kiUnNovbW&8#D5eb7K>qhxXrZ6}$vf?PhoSeVASbmH;R06_!(1L`8j4*QQxLFpG-vv{Yy! +ZSoy`cfx)KCI?{{>*;E_@%E8!9->b*u!u!VqIi@G<&lFzpPCjodI=m>+=<%k5BW3)&CU&(SS?teIpnnP(nHrd)GA=H2}DDajv@1HVix!lJln0;_*(EhG%NSg4cAjyaxtKyg8+@ ++dTvp3dwM^Sn&H3<@D*9sV{pf<){d#ZeuiX1Y%yB}G%&_mZw48L8*L>Nq{f$dvqLOWA*ICElP5aso!+ +~gmtNJEj;Te-a#tvr#;nW!V26?G5~M`a@WoWC;N(fr5sXfZ!gm)ZLSPlSe5Zd51R7HkMo^09kSK-0Dd +m|d))6gofH~Seg>euvzQ`BMn%~7HNx07proC9%=(rK<-l2F+$Uh2kO$9a)blCWNQ=DMP%^6EgfpW(4> +JGIH0+Nh+aBM++w}&jqkZs9hLXFA*4N=%s>t<<|-1jodOnRmzH62;kF*dlj2xez8KoZrxo +s^xAwH{0ate*FS3Q7)qe^G}j|_Ms{+`8ot(C%RR`5D)8#MaJ}VOMpkeG(G)Xoff=`xO{|T6Tuo?E$L +vA0-aj~Tt7J0e~MF-P$D}yr5VII!d19oX*a3#TUr9908W#jP<@*Xd1;*ieL9hzp&u-`=ml*okx3d#`x +VyfW=5yU~dH7p6yd?EWTwp-6Tdh)b>;vRWEQ2M(hf_GtL@|WjFBrTA@3i&6sa|F61&l6qxXBvOiBTM( ++)D=}GTQMFMBVEb>f<~v3*zM45uxMBuPINH~hk+g*xR^REhNUQS(>(#_odMq^U7KQ>&}0N4pr5b;(F#0HCA6rQ@Z>$X~ltpW#vCaqP!UgB#(MH;|>{@LvHL(cL2&w7+j +UmupSpy-%>rCDWW^n*&^GBG?5(>hi3$uTyh3u;=XWz< +WXZ>a&RTPo$yX=c6V0wlgUl4;ONk=+0kZ$GoyG8UkF+EaL!SF;a!66nQ6q6Vjux)BO?G>wbNH?*q+gf ++3Np69UPO?`|*KL(f6YKzDTcT|Ld!c7WrC<<$A525s3wz^swyf4L+olNhwi$+{?j~MK2a-{bY|Ak$U> +qt|=>Oa3jkh==tVa%#+pK?}=R2&^{dLPcyC#B>Gtx-H@@j>fwWcFyM*yoG#K4-Gu34SH_?@**pQM?IP +EoSbP-SoS20@$NyQ_7)n1e3jVfFNBv&>U($Tz0Rx(-yPMYbELCA%EZx>-LA1J&)+^m@{d0Mc#uNCklm +0(rfk9{R6!Ze@49Lo;?p5D4}&ep~mK|7~ryU0`h3Y|uqOuCELJD!=hEPN|}Zvt9$U@*DId9dtVKX=r^ +qD5@H40|L`W-Qt5hL+hcBe^DvZ0PGZ9elyr8d2e^ZQ>sTfOh~?1w~vP&$fD72%b@;v)dBK#pkv_ElK0 +-X?}7uV+YVsc_F-@EU_8;XaGJG7=JAT>khtq-H5K=X9k1?o-|$)!Vp~|a4*Gnrd?0gOKj>pCD=l0QM! +y||*Z$6!roaaZq?-`DCnR;Q0CNHeu^EHVz;G#^1bvF}O4p76>KXS*0WYjXt*)>;E|m-om^~VR7mOEd3 +))u?ZTR^X{2K~&ecv;baaxX7i5qwX*(wz_tBf+EhHrq+KqsbFj|c;9%QaWcMychu(|n9fJ)|B{Y&A4{{=;@ +<8c8CoA#^&rTYI?%HFqOym_J?Py}0IOiL%xp@dxUZX>ad!qIhAOpXXIyWB(X!t$APXzdgc#O0RdQXN8 +~aa$h<-I&~5iVMjPm+j!AtX1H7ECua7XnUjI-Y0|pYFc!?M9qsFcL1e^W?Co*2M>|A}??ED;zVu=yzU +ec^!V7FWIsiM>aTuTXneF3?WA>(hZ6Bb`jOw1Y9qcu;TOKt{y9Si0K|DxK5n;-Qy@*)rG0DE??+p+wA +-hrPWv_ug0pabZ4kfTwJ<>GvZ2%#B{8kV_(|EPIzmt(YpoeFII?$tk{to!_y$c+@{4&^!H9NNZc2&Eb +JroqA+_$YR_nl@l%IOD4!mLE?D~-ynN)9IR>jwbBJ&=cqufbp7J;H?+8r2+P2gucGnTHXIX`);8*ip7=r +`{SzW21w*4lZpyx~zGR{hSI-R*r;mD$L^9+l|(Slz7YVS%CG9uv`R$XK@_7i6tBtMMl6`E^{s9sIb&q +8r=~Kf^%VM}Fm +!eSMC7N7Beh3+Izd(6=j2clkW^WNTQefd#NgNQbwsLJrUKF5P`x@(vQVs9sYplH{5m+TeWt`%zsrjww +qC3oRJkox@bX-_?(udr69c)l*ep!O)}qzr4Uf0@5BDWfH9uTphfD?p;1FAc)hy81 +eb+-29{v;Ld=5}d*9`oY|F)tn4M-}tR|tmzwwxXru4a>bj~pX8o*Y68;U6n`LYf6Bi&@!D_~9YHr@cU +W<+t>{;OEA4@iCe~Z2>xjCigWORN3(4N0Q7FsUF1#7hU9s+Q#tuASmLAre#~L~j_sBzV_X~YOPTIP=> +BiY@!^jzS);4m5-Hf?Xs+32EhbyjDRdUT#REW*t4Sr}8N&L|0P;xx>+;r6rJ4cbc#-`!UHP6$5vq$>F +pD3YOBKdESkDr@EJwF_2+`j+w9B}9fTA!>0E`0yz&N-|>1+GWGeBqC73+1-e79yH6J;m3!dOP`LvzvT +HMT#{920^-#MOG=?_D-(ph7pr4Lr&8HlD3E7@cXBXDt^Q2PqiR-5m0#4K)k6bl+hVq#q|P<=6j1sG~Y +Jh(QHWkJNcLWI>CGa6?OnkBYbX(k;w0yo7uhZ7AEApT4g*T$LCA3F0fJM92&;*woaqn)5?2`TKC)@9- +wYEZlhMGj!G)%)(3cGwrBk{Zm&4x1Gq!T@oYT60&C-Vz|h+)AHH$B=X3~80r8>^bxK$5Y`t2}SBkB3cw7uvwICmx*{I>!r=F6!|YqML4ShanI5 +((d_4Cgosb=1(rI@@(ftfMp8k$=E2;khP)h>@6aWAK2mm&gW=Zv!kPN)4000170RS5S003}la4%nWWo +~3|axY|Qb98KJVlQ+vGA?C!W$e9sU=&5RINb9{(n%)i0TK-Fh(VE{q60`A0u#uDAOr_uX2@a!t{BIWR +SeyLy95$@M$>6#)xCOmy;pZ-(OrD(E~_H=0B0CXz$XtEqp%v?s5NxdATb#rq`z~jdnO5r>%HIa_x<&u +>8`Fi^*VLx)Hzk>)Rg_~LB_-|j2Zq^m0@-<+CK;L@Bb0_%N+MgCi7zII~VUVEPUtU8@;!$$z5H0*KM^ +o|04I6oA12yE19~tPjgC7Jg^}CckIcF7R-lt`MSIXZu% +awU>STF+hlTz2x>=yjWhmtu80SEHorB-Y=JU;&E+^(U5LPW0+UqS*CW$f7^!S^3!a$Ms%smFcpQC{SB5dNFc+r2`zh#)27?@&Uo^<^HG9NTB@3Rb3e +~4j5{}|H0K5uNGoesl=!LQ_RUC+b2X_ww0?5lY&OfJK$xUzQT&HT-fG)eFKWcb@N7!K-nT&aOE`>w_FL#eG>?g3FtG!oiR)Qz0(oaFN5Am}v1C)NJOUgOS +U6ZSRo!6oxqvftutp)?-tHCA}_gPf{qeh;c0@ccjxCfe=6HWsH(j?W|ywW5H5`>}2!9!Qv^s%6oFl@+ +vGr?3nEFI-ts+v)872SB!!(q`F?Iu9JKTwb%~WTeyeAF!LSEVv?(>s?X?AgLSaK`_qgc6<*i_7#Yj5Gl$eq5V%3$65r=F7Q +*!&igGxn(531vosAK>hnJ-j&c +NN$7Bq`55i&$ai-6lAy*)0De?!16EDS01wa_ao^;8p*>${%RhCG(bnx_+*s9ctt#k~honM9wD{&xp`K +Q6Bb4tV9p@-sg2l7c>Sao1jck4SNl2)%58+cv?JaA*R!ow!6N`Egijtk3mCNbSy5&wa+X_Q2Uds54J_ +FPTN!#ahG-dDhiJ5)`T!Z6WV-w5tZ_YQyHdMw|vy +7^bq4=H#`UEaddQP2oQ51u`nGc0=M+kBf|)LFr%O^CrsErUIC+TRrN6#FeBAMyAD_*Fm%W5wby<-)V_ +n@`0AfDwr7161%j-Rpb>dF^?vCwM2urZm5H4DbBkI`K+2f6Y2us9LzD<&yV!6E^;s((HaN|769v2KcHlA#1;y4BSAk*>-ZJa0pwa)DK@h;;_UH0< +1%5KEmR}U8t-id2=3vKi?{*E7OJd~l1-;7O=tDw+zv>71d^|XWNv42WhGWW0c&>aHS-q%tdy)|Vq{S~ +GR<@fzyVkwveP0>0q#=0jFNFfN1kaQFGQA*ZHBJbh%?6XW?!z7WVb2ayOuy3AbcAPyOI} +NZB&L}ZAa4d+S0{lqh8&Y(hh{w_{tvSUTzof{RX_$1(W(x_>m?9d8N45BvUOL=@7ZH(vYUp~pUL1Y^=H!flp_27+HVx2d@?>9ew +wZ0G!A)rFwk`lt4L<@d)yu$>y4g65}ZuuvMppgWaaeVP3pznx}N +UDwx7VuG1Fjn}I4&x=>;~n}aucmeTjLWs*`b}zLxOxzO_J}}emW#cXukZoR^B;f@209Q`Zs~D+ +lbO&UDbS9X3>7?%Z?EGkoru1TX|V|CT@{Z#4zV)LA@0iwmKuQ}np$e?M}+SD@S&L8DbotRmmmd>;}oP +L`2Ae_WlAtX7bN6BLf{xA>^&4S?KcH6pC`y)&AQ2M7`w#4dbfRrxLyeDQ7I9rluXne9rQ{2avVV1ZV% +aKMiw>2LtX_UcsrU0y|!l{O$)|Tk*EpQXrIM<@M~DO$7BO}s8U_KEhJa5_D`T9dy9}o{*uKoEzEG>jK +l>&TS)m8KnNDP6v4{(F$_e(EG>MPtR8|(91A%!$Qqh62XZP0U}df;unW1QI#HajFX-%ad9g9%!Qpi2S +GK@PVRe_2)l_(}O3wBcC$7&bNu{j5oxBS9Be)9h2T{B-BCB-85m;a+!-xSAeZ#AzDdeeP0N$+RdFvTm +=ByyUkfC(7wn)i97-r~43OR&O3@ksi7+6Va;;(=vz+W)U#6ql@5pqZh=m@^CWbsH4%Tyetn=hioe~dTF5yb=xovXj03vt%Q0;+JS&r +)5Gv>~U6;WNrfI+TIz>uJErZjg@vfiKY)vO^`SoSYa10OXHDaqKJ%Qo*vS2RmBjtDV_lHj>iDBzv^3KH!)3C_G0DV;|X<~D(Tg` +R>b_WoX7|W^~E{3cw^2EhRyq1Pi4IV(87BQ6T(z5jDpgp&TYsVGR3UeA(Skz6bnjeOa(t{Pn#6OSDS~wf181tjb%;eV{#DbET%3bo1eUfOR +{#ztv^+lvpgln?dW4KjB%qBnRYsC8fpLh1x4{YyU@3kq*Qc%OyaRd?DBPEpoH7_SRZZZ|rrw-2JaYgh +!o@vXKxYv#(&7%Qu=0vkY~y{7--pUS8KL*L6k%0A;W0s=Z09>tgtEF9So{WIJsCaBZp_?g2$1tfa^h3 +`FwxD(Sm0+1|R&C`ath-gV1>>%?Fw0d>C8MMC*;W$RZsVOAQPvHaG{oxMt)o4l0=AQ-zutm|d?@p4&A +b;cSE(7gpJuq0U?Na!Wo;@gBh%^=mO +!r303rPF#ZiD-$IYNoX$+to&64LKZ)%K*$lUprvzAx*H3Bag;)NioHV^S5amUXQCEUteMC}LAaqEX`^2; +>rdgYwIQDhq|-k4tr|hx``hX&}z-c@~Fomxo-IucLgF80+JQ%Ll_}lH~p3r{lt(CYvmeAd6FyUS`ZiO +m|V}LU~llr^xPP&HFTcH*ZZ#pl>F2GR73YMEelU{E28Oq({S5z +^xfYfe}aGTF!^F6@aSjZ%>`SZ-t2`Epc$TzTZYyO8)Raf_36F*Zvib&6*$QHjC7ycr-yZ9P&J&eX7`@ +uCKwL{SU%A71|rxi>xD&glK{fUz}j{ugQO=D=Zry||()`V@Xv#bhCtA +2#g`pG|_Af}?$eiAWzWgJ@cb!VZ2+!d3MLB)OAmIyLph1}(dCiDjE8SZRq`;aKi%V%s +-joz)ix3PTY)7VWRrKKbXQJ_s~H`#d^<$ +_D5<4zGE3g#2{NH|!eR?|7|!tSP@-`zi^Cc5iP)tWV17Ob!?q=|h7K1u8|3Lnw__vrn1>x^fdE_!|+3 +rebvg;>uZEO^BCRFDd@$QAvS9%LCNy+tYRF0qLG3^$nxv2Hm=LNM5F(tauK$#qVrk~1Cn_f%!5TrwIJ +PZx1~2TiCM4P2(i!k}D7JGvS>IzCn73n}Iv@WrK7$qkjlU8b?;Qe$2-4Slx(mgU-*9p9^^X>m388UW-UqR90Tvg9f@x2HgeIiB-97_IS}TBg>?- +>ia+)OE73Py*)ljBynF-;BT^NJA{KAQs(1?XkVm&pfrm?-mWRUnv|M5int5fGo^G;$n*!rTjzce_kKh)fO7}Y^f|$28#sMSB=)z}qCqBn?;By+ +mXJI=$Yc^+Ft@z3?)7O|b8kuyQz9zKN*A?%>>#+xtSOAfo%+_8G-{!3he8UQ`)q?R<^=(Nig){^Fw*? +co_5uc5k~-m;YGy($NnM#m^q__A#7Kcw$g-u822np&vsdE)IG_kX>Ql23xuEB)!kw$f4mlv`#f`>71O +VO-FbxRf#j>?sN|20K!Yi@zShvJR7BRNN7kS(W#hlw?dqi%j2Gc7`vIDBF1X@OT^eZ{ +vvW;Qev`Po`ifOdNZ(_R}FwuCBt@1EbBEWsjsFQaHjPdwS6Glfg(?heJ|%f3emxPHob!98-W9ye>8k^ +J40fuoO|FuP$J(Xl3dQ;jl7Vg^GizkxgyEouMkNZe=&&KTwsd<*?Wu&yv^W9#}H%UTh?d<-szu2U&G} +n;@|>*q4AFBvlOfo!J?1SL?ah?kn*Hn@n3zwM8&s^=`GOzC~DARU5pXn{k2TRNU-jIR6v4iIBTo8<&Dve9UKZd!K|sCq?u0)sG9{p03!O+z$jJSSSdIEJ@zyAcvc*F440H> +0)ylGy|3mrO3y6chTg<1CypK*=AYZFVZFm*}Vt1)UF0)AM&C(2MJu9srEtOiS?&7n0wACBizr*3zXF(+}Ojeg +7K?cEMoi!3fT;c0Y<@{k;Z1}L}qW{``KvB?=!k2n7vWZy;JCpf(*$f~KOJe31!oG=V3Aiw<@3euGS(c +6_#2|!epwX8F@Lk-e$i~TG=yx}&gQ-kCuEoY^1((=*b4OTV2{G=mAw~+f_Dn?|AmYG8m+eRSgY|R25t +1FKh101m7D_6lP3`$^1Iaz2&@%$;|SB!6AknRHdV71KwsVhj?n8ulcfhp%SeoeWP6llY3#^7;$KGKTM +$KS{2j)VBz{WflnZhj<2U%?LgdVD{91@_U`Qz82L%WLp@?14b%Ib`7GV3}D8;+AR)tq+-}6d;&3zgG& +jV*n^6i0zWgtPn%n(vjeoK1PmdOfpED?b6sJkgqiW5{uqx&viI_WxdO7?<^zDimD=yg!OmNMZi4WJ|l +U9o}7VJHjt54>k8DgEV|>gK|6ObRjF;~Yh!H=Idoo!1m3 +Vr{x=dfjQW!AvI}aOia9;z}=flGorZO{pHZRYL!H>#uMyE7fUuNF*2MS*2BZ)*$@lx0Sm+lx(hc_S)WXNw*S^z=4nIL?}69 +L1*X6t(Y$&mvyd`GB8-V944>)dDY^0J^K2SL$@#FHLPtKmg$j`o1H47Gs@tvtf=&5$cxOT_iUCK4n-)EJaoieB&vA_Y)CqE +!q6;x^ngw{JY&6AxmxfN;^-mR}w89q-=9^8cIqFNK&vaLbxsw1M(k_` +9*V`IhU&H@RgF@;uxb;p7TfqL--I7%%PvUB?13c-w2hUd(05HFFu}WgKJtD25M +Z`^pDUe8&APKxPDrHTM*mlObjo!tpk!kA)7|_LGT31?utUsH-jNYOA_Bi_FqAjw%WR-H?pCa2GF90mZ +QL@i?wyEl&WvC{|C*+fI7)B}*Ns$bxiwAucr +)3RC@=;3Ex1FmZ+~3MzdYlB^$WUSniG6MBhPi$0zzuGg=+}saxVO#lquu1nByDs1uXpLxb=2Wv2nA;x3ay*4^h_EsC_2^<5CY+#W#sqvLCqyMry~RAo9O}XNwUC97@xc8aL^?3b!f +T} +DAdoZe!JP87YcLnspTZ)p=7HlqJ<3_i~d+p5-vkCxqIUsFMF+3{en7w%oC#OI$M)jcBVz&3yo)ilo#( +I`l^P{{NBHL$aHCcQN-KNOKSR5T+uJ<6yBJZ66w#<@0BMMM6w1pf6Nef|!I6rQeY%PUglhgV~+=UnGE +DRSwX-=Kii0k__Tr||9a;sEzFmR0bs?+=^d>lo|;(e*=xK!6Feq)BP{cP<5vgJw;eN*_a;A570EoLLX +hA1gTJ))I|QSl-Qs*Vdu1l`mSHZ9D~ +NTdxDO^#im~08Q@5r82XX5iW0`y~ga?Hb{Hp-aXCfm?=w_yY^QUMLY>74nGsHqX#esycp(PD{z3}Ax(*el4? +--D17O<$-U4SnSsdXkqc(hmZ;_3CCdm+hPUbD3+t4Kd9fAy@9uI%Hy4?_XvZgO2bA8(0^7V~;=z9mC~ +16nn6?Ibrj4MZO_J1xk0_UFIrGaWkZ-3$ffe^~A!TwDehc6@BLL647;YUJ%<0#|9IiExga{7-$I~KZw&KH42K8BK|!ORtir(cRdPBj`HY(2NDxkJi3Z?x`s#`-1alQVD?A +!<^rQ!5lGU1`0Jr_Au1cDrWz9gHistU<_7QcgO2~cwr04+Xmf0V6m8lX}Q5hnj^&?UURkHCUJ#{sb4X +!UR+^gwD!R>Hw_wh6(e)dB-6XlDEpz>!@woADmMI4NtS8IrUs5}tVPj@!L9n6P&o0xa5bfNhYfsLcbF +B@0cF3_kXtDCh+mA8Tf(uV@E6IZsoIeyW|opckZfWaOUzVt3YJ(BDih~NtzIo*MQ6-BPj&X%&u;j&?U +;NDi=b#jnMmc+vF_yhMdo_t?&cD6L*ST@m`N~0ko{hp_{q>7B@Mw^l93b670;Tu&0Ywpbj)F;pe9|*msKB#;ErOqw%B=W-N>f0KSiEW +2};Oi1xfWle{079sXvK|%6$Z8pgyi@)|@NjNosa#@k{%F;_}Dni?fN^I2 +R0;h%liKT`0Jyxr?6Booir&N_57=ax1kV#X`eWvA7U7NiSb@RF#`;8~c^*wiafBmN>+p+r7M#1qko|NzfpjCL}S^ +2Smx^c1xRQ!9bbkqEjQtd#ZMc^QxKXeZ#ww=R0_Y^$f6W>yoLq@U248&V4N0wFf%QGOfrMd}9&y~tmZ +n6P|5#%UH2;+K6EV%#0XSvA;D{f^!0QFS%v{sG^p{ZUq-4eET0xoO61zh4bhg5eQIx`15Bh?Mw=@19* +bj;wZWriZu4c)k@4Vj+p@Eob4H;zlW)Y2Um`Kt;lSYe2ZT(9a#9}7rVMikVsLRNR!h~sgUo+Ox3ogj( +y65tz5iQ>1Zve4GQOL8l%BoZHhp;RDX4KN72Np>D5r%q}k@f<^?MFTw|pwc2x-s_D(OXAG$ip|Ki#{| +vaIUpp>pz}?gBDUltCY%M9lDrK^fG01nj)-{_5QW>5vRW>WLE>=l!8jO5nAgL^jb;O%;Zcux$W{LYLE +%yct?e56RwM!UI!+;%%V;2zijacIr5@=||Dt+XVyRH4zJb7TvjU&RI|GO2gH9Zpd1yv-tY8ev1xxLuvOuVqW{+$bua>p1PXW2KF-I8!d0gdWGF|JCn3H5@mc +rp#bbI4XvsCW!kVuU5gikkY%3`2BuYH|p&vLCjRgrSJ%1XsPSUjvSi>(EMMHp%eMV|q%KsTQv*CC^|l +1+)s^azyP1>ewmZR^K=cI_m2#@uqZcex*EWjB>nb8u^69x1`9W{ejq$xH}IGZdGch)&QG}XQ>QA +j{wnG6)qw}^*j>@i+OUC(SguCqneW`kd>VJ3fqF#2joA$q8*{isjj-^oM%aLTB{^(s)a-3CJ&~g7-7M +)#clUOjZe@bk$@jWE2!%QHlpE4!Bb@_Nzj!)G1=sk&A|4dW490qa3?`WN>@QQO1;nr +In$moF|&x_hsqgk=|xPSbhVH|9$m(uSX5%RCy_Kr9FDzDq_ZSej^&skw%f7VC}fGHtBp{JK}nNYDA{4 +g#O7+;@c1_q_<1EU6DkyK0>3tB0*{6XoI~V(uq$=2hw1SOovScWVV*Xi1T=eXDyWz^wUy+cc{a@N#KZ +myBogUdx6-*@BNcD#yTD|B??j^QwI}}FWdG}Vll?b|%u +yLjxc9^lPWJRIFoz%NpX~EVz!I{n$YTqI5N6Q0kqJju>coB*) +NkC&#vbr`$UCX-3$`mRc-IlD;Kbm@Re#8sf7WnVQL$(sjy~1M9QB!ndpDAu~r55hv^FXD(7(PG;a0h2 +n4S)=RZ%3Ov#NfNvdD7-F-Van0?djo5yl6~zs@(96UA-_rhlC +eaa4~vq}92dIgL30#oKTO=gPW8QdO7z2;VJ!LMmvPa8JVS%5j*L5@LE3H%t|TQ3ptGD*oH-Gv^NpF4WzO_&cagb +Nj_|*1nx9mEI*qTTyFaVcGHZQZAJdpFbHTX=eUrbrI5R1YcgbAS!psQ>?4-c68(EoiXgLtnsDVyM6DC +m5OA&M=1kyyEM(m1k1=`=$1=PQKu%W+1qqAa=i(U2}s}o*Z2$6WXi1E{VOpp#ZcB2EKW9eGx +eOm9hwF;8##X#Zn+%b)9USMLQ*|zR!sG|XXUC+v>1v=Rlvcz?5&)5h@qzsO@^5xIsf0_V`c_#X*A6(0 +vtylqB2-lseS*NoM4dwt(nrruo04)O=*e%_*Z_RI<3%VC!t1T>flxjX_}2SgaA7Pup_5*LsLuntok}N +jeoh>lp&`ym8p#jlarJQ_Nq=$UNPYb7$;RT>ihkCYAQpc%>X|a8dTu4a`%=1*(up_iq>}rcG9RMH5s7 +sawOl`i30$g43tCG4rNjP9NW8pgf!Cbv +hz&%gm8gUtIJ=?Oh9m0uRw_X}oItKyKk?&7PVOB3cc-gtEqDBv4Xn}*3;0-nvhKw-s(H)d> +y2NmwJ-lWtI!%ZLX+j3w+_C!7qQAyv6^O`>xt&&{P9?^mGj>5LSw^X(B2Fa}Ys9)(8vnd6V`+_KLQ07 +trC{JR1SZHS&Be)=rYVz-yIu3th*J+_{;)7`1sktF(=2KH_OjNA=D<**z9HXUctr!+fAIfdI(JjE=w8Te++s@Q2A6>^|So +LWV~>1 +)VM^whKUEe0`a5W404;WpM3#+MadZ;GFp!cilieCk;!I8B2)fpAd4@(4W5{Q{4hyo +bBRWL1g2-MN9xdso*nC{{Rf?YnV3V+AlR&Dcb@R~HtQdw>vHM}RUsn|T$52_d(fEa*TJzZ5|KuwV%&1 +`-NEOQn(=5P6ggdA78Xm1arRIiTBsfMOg%ZR{P(^gWz@7n;jZh{jDHE1qDv$(^7;HPl#CRO)JS(0f#@ +VVO$E(_Lh7@X6vmkSR}{Z(g4+4{0>22JWShVu5vkv5S;`tINHDDK$BwCdW@M>W$}FbXc@wHIH0}BpD1 +oIlvmDow|g*NS~ebxt~4>eZEbfuhA#kW{?>m9FPY-!S9FR8|W;b)PIs7$4ekszk55RFnpREcn(i|R;) +gUlkwVgDhoPVt)n2x&hYTX!tF6hWnDJ_4f{{jTz-PspbKoyYJIU15Ce-@?Nz2<^p%CC` +Q{q{$Hmt%v@Wy^f(%u6zo7iZu3158JyELbLl#c+q0M3Q{Q>a0 +m3MU5A|=1M8B8Qsdl-2J(bN6icDSPGCqL>u6?kz$zQZ3o5Y4vNVg6vI0ZlhG)!0H{MG +x%~AaG4azy!txVJOVOsx#0B0&^VA^1v(Y_?usQmCB5a8M3BnCDjMFRn+eDHvDnq#b%p_s5*kaZOS>Dt +u?Z&p)`?%n${t|nr?M?J&5F^vEzax~!?Rhg;%pTNeAvzn9q#f9^=v2MfO9vNA^kTDVu@nc~xgma@0L%7K_bG +k6L{#S;nLJq7udfxg(-qipz(?%h#(IB2e2=pJ)Ar>LTO3q(`@7p>5EPUU^`KRMs;QUwOdp+mB6yHlZ| +5!Xl*@5(MF&*1r0B4wsdugwWTzUiD!)OX1-Bt4A0fF@4Xd1c0I##)7mB2aw*u+p!5>>%$_1VUt)YHzZcCt%T1qjDM)y%SrayDsEVgmA&ENR!1!x`R_uE}C7|gS=kGJ4ACQo~Wo0tjtYV~0pDmP&Py@`j(Mgj4_Qr +$M4ej2PALjhnJ8ZuKi83wq2P)#Ha69Mqy1c0W>5jU=08ViiDO;%2dExG}#OG(f)WVg$uW)SVBYIP$9xYrpeh|ql2qv)(Upexrxc5URNlkqBv6^UNE$O3dLie_VHW2?Cb3 +XM2?6X@{W%565$_}jQ&@1!d8?feEYb|-(O7`qD;a==SBt-fAEh1PgfzxY-9$e`ol3Ne7GW|_X^)xBiZ +0!>2yIjE9a3AwzbMh+lFp*J|I1*PPE97Sg(B`{8lc4)Pwp*%t(dcrt|IDebwMdC4wEo{_cJTF&}Iz3a +z3+Zuc2N-yQ@>e9EI!g;>0BFsl_=F+#XKoX2(W2-$c?xKFW3t948Yo{u6S9qkGA*E?xe8ri$Zn9^nUN@L(3G#9Q@Axe1ka5>{0PHBsbN*Pojv?&>r`731F?MIimJmsVZb>8 +q4>2ZxT0iqXc*Mau4=^HhFwiQXJ5D0C&Ti&6e;&)|tC7y@1B@SE@T6Jinzh4{hccbm-fSWq}?b{7Jb)q~f5ejMOr~1aG5#qtM^v(-R +}wRA$39dZ+ly^-g^cYd3YBhc$6Gaw3Kwrta89u@nM;r)XTIOjr0OQzI1v{2_jr9NbJ>j`OAIV6^tT9~ +7K5MxC&Dnf^LjygYb=%fT#KcUqh9{zkpX)7`XidATs5$6dQdP(FJG*K +O;3Q44-fwoy}X>Pz41a?cX!_at^4@lM9J-kFQ|2wABk(-du|+b(SpZKo-Eh*uU%Ux2Ko#_YIi;E#u$W +jbb=e*?Icxk+e=zE?a5!IjO>C6J_ei-$N4>jP +m#?`?|j-yyz#c6b23S*>s6t3w0v?LQyipB~b{niF8;_Cr4n-^u0Y;Ttgh58c@jG;6-U;vc~8sY7x6R+ +kULFFlLk$8KZ!k?LBONV}<4+@oE4BPFA@U1A<^%Ye)@%%En~lf?B_laMDnvI=vP{$m86U3f9RG7HD!E +2WTeJZcblJ{q5DeNLUDumreucR(F7|bGT=ow$rY>|_7qt83^8O0zKkc>_Lkaj8p1Rb +USrlS$Dk{NiwztWQf#5YS2jky(yOwfi;Y0Cn9ABln@IT_;=rOM>Dh$TI@fb##Rro +;s8#il}D+_-U|8BzXv4uN~`gah&GYenD?-cmPtw(k3N*}8pu9P;eR8p{mi}9m+#WH%}R22~mH>0&I;M +zJ99W8aGIs2jYt9RQ)VQ*ssz8Na3qM>k}}@h?g-fN%dnj%Tyq& +Wy`B0>NKp7TtuNTNV#Ks+>DZWH*Pn&ST3`c+d^(BMgCTvKz06O{590!`sw +_N^gl=;FC^Vxfd1fweo|!5nmnf$eDgUAgxKB^_oKo>x4s4)RHQ0{LMdz}TqW +W1k@u#u1m*Pp(IC|%SC0JsppD|uA%biLF+Pp(IpcBxCLs3wMhR&yz8*iEe9XcSK#J<1?@)fj=EHq)k% +v63};22-X?FqR6_!1&}v`%I;B}4bL&Z#N=JykM@R|hdc0wh&fN}_IH8jwAu*~lQqFoQLkN&Pt4>SYKE ++)FhKaGbXtb9)NLAPE8m{<eVdUZm?WWBuIRu0^!heixBX+fLAkD`z{XoarUcnii0SW6k6gG5Et}l#{D}Kd%;73`yCr9r`T?4JHu +E!FQT55*7rz&8lsc_rWZdXh?o0se$Is^K$d=W~+CJfM(80PAkWf(u +rl?zZJv|dv*SAs4%b*2Bzxfc&@x8lnm7MyPs(N!ik2^WQlG9Rh)B1J?-EKwOt&LgI#?{UD;i1;t=KB_ +)BGyvk4M9P^4DyeU;;#K`y=wMBC?LMF%|ae-Aul3;RM(5wsgk7>x)yoyDAH#j=l(&7uQJfhU+2~!)oGmr@B_n<;{ +$CuM(v%|>{i6hA~WdyN~)VocnM-{-B8o}5WgHTjb0m@aF$^`=m-9ngLoJQDS*Z{MB`TnAeFky`(xCEA +P<*77iryrfF+Z)uQ#=?soK|T+Sg3&>#y3EL;HF{`zqGHexrSrYF~cs>!v~+CX85v5rD3FAL^qaZ}j3l +H_(OSnoz|xs5oMLiiec!7-0P7(MBorLoJSKNgG!|-b*|r6J5ydh1BFGt3h>Tz}q6uW&|iio<3mU#xl6 +|@b!ymZ#N0>faFYv@8b{Xs6p654r^i6GmzNu?x|EV^&CCJion{4el^}30l=dk^_Jp$E5U&~>YYhHI<$ +|e^n(uRQLzvq7){f_~Bw90x}?^6n4@8-u{%g1!op5VhhfOmL$wrbF%|@5JGL$rVviZt@_O2{9 +#<-=`?hyM{( +?K!v=J?fQP-N?7q><-EndTl~X%_hhXJGENy-A>H#>V3C_MhRkD +_aGN!~Q=*QHJx8T!SPL~l5+|(2)310Fr^2Gu?X=dr_=SGJp}tx|hG4^zDoH@Y8+q9tQSd59u=3;?!>GNPz%l2Tp5 +?vlF-T0xkS-Ib$@e);)(VDa-L6Sf8Tb8L-X44{a#xgpj$RtP8!}#j+0b)AT6Mlv>xhEtgN#(pe>ao0U +(|KCI+-=qUdd(5gKmTufH(qso^wmdx9S$`alcNM>TwnCJ>k#*qsMPi$YrfsWU&sv+>^C|DD^F-17G-L}!=g-O5qdhAJQs!~Sw4uzeTgfI&?>C535ffE +p>d(n{JnHY4i+2p>T~NG%g)u`dakswOcgeDhwC~2HlQ9rkda^QGnPa7N59scCG2N~5#-&ypmNSYO^bI +yqOns|qbfB&Xl2k8rxjxld`PzxpzkAV#Jbjz!Z5kz(IuGj>O##uAj0pZ7E#m5y00lL#BA?&s!;z#sQ- +1GqA$}MFY2rUCp(W{(jp|KmRS{3s?!QYcu9*r%oi6Taq*WI;??H-_(HsQfqogaFEc|mTQeh!ZFcq@`p^FN2zpsLUghg8?j1s>PzStw(;BwUE|T4VWzluO)g4|9QgbT^|G?!G(m0 +*{z+ZKfDAugw=@NnBtV9z*SM_Sw`@&Oa7UZMeWZ1KNMKt9`)EjnSd#1!wel02PzyeRbCKz5LrA8Zlym +Zc=NHaQb#dC6X=DS-NIG=+-%?Gx~3ufjff2qOXR%vU%Eejn0Vh$O_K%b{b1*hy +iO$7ckXU`L|OdvRYF(LamUvPMf${tM88E%%w0$&vgPSFpH{_V(Ru&APL80Ot`EGoA7| +6byUc~zX=liKy!GcLAjaS6w@!vYa1xD%fL5VK=FhXW%BD(dWZT8>e~5<1$Av2W)pYP>HX>N@m-F@b{F ++$9e67QxmX=&gb%WdEmZD7lPW*nYa>^&fn&l*GICGC%3}9!Rize5^hO(Mn9P6T#^a^3PV%3JsL#K+K8 +q2G@;~8rn(bn&s5V24{cIg8hH|-`or+QJS)98@cVpPkld~pp(V6$uNoqR-@fie%b)8r!Su +gBYYI<;>Q#=Y0m3551*G#ljS(=cZe=G@Qig#VlK!}WE&Of?VsdrZ7}^|^jS>_XQlbpICa!MzgbDQ;y9wDZ3LrJ@T5~Q{@)9%n~@jf0lm|dX#xyj}AhQ4stsU-|JDB_6XW_7~6G_kI;7Q%?~TXd`!O^gh;o +Ft^JldRt6Pu_{4n}7R$(n;_-Uzj2gR9V4+}fuTl8|BDtMu`QfTT_gO#|{hlrZuN6}?(-dx)L9gff#&% +f0psO^8dw8$BcaQ~DVuQ1ErU_bFlvVELcHW(AJM0M-vv^zQC>UU!scU7+3(~?o3tn@v;RRToFVgP0D1Lz@^BFy`9HpL}*lfMG`b8JE&`OzpH{4 +^!HV9UEu|-~DDOk)3NwjN`^2M*#gHoiV>j4?-TEI$k&C(r~ip8#_l~t9?Kr2-bqP|{=+_LZ$;9e6zmX +RInVVs83J&c1&3MfqjkWcLM@VYyIjd(w(b?Cb`TYEwG>i3dnV8U)S}Twq3u)P?Fn9N>q9Rm92{HefkyhK1$?#~@flIm7!Q9e +{6SclOFpEs8vx>=I&LrDh`W8*#4Y$xD%5p1$w#z{?SiXeu~Zhz5s`5GH6lsoFD~VWk~eoHxXdpgsJy% +f+q4BA%J4nd(JlB;()M6ix8MU-aU2Mj)^J!KY$36(&A|DO(yib&A;o7RPFNfYob9+_@%#O_#e(~%;#r +nYgC6lo;#spWO1@!*RQA3!Zw15)v*a6AN@WLI=B?a}qCvg3eI*> +jUrJcL!9$CZDQ|LmZq90QgrEMuIyZe_Vz(N?L90A$K_t#~ya&-xg0RSRxW(6qtL8X`O6ZAzA%2c>x{Z +6V^=6~CZ?-W)Y()VJpJe=aU}Yep8H`27>w?Gt#PMX!1kF96`~rCh!*|7>uc8KksYp`2s^OO#vTyVBme +rgRteb#Gl`lq05yJyOfLaMN-{M8CdccyKOAjJ309?Dcvqe^ppDx`I=8=~PQA7eIxgI~E^E$zrqFt$wh +THpa3$50EoM=jSo_8D>hteoqWmsQFRadMGKgV=Kg2K6B7|?~#W +}$z^9HVsmZYTGM@L0!eGsEJ(E3puaxxAS>VgI34z!=6SplQ$~w1dCLxB|jVq7WE}U=Mte_J +)}!3dHtrQ_^Tu^D`cm|?E!p{-l%52Ef$W()n0NEq0YOH?u&KN9q+&~&TmB)Sx9%pc72XNsPO^rKT!uI +y6NOnk9xOZ!d5Iq{Q$oorr)`V@AdRMFaEuC@+kUqDpv0btwfBQh_e_Uav9Mm6*R4R1sMp-&vqfbVo;9 +Z%_$&IO%5F6Ct_px5y7(Ki+vUlt`_?YF7*iBr_=3>83fSwt@!g%ifs$F#qK2h<#hjyAFm#ioE?~VOP- +#>X(=qK;+UvTqy51+E0sjrQQF2tB+h2-*P)G$u$y-XCHW5 +(G9$5fuP_e4(R#D22{{bsnmc4SwS@PxoV{1>-&~QSE^{^W+ck +BKJ$FMKZ~AEAQvxF5|R+LpU6k^58`hn;AQ<CCWYMw;E#cZRq&#A2{43{Z +;KEf-z!W+uFC>b~&ze)n_iGWp}*aa%U7+%5S#^15W@Gtx9D{yHsQZc*N(josBg5?$VB541!_z +JOSUMLsa~b2PJ?L7!9LSx{%CXXt-T#*=no9GUfZ^pPZae@|eeWxM89Cnv{ECHl&Pqcu|nllDUhO$%q_ +84nyhEj^wGWi|$9!?XUhkx!~WZ4fR4BJ4SYr=4R++jh+W;*ITz;=K@zj)Ahfi)WZ~c@D35!X4*dWKl) +OO-2vbZ-#snjUG+i#VO``&c7KxNaPEYuvXa)6qIHK1G!Ku_i)%Ho7AZ(@<}zDIfVCq;e{h5}FxAhQMS*3TQ_6U6O?MXpYa(at|~4LtNlC;F(S7@{T+TTz@(Zw_F3GKS#ye)F +Q5*!SLBluBnX`U5#bmi7RF>=qA+VQWkJ~!Y=aGc(aqF(X&}L^>#-M`#PBS8;f!n+ +tKGXn~uhP<^xEnYVRJfT&;bLy5&2~WS15Afe=cSD?N;|NBQV?s_0hg#Wj;xyrNUpI{ByoZHSPw1KsJD +~9+?TP`CDC+p{UG4cv>h{OJFqptbqZ*G+`XsIL9!%@;`b(A#ps +lyni_8)SmmLy@AvF +x!+AZMhdo6KntkG@-mwAQI<0rhE?TZ4Kx1`0(gsQ2LjqZ-t?BD|IVF8+7NS-Og +oydcX~z~9qDL_IUCx7InhN|-GLD5)ES9lvo)NGPZd)lrg;aKFVZ!H5mt%2DGYywFR8kKPC+4yeDO@ez +U}L0(6vyRtxwNy;j>b?I^Gv#<_=I@X&dWjjHG55dE`$tKmHym`Rg;9)!=?;fJ_^bPbbAP?XK8r@?Ve8 ++sLfmZKx#dduD)DUagjwc%J!DE64>p*p&WOA9?zxS>>(HzmOH=ov{H{kVl_Rl>G727qo&bdnRtBw=19 +C(_{7S$3AsFo#@jrB0oK_FIxupWhhzIUlWIY_~?RtNTz*wx12mTX+R&6p$}J=ldC3aMw8}4^u#G$AA0 +DFS-iEKp*rmdG87wD)-JK+yKO&ae#k!^@7O1k68o`>yXRUQZn;xNTOd9|{1r%9DIlsCl9gHFW%QoLjZ +;8yY+}?hi~JT@iI-nGS#g#sWQwyV37q`a_St07e)@Yb%%*>!=|Ga~?3GgDSAP5ikG$v3o$ryi?c9%f< +WUbk%_HwmAjXk%f5z{}&gmX`U;jBF);#oQG%Vf~H!ObfT)#)&%>z909(&{eqDNjgG8Ek-kJ?X5J2d-x +%|QAb5CgsPq`_W!FV%-WPk80YK`i8sP%8J5pKXJ99~&m-YRzd8*s%W_JYGtv9N?+9=0UV +}iu>wOKfX9d_Yc5vX9CC3FZ+GB>?ZU2lSZ> +w;S3UN^u6kcxz*X-bgI)ESFYK!K>;PB2KMZiy`;VXCs(07Fb=51=UG<#0t6rh*sy9t{)w@D>)tjKZ>W +#q`JVm`N#HXkuLXaBUYtDN2T=XN(dUxzQ&sp!0^PTnP14Q)I0nU0msk2_izj4;v7I)U$d~T4lUitqw& +U$Bmg0tR%xU=5q0nU0a=+1iNf9b6E#N+|adQYDFsm^-$e9u{Lrsk|S?I$_wO~tNgLm!=ZzPH}v=;j?A +68F}dPQCTU$G!FNSD>l4-V2Q8t+yV%^(Ikoy?>qWt*7z0f8(jQcbMj>cm2Qj)QcnNr+e!C6TnS<^1PV +r>5ZnI@2RIdt^I(*9(v6DA9K|k`j-K&dQY4i?5c+~{d8A7I!{&VXZw9uz2BYtpStSN;(p9kFAnhUUG? +_S-q7|0apBh8^myG(Z&}<;Z_fZXJ%qb}o8C0)riTC*cGDX&z)kO>|Gk^usKDV(7g0C8Aw8|)VdlsE^m +Od~4;}RaKiN@l(NNt{Pa}+kqaLE--#hBv((kCZ^m~qaj`=m>3?}ZW_wE1QQxE6i|3y!|-<|srPd&2x0 +-ky(`TdZm-pKFbeC2#kJ*;Q2r=EOX;Xmf7hhBHoQ;$05#Xa@ViI#fmHD5ZwQx9X&Q?K#-miBwyXds0 +P1iOAv#6Hh=@0a(Zei)q3oW0+{!~zax(tQr*KKMHfe;>nN9>lvFb??2!i}l@7$r+QKR*xI>26FKjKkHUH>cOs)Q@Lm#>YvgVNX7&tODA50B@ZosPkbCG+ +o4dmA$(H}tG}Zh5JJE)Sd_>a%L!bpF=^E`lI$U)Eju;@Q9HO=|!I@N9kUMp45QO`MSDVF8L +8En%-;X{|qa8i?M=dpr4as?2s%TS2klz1F)L_;s)tWq51w1ZSw2?a@o&NaTN23!;pmqfe{hwL7q>!IIG)7rA{GZW4 +1l_sd~vqZu!%*=PxWYE2IZH(H;4_Su)wVqV;50pR?1U&oA1S%yZd;|8H8c;6U$tWM)th+8D|EU%6$wW +E^;DYc$pfSkdpy4I{_v!Jh2gI*MFdMOeb{Yf|!4tq;&S5x3?0BsInL@vy+DZ$6Tfe7xU{oG3?`~G#q^ +TQ5T@Zk(h_vJ1jf7(emF`DKYKnL)Lgrh!2U26#jdhxEjwPqL8ji4_2TL6ud@E4)VAs%9326__79>`Qq +?3W{RD%Jsd2Lezjl>!Z?KzWF_%}%Ta`FUpj!sId5rp-xMtTF_ddNxMoViXkAxH%aSrld4JMg!Q_*Oet +28e0PGP|P3b4K1%GVPw!strNH7# +!MN7jG%bHArm +?)P_KJY=Qzdk)=F9c%9sGUW()r5C456n|R|I%W$M?CMOzU+_Q&M!bwXG^G%&x@*5|P{}!z)_8zyP@^> +LMTKu?3vl49L)y-;8)ERHHjg$bFzQ-}qBAr&ceL9@4!j5z9-f1nbiXo7Yb*s7gu4&tOnu$gP~;KRe}r +$EGW`cQe>2L5FO|SdIS|DI`vJw=`y$;0gJSMDFhvsDf`4by>DVawO(ke1a5?wVEWAAmP}bH|-vOOsi| +u2eG{Zc5Z0!lTj)kQgJtq&sz^TqQv6&U?+RRWwZB%Z7wzbT~+jkjq``Q18y*B}fx_JM`hf7vP!PLYnS +H+|7Sngvv76BCkLs9UIP!>hGTy{}Q0bMb1#q`suX=!R%S!sE6si5Xj=8dYXI_PjjpHC(<^dQ&wE~Wl5Vvb#9#s2_{yhjdpgQn~JJXLxneaCEA79ku +Z=P-@_Gp)Fdp|FRe9qXSk=%ih+I9sIu78`1qn$Y*;)cJ_wUrNh{01N#RmENwV%K!HnnONy(P*!(t=Km +4W$=?xjCL;&(yobZ{^I8f)w=tkc#gO)%PdwGMj_qE)M7gz2_=a7TPLSVoLj<1))5(~=PFky+*z>rc+Q +YOC-G2NTR{u^_>-)BO3TRq&{iJkTO$QHSM;9%lZ0Yg73Bz(uRIq1{@vW*g!y1md0Hmdw9YTD17`LPN; +@`VyLRbq|~=pq_nQij{2rvKY$a!Y6G9;yIi3r?F?&%E`_4b?`ltZ&*{XU1qP#Lfdz^wj=oiP*S)8Ih7 +x?Jib9l6Go>byu54wvdR9XqVAWUsdWqlmi0FScF+f*+=+qwWZdLjVdB0d7UG0W!u+bpqFYF>pDF@_@QEc15LTVFKgBmi6p~hJyvH)gxz1S!XY*cBrh8MYK6tHH$Jjcp73V4%{ZlL&?Nwv%)UsgfWHfc`wxt0N;(P +=fg+Wk!97uy;0a)0w_hGS_Oxy!782!$n#ne)^?!mqYX#gIWPm)^^4ZxkOE8(1I(K(kG$BFIwmnXYm<8qR9gr~BU=qj#euO8>eLuOqp((ob9)9lg +CfQPW&xRlB{TdVk6`%$U^h+p^W*OLs5^AM30$jzt2L(sobC5IgH9{Xv*ZKJl|P53AeO@LSyTchgL)}s +DmGNFm|+*;Ds`CpPMOmaSIWwYBc!oxpL*WUVCJqNz#hFSR$tioW)B?Pj;xEn|o;}CiL&iw|dphQ5xk#bfP>2{WkE=g89Wk +`jQn+au{QzW(o +bKE}SJ_6^Rbr#vEVuIVO%T&Ie~#Z3=kQy)Ui{XG-{a!IK```k6nu#st$)3vf~E3b? +5=dMGOI9<{tW}0iDOWfK}mnhPbbcq^!T_T*JOMFOtUgqllcne9B`1*QDlL&ILc4tTLak~k +_=W0*+O~h1&1 +dZCSMo)9iH22a2DupDW*V?8+ev#RxR!-MsXAg3IS*76bQMJrwS63|(3A>tW0!{5R&Bc!XrhCkLo#lvB +MpZcoT;nJC`bxfQ;R`il)kDHpKJ3$6BdZXh(wXZoEGGB4-oi57eQq~l8RHE$oSTLmDm4OO=n-AOdN^7p;Ubp$B`>tc<7}+LSgt4b|KTzZw)(h1l +{FBN{QKCuKL1McM2@*5h%QmAWSG#7G2|p=>M5NU9R0Tp4S=T1SmP(Po)vr( +{u01T87>@e1D?<{-aqvdfVJBG+`MuC1f9fFXA-5}f$R8n_)?^uTp@;MmddQcA9#ZrVWt+h`#_@7nfCe +(fhAh>hHRh^l!gHq!?V~6{p?w4=XO=lZ`zShEr@f+66KG#`Rv1XPw-o6&vvHB6bzF+YtZyvQHJ0Sssx +KTc>7(9bqA6A4O0h=spmtx8O6nLa`(|Ggdc&adjgrRj^kOWHA?ZIDR{B(3rSr{bNkU_I*~T8^dR_!Uj8uD#;R=ufjp28S#!z&FPzZ|TQtdT{ndWUk6e`1$_95(4 +hLJ*LD9VS(8zi;Y)T;J3LC$5-XJGtvMY(thwc%s6g2m@9SJZ|F#quFSNeV+zyHe>(3d5OLC)JE3PCbA +E5JAlqL+SnCb#WCtxHT0T!&0R`buYzxUE4Nxk}Nu@e4ssy7TUw;+NIU)WIrleMT00p$x5fzH%EbD +0zMTtU-Xyb?uX3-@pT12=*izqlm)*^z4^3B(Uj!q0W<E=5) +!&ZrEy4oXqo7^j1LQ4;+~RVjWL;v_G=LwDD_i&n5H^RbbJ}MMl1Q(HSp@D4+)K96Q{~jj-x^0eWXUp# +k>s-iYj59*bWL5*6EDiuL>oi^W?tOE!R1a>0RAqoujeMWc8@bvho8W`BQT8mTefQy+w!Vy-mm&f)&@f +nY^m+lLn>9YH3t@$htr%u3+b*gbwT*z8P^W+aQNoR(vkn!U3r#L@?{)zbn-X&0&AZ>TK$15xG=%n5>b +~w(NSy+NWXaXU*G0$7Y&hSs@0dlSSzk!T9w$Vx#Jun6B=n4!<`l?n<4mZHhTyimW#rutvuQyrg4BfNfYvADWoMT5?l>d_yi)!%g>@t<30w9Z9Cv$&)Wv +tCA=GUhR}T`3i6Ad4v*oE$h_8uVPH~z1AhgHucrgVr5gT?G8~(qDmabru}5*7;OuIL$ak3`o>=y+=3* +j^#aXd8gA4mm-Tk`{>11JXH>=A1`D%W6PjsOx3xB}!=iPuIO@gz;wxDV=V`rKBxxW|71?c9t*4LcU_B +~_dDj-kI)<#(U)*}a!j%{m;ryw^StV9|CSld*D++6wr4kp}iYsmFZnKp?81*|D^03MjFu9p^;UbJ`<7 +)BV{+5emO-^Ow&hddNWx+?oaOKlEV`q`J^ofhCwk?kdM!Y0(7|}WFvLc*FaFWoVOoo)(U+viFK@5m1- +(l%FX+EfEjY3E~C%(WvHMzM}T`pe%DRzqDvykT2gXPjGXSj-->)gw==)C;5Az6IPf#XEVOs6f*!o@{= +%X!h={0zpdfzA%5G3Fwgv<4G~rAWx{WHgn8aO-$$QMiol7&Eg=wzPQKagxD}Qt;n{`g&ghS>tT`JEg^|c3#lWN^}Ln +>8g`|Zif_o83S#A0A`>mm!Vm)0+^N{RI&OQHvOtkQDCX^-}1p-NlhK4&EqPuC!&7&<98tF%r{G5_dp{ +=r>)^Wij;OI3?DGy?AxpNF=ota3D;buwR58ScNdmU}(z@isBf-uK~Yu5vcGnNK@8?W0+(*G3&pZp+o= +y_n23^t#xeejXv1OVItuf+q7_7YuZmKgeOhKu1b;{vb#59w+l&k@x{y;?!x`!irE1<~=wr0-;{Eg<33 +yG4DYbTEe3}6c8Pk~g>bA_B2*ko*m9#!ZTZZQTDcCq>gu4yjZ +155Dc|+)Am6KBQAv+|N6@R($u+4?yiq3`-WGL&z>6!$evZJ6UKR{=>V9PYASd%LqVz6^(tF!3Y2YS@s +jI7BD5R)``F0@}+l8Y*b#?ZOllcNrcAtZDIqRqW2pN+I@(HFBln~5EVg#$-5p~mv%DNMoo@9EG*@nzE +WO|V4L8cp-Ze*&+RFUaSrgQzek;>>p`rS?NIf3;ZySf?ZL|EI^g?O)D5B6^L>Mqm$LdDQzTm|Y*?XuX +i(|oqL(&}mql0Tr%bT4)wi1NUX8b2ER=%aHvKVXU +FIefOSUt7Zr>U)jk!v^PdcKfzge#TTl&kP@@BAk60=RSpnpl$#^$GG`mE(Q?~4mm^WB>0=86x7FHw|MdmNcnTUhtG@E ++;Y+qwmD73yMJnOG2~q2Tg@5pCuUcj!z)8?NTMr`{5I_gD}4^mZq|3SFaX<<4TYd@{2x>^xb9R!ZvHpS5TK*#c^F_BhEutG71;tq9lfXg$aE3k8u#tHExW;KsC$5`(npG+~;GfLa~aib;PHct-HaB&;VOm$nX2aFoT?l=7L)ik-EW49=Ea)sB`uI0r& +pR=-PB7*Gpbirl9+DLz_y#dOGGy2wp62y#RyNhmzdq?J(^j8h#?imMB)hm5#p)y34@`nFLyoX&iZmzg +eCZ_{2co;s7VEtryA#{?M0q(@q`GgJ;q1P>L +fQmj~458SjJX%uL}Wan2={X5|S!UJF{4oSj|rvBUgU)xGMw&MEoWvD#Xa +?p$2mqRywJYe^}@ag(b!pmN+U6h;qL!ALCBF}ou~#C>*=1vVAHSpyo+ND9zmY)2BlRO0v~@kKclBj)p +MGDBij()H5GDMD3r-nx1oPNh9>8Pdk@r1le2TS~Wl@QzILwf57TGo_QDsvmq8y~tz-L@&4x#p;_WWHB +iAMj8897C~+8zQx(0T3tS(b{KUjBUHnZhFT9c7iaWH0gcY|TN^yC25ssx+7vj|+UGs7N~M~7ueBdpM_ +qC8ZyCiLjjbj-Olr%RZnBegQNG|&vU$x=jue;l&i9zDs@cI`e~l&BB%@5 +uo1J{k@L}N#4Cc9i ++SL~=yOdQ|-KvbXjPR7^f=7$G(7<8&I4;=JsM1jtT`}+ +HmYv>}gS9(nIgsq^SvIaFWSp0&xj5S&*Hy=QSpxcqW2r;N^+s>w>Hc&Dl%&odNoVkwy!bKf?YXGEE=~ +>@M$SdilTZ77HuCCKbB&`Rs5~Z86^^q-r?s|bP%T<^)1c64FFSAmTRD@gE5=c2kyF#X45e?bP?g1A#@ +VEoL&jY;u1^&wX5ySS9NFe2or`-KvU-4qN-H^83LrX!W7urFOFBna9A{dZ=wZCy603$I7CAy5P9h;2?`iVeI8|T(JmJp +Ns^o#GEQxBPEM|F!cA&%WpzzzGAI)RCQ*=T)!z_@bzZiPy&(qLQRVt`IB6@f*6&m6yQ6JKk<^V!z0Bz +OdY8vuL`rhHb%)y}S-%$_V0bk)5Dgt_r)UJD2rlSk&jp?8xIhgqXd}45qmBzYfeVNQ@WF0zQP^yL5w| +D%+t>Z1rnlDpsxh||-|^Cu#`nveBaPVACS0AUZSuX6jQYjDmpb*Oeyk-+Y@juK%ujB3bgTsD(eJcx>?5v)5Dr9%r@2sh3RRHh8buL6R&Ekz +c9V5eT3QD>LtuR)=t9ISlbBG-|8mJPF81O23u>f5v4H9dU+Hu)bT={wMsa}SkDM^u=OipCRmRMGs(JN +n8U4=!W?ORPnct^8-@9Z^;KbJSXT*il69#tv#m>nnQtus#-6$6TO`$!pOY=N?F5FYP}{ZGP*Lrks9g!L4xPY5e|8S7kO#T_En8N!MkIM!TYJum1NR< +TEFq_AET^b6}{LBFup2>OM!R?si37!9pmg%vj?Snm~9Z1A);S5U@%sMZ@eN_7iPX|nz%tZiWZQCK};J +teHrW?GL3s~Xll!s-R<2g2GL)(yhi2iCR1s)2Qxu=>OLgs=v~I#*c3V4WeXI#_dsH3rrR!a5k%k*PAu +33!Va9!ao93M)>Bv-%6`NLcR|*0HeOC#;Xa+FB&y`S3XVW@j8_X`*!zJM3t5zL+A;q<7Z3B*-q`NG>X +^OOotzKyuM&U8c(}?+cege{I0bmeK~Yb#SSlk^5Zi4Ydq()4B|oL2~J&b;*!jLM0cq)@73H(pz%z(z;~JF84|fwt*pzSQaVHFBd&^x!4UFZ(3ct- +xx{?#vQC{p3Z@OSU<8Jh_RN}hl7M6R<+LaeNmlr$7nJ(ct0w-frth5ar6lc0R^5L{` +yWWQa)cdga$3rbUl>qn7Zzlp&TI(e-*mP-BRdZ!dPx5GKMN#u4+>G|BgETqBkephS9 +d}tGI}m>BwQ$&9|-}9bn5C(>>M?&$+Y0mTJktZu6vOFN0k0HbERYT{J%z@g$u&m6vBQjAIK%jFkeu4Q +$@HtRd(FpymD04`lhE&`IXeCjx|eLb$hIf+w5d7nBtPP}KlHS*DYh7LgX7h&ER|!he%SDQMjS1h;N{VLA5LdAHO1BBSI_ +M9V98g{$lDGxyxKTPwlhvg$B-BAQ9^|M_xVpeeMnFWB}gF1B$!UHkl-bP?F1(XE)q2Pow05N!2}5eV+ +pbe<`O(Z@G-$Lg0lpF5ZrTxF)xBZf&_v`2xby2BY2bG7{Lz&R|p)hGUh?hjUbR<0KssA@dQSKg#=F#t +R#4wU?0I*f*OK*NV>a^pbtSPK@7oIf^3301j`6E5$q;7L2#MC@fyV=P!nhf1`wnWj3>w@m`<>OU>U&{ +f;|Ms3C<^QUO43it&!-N^y4sG(1Se~>|uhzzYvf +#e39D!VD~6Cf&L1}eFPiM2C}{^*v{_50$Bo!73qv%Ls%S(W)HC#;S!x^h@GBgOfuw6&=*hwIh4u-md6 +ZCPk;Sb2Fs>DM(-w;%Zx0GLg<;Az(9Wprxxk9V9kU%oN{`ICDWgM7|A!8avs74HR3~cLa`EAlnBw7Kb +~PkhlcslA6)xVI1-iUPfs}Ilc^@iqhAxz02~uVjtOJ~MH#{^Q>2?C!cHP;3dojDzXc+d@kHwka><}H4 +CI^3Cem9jg#hJ+B89rN;GZRY(kWgRdsGgWNAAt2B$V_KE`xq22!FktrpIoy +kwfjZsfeR+saI!DY^hQf6SKtWlnILM%AaF6%iy0$uN~E}1f=;E*mHPIz)pst%Fbe+26{R(iXjM}V`4o +48T)$H4*=umJ{%B?X9G8 +)A9rM^RnZxS^+UM|Hul>*8D_}$uGeOb`otiNf3!aKLK#_|jN8~K4tGyZ0N0k-_|MNJ{yLJDu7SSFE1V +=YH%i*+d~>G}T+{L@6LdNy5P-e2Y@=?yif)Z(r9`>>EZ)^{G|rk636+H;=lk6y4)aAV`?*5@N&gOnx+ +%rfkF=Fa`Sj~)Lso=%S3%VmicXAr4o*!qAef13W^;g|Y3Wr*@lms3~Lt!sxU(>%csy+uDdNsKvY>3Un +)O5AX3d(_y~&)wsP5E2if&T_=Nu^xUJyZX8Nbkpf~B85;=EVzY#HFo`VrlscvrBH;$+k-3q|(neL{!*MeOibIy +GJIM>2!S6lYj|p<}qja2=Ul$UObIPDnV@$?Qtz{Lgg6e~e|2IRkPSnU9j$hfJ&-dXWj;zcZPMqHP$&I +F0caw55o?U+ER1nK%8ZspRTQR|#YrPcc#2GX(9;vHNqp%ReQq`afO#{|7v`*6F1GZ4Pj#`@7qx9tSwo{W;#{UmXYhyMKR1KmOX#pZ%M?-(8a|(_R1lZt +1O~yP=D?H=UKto@1U{I`8rMWeY3|%NISdc*(z>eCp|Eo_%iVvgentc;UsBt6o~YX6?(btb6sf*Vn)C= +35&!zWvUo&0Ds<``-H>e7J4NlXzA|J>YmnZ+TPpFvweq-ojTv +wMcuVqcds5jd-cBm0q;J2`}NoO`1<(=1O^3%glfaWBO-O_<0oY3Gbc{Unmi>tCpRyDs-eJWDx5Zb#-n +4#j(a%mk=y$}Hgi@{@qe2B|8)NUcKJsQh>nRJIB0NO{DTRJLmo;RIxKnkh?LZkqee^Re|!J`Bg!9lpf +#6!#Li@QmhI2j*~`hU$PJ6^>`&O)7u(sF*xCPOXMfVpzR9u9zS+(W?L$*3J+Tq*L6V||u_5%EAXX{*u +^6%?h_C~*3kDkWdYH+2V@i6qN!SP3*`uBg+QT)2-Y&>J2aKUqJ)7?+!w +XUGvAsZyMT^a5kl1Y=gAJ}EEXlrP+*cPSZ`NGYaI)DOs;p2|kBWPxo%Jn=LsDVbL?yMzQfr+Fpw=9IK +?aUqGWw6v5eK%*&1Dw$8xS?^xKNvS0yuaQufl!RRb>fR;uODGm2v2N0&Nh+1=^!)s3`T6zaxxw@oN)j +bx$^x-MNwTy2*N0*4N%~XUTxQ6BOt|+K?)_yKM)GB%Fr#EMM$81IwL8r6@C+eIwy=TQL-P8Q;*v~ezP +!exxJ8MXk4dZr;E5N~?+lwAb5AMne6c#1EpUX4J^}XtvVr73UaWQ1$?frC1*pzN!dJmj!ArqM!9mGe$ +ydr}hAnR;UnNf^AEc8mRviptPAcIrP+(j4juj|`D6n%&6|=2eu?nTQ4yRD|?}=hASr;c+;Aa1xE@+YR +Q}R*LR?<__QR3r#E^v< +E{7pkKiL|AFbo^lY`>V8}D5vvSqh>89KXlk|pAb&mouX*CEAMYybNeTLeYr_RgQ=c@J7^%G3S^zqrKj +1jr8z%P?JFLipZIz68PWl(t34s~k%?7|rI=^5%wLtYMr7SUPvu2NqXpEsUxuyvK{sV2Q)Mpo`bb*9Mt +7XJdh(P-z*3XB;Ir!ndUal=5*l-VtbIv+Q0(-48Wf}$Qi)OcoSbyBQK=zWBBNJ7D&t<87HBr3XJInJLkJduC5#eRkD90^eQ+@JZGOyy|5X2QH +=KfaV~*0VmvSR`^y=D+=%S%~nyAa}w-k3Hac*A*jnu1QqA5q8Yb;Rr))!K%$ +;wpgbMlQd?!R+BCz!*fbA3p5rvSW&&i|ytsCn>J$yGBcYBBx$@=foGnoDT2YXjH{Gt=G)3D^2 +9h6e1^Thk3318 +7D?#?@m!C1-F3*y_jIHcX0^QWcal!|MFh7?~<^6R}-5vdJ-gjsJUg|sho4VcE|FQ0O_8;R_-~WJ}|Jy +xuY)_B+{)ZdHKm9;`|B43w`F?kfUlnru{9zVob+$5&B>U~?xDs~fd{)HY*}wJZJNp-msqcThf&a|$b+ +}pV>i@%t^kbNsiL-`W4boAv$oHSk}uLGs7*>03H>{x{nzTZ26qhZ*y_T<5kOdsL3FMxX!gb@})9y0mw& +-%j$l1Ibfip$sU3*eCWC>7KPAO$&Z+5H#({Z;WEyU>^>W; +a6f#$DpxDuQxdnOI`e>seJC=q^lKSsuQ3VBA6LaMhhUe8~$-YGnKscI&1lt~%Hjd<)n3rM7)(<3UWJr +1rA460tN}BO`r&!0SsD81Ni-*TTBgVrE{f(iNITh>F_=mOlB=VmJd=-w_{>;el# +d+|QaA&%vKU#k)XPzavFPl)0_E+&*kMCr6a0MpWn|NoCe|U@XrTW%!aI3zLTXe}obWj0I9Q*aFBT@)C +&Df*Lj1yFb4j3zHe?woi|k~=6$=n7#3@0aUZ}stJxij(Ky@&DMm|bsUW1yBVn;>#^=lgoH;S}aSKddR +N90ZtWMsrnpFk5g3P}ZT#N=%)%H#IlPH_b>`thcT6ZM89gT4S2{+(l7E}@&Ao%Lu##G`UElJm22qw`D +@?kA!dvSCtQ7HDT5W3FfS?&&tiEd~ +9xEmLV?}GNn|5)YMwJC`>y%&&J8@glHX&1ZN*P54Wvf?SSmK*k3!raVDwOIBJ9nGyQv(rGDPo`K2gseM`_vh9?ld(rY6rYP>;0-z0wYn5jH +kA2zE#HWpzQyp?CKsrEdOgAGkmKP{Kn9dnx}p+cuA +}gkt52*}-zMGJHziXio15=4e3Wc%q40-ZI`>is_WeuNm&V*a{i0REHk1UQp(h?bp=N0(CZF)VHT==z- +<-b2m`{-u6YHpuS>{*i*j$1Vf|&%<35*2!1d|9JAs9)JK%gTCCg?-Zo4|`eP0)$Jlb{WO2Z0-bioltG +5!70B>@tCs;55N;s}%k)nfnMT2sRO{Cs;}F6v1MGg#;x8*#wUeGJ3@1n+2qWlC(22l94)07*^8?XC@HxS5f(-=A37# +TYNHCosi6D#s&;OL{fg6AR$#(~KE3P=?L3uD<*PJ2xz9af6E^hw8W27b5=3BjKI?|Gfxk?Gu49m9GQCg;wX}&5jrS9T-lCQQkcR9oRZm-FroZ1DoVh_ue~({Cm{BAI_q8kGl8ik5YK&y7$vX4q_j +h@;q%@4d$=Dk| +8QUw+AM-n_}=rduKc(+iI4p^4}d2TI(S``&5O4vE)8{6cMsTkW)IGiM^e1%9CR5I=C0y!X<(ie4^2w> +pg;yju?)IB-C`i)n?5elGCZOyNIm=0(+cip=-O@6!&cY7jp&vsQX9M)(7VGBXeDmEUV6|7>!v#XF^6O +a6E$OtF-{^qzfHggqR*s!0D^BkH1K|N*w{D< +P@7HZ)4R)u``g^V{J}J+!9V`U4^ +?fZWeVh4C7SF4h1D|AVWCAE>E4R8k?rAL9JRh#fVx!W-eKe5;n%aN#Y=A4ymxZ-f`;J{*_4Mfw6a$(y +O>%a7#EYP(bvpLQyVBo^pm2TlYIB~0pQZUYW-IQw{!w}D~;Ucwv*oCsVA+zGmH@VSS~>wm`Q{{H?fF) +@)PCnvK>_al(}1Uw%*9LYCqez8}N+^~_oOzaKGT#E#4a|JTV(n-V|uAcYIn>=|k%gM=M27^KLAG2o7VyjG%?Da>(**isAW}X +MoAo7HhVnV`dmKS^TdPf@aie7_jbU`RDA!i4*MWufJv&zCX^6{>IsvGiL-} +R8>{6%NKrP-(BPE;>C;X>eZ`)SMWIYr|}_)u_nYcs>O^oBfe=)jlCr`U^Tyog>xS^h7V;k_*C{BU&1! +?jqG!NMCngi8;akJ;%g{=IK@w(_@gNPM2bJ1w_*z@{&I@{CdIFy_@7byb9V82QhXi7A5HO%6n_!Lf0g +3zr1(cD{&9-`4aNVC;#X1p3l#r~UHtw%8A~GZFrTI`i;awJSVVK0S7}V!MUC*YR*WC_Vf^c%jGvpz_) +kk1zqpa{D|YeQQ2cHbUqkUDD1IWvr?f6+QT!Pce*wi`LGj~m@Gm8JcU3?NglBg-?ldysNz&13a_ +-;5qgW{|2VLXE3kEQsJQv7Er{uYY=xm|qLk|nWr)MmS~#mt+UZ6G^DoPUwUG2Uu4<39O}51q&O)a8sX +d7JT#`xrm+tzCRI#Sf(T2^4=k#h*^`7g78*6#pHHzn$XmrTCQRl2a7_dy0S27QYXr@F1m-MJYT^DXgU +wc2f#xD20oyIQz|qv&%y{yE2utt4lb$wvn^zN4PD1M~dH<;zv^aVHAG?#V@4z^C|vPivKdj-$e0uQv5 +>{{}jcqwu`TlOQ0>q??~~xQv9A2zYoQap!g#x{#1&;kmA2g@pn-C6L#_IKWWlq?-U(9AZkFASl?#}5A +^Qg)va64K{ns00r7EhF){Jck&#g`X?=V5>ea(*(4g*03NdlyP5*IZiHS+`z8?Vw4N}Yg@rlu~@sX5#Y +;;uQfT*-S2+*TPx302(T%s;2J}NpUn&Jbmeto>XBhu=Sj8BYLo`D@b+okpEC#B%kt*g5GAjGHi5Osu4dr2EI}7Z_~Q +-gEDFf40tkOTY^#Y5?Ls23m&#Q^{4*u=Q__{7-6F7*PCf3F +8b`U4VU;$stI5(nPbp{*PM{`dFpo4};>qeT`fLwkeeIIQi6>(y0e4-#i=79n73J&X?xKlIO +H50QiRa}g1rW=3^Pj8x|z6%?THYwD!BCyqR$ +2M{m&`$tFD`KP4~hvS18=+Zsc7P&LK}Fq`1(&`18>eNifi +0UB2SYbQSr~nbH$B7qq1BHi)apMMCa+R}<^nT>JT|e8uD-Co(G|*AITs(mW +x*0UkJwXHA%d8dO#C-U6Hk9vUQ~6Q0gr8y?`S&z_U$l!)17Z@*=<{i?UEGJ_2U2_;#gC`>V<`SqivKv +pUqSKTruh3Qe%(0tUpeK!a?1a$a!Loe59rXLgIM}+FSL#wJbU!--yfHCbWnHb;Mt+;16@2?w!Dw{tbM +oMJ$m%&(Z7|4`~5BGy+haTy?RmDRvumYd-wNdow_~HyMO0q{aaChmMvP`*Qsld-u;_5>wTZ>pjP*Opu +bAx)|=woe^1L69X#7T(7(A#)vT$Di`)I~?j4+)bavww-KkBl?%w_Td*f0>%KrgxZ!d4}uHJ&aPV_(r)wQdn=_qz*EDVcqPBPqX +q1wSN48mihL>Fm&2-k5vB7&&z*w5a@qipGDVh1jAuKyd)-&v*yzSu(1wo8{TC{zGGk?YyCX;bQ1#Bsb +-QsT%N>M6uF45h^XsmDo9*X=IDqg*jOg8kJmzW8D)jXNJ)xNzZzUw--JM;d$1{`~XL-;??6<;#~Z(7g +2AsZ*ym?%liB;^5%m9TpbWU#7`ZP6u03P!4~k{7}~znD6P?vuAfQQC2PQGOp*CF=HYF=^=Z^FTecq37 +SXq9XodLAAkIj(|F2{9Xo~vD*o-a-*TFNbNCYtoW|L&tyXIl(R${y&pvyhva+&xz<>dMOsXer!D+{&E +i%9b_1a7Z*p)3o*m~0$VRLeF{Ay}y{$S_^?;ij5RNjZE4f-REprD|hz>n|}_<#KI$Natb-s6NHfA`&Y +1>WC(|2_ZVhadRi!-x5iBS%Cy#3300?&m1ZiyJp?oV9i9)>$O7#hT6Lhw}6DV-_u1ltgkhaKrW>?{@9 +l`IVKGjrR5RMcH}A#KiPQx_=e_OP4Njl4X{3@7_It%5c$7KmEijDk^N{eCW_2{?%7s2|THO1n#h(K7E +>>Jb6;QgC+$?<`E|G+~r??{k4Yp?mDGu{o{{6_;0`ccIk^RzIgAu@4ow%^16m_MCX&#-U0}RMTq-X@h +5o-dD#H?D*zf4K%FQ6{1rMBy8;bqQGjr^0oAz;?A-x>2mf8Wb}giO>_$8>7c}hLxl`Z|{y1^sgs6ivX +U>Rs;D|OsZCIE`j~*3(wt@P9iF!lZL7Y!M`9$E4I;8f`Q4cq7-sJWVypa{TylVFwN91Hf-+C#WOfw&fSj^(Q! +wJjl8Ke$M-UgnNWJ?^nV3u#Y)^?R(CDzjEa$wUthP1^?~aw=ePX@(Lgsei8MTs1HE{@I{%UTtN@&0=U +DDy8q^zZv?=OGDmp>U+@8F0p2Ko)bUH_IgdHUx$ZO0wTCzlI>5Q#KB8ea=MNAKJ-2b*?S0M{o#MQLBnF&V7l7+%Gx5Qp}1O7+9OLI1X&_jg(gC`{#27JzW1mPM=Gz1Xe>qOymlq>22dpMmeuE))~(0#EW8&W8{U@x=cFzm#Y +QKg@Z^rxFbsY72dKa^8E#U&o*N;w3$L^a!AOScG(}{__g3(=GvoQPsgeAdJe@#d^beem_>S|Tr# +Vjq4PVLanRq5lY0vwm_KZHM=XR+*_x(_6)70Z0xE=mf&kOzi{ku_rJ{S0dPa4tzz6W17q(h+vybeD4_ +P{3o%Cs=P+7!-TD2Na=;2BrN`6!u&q;EM-Ae;t&W!IiTgWR6`p--YdwFmV{U5SP+?@E0uJ+m9bzgxF% +HvXqE9^?Ei^?~+_@j$5yv$F%%4qG2 +u3u*xXmUvPo*N2-YiE9a@-OYIqbQvAuf_6!=7_6!=7_KZHM_Xi@Gs}1o-JHz-wa+VE1g8~idXsnGWwB +XrV9Kzq88Oq;$RLftTPBavT^WQK2#J~JQq9KiF81p01VAr1G<@OwPRO*w0Kb6L3rBCWbG<5%<(SAwbP +xAf3fPjE*B%{m){^%EBf@eSjWFCbUxM8eSMhlYmsL|rI=_6od#8*o=>LEn%59`hRXn;5Gww&B@6Cz!uSG;A&k`lKZ}QGDT)0epT|G&fI-=EWH?++rHdzxnd8put|o=qJks!4Sx8AbY5u=;vdc?8mKM2Lo~c4w`cT8t4tAmg +&~4JmmkTW%GL2FvZJ_#XqZPd%pn?P5e;}6$`}tHZM^>h{=^G{|B0{Xf|hyn=JECG*9&^?h7N@m#I+uI +hwq#l#4Ct~4~PcQo{0wZNlJTONqy3CLnMDTU&o&$8Ws@^3y6kN;-lGman+~jlcMZojCZOV@Be|n!v9* +WwkL1^e)H$gx6#m$jyutE<3=q%Q@MF14Ttef(Cp3`m;KLi8j@6j@8)nw9#-UI_^{_c+e+pD!PmIOf)po&)n{5k8)bPcyT55oxE4CU +OX)=jjvt1mSbElC@A1YqmeIMxKOm~ufP6U^gED+8lwexV{AZQ1z8C4DCPrr(4G&yY~rB#zN$=+Y-Y+dj4`x9Pv>7@VPR#7iHW +npKg8=xXx<;NdGqG=)P_0v@#)j2b7~VD?+-rsppX$h`sgFU55OI`qK*{4QtAWrf%h=afn0~WKzl%&7V +Vkp!M;7e+Mqoj*!m*mz~}FVc|t-$o?5zesaOX=-f~;!B_$<1B_)M-@7|r?fB*fQWNU#7@Ic$J2hgBEL +s|gfDJ5<6t)H$K&p#~H(fBOM7#N>lpB2rwJ~@$}{A3Hi^84>cslM-e{o%Rip5t@p&b_o`$r3(i&Ya&z +j~>mlv$I9H)4Wpf5@$Ql+j;Z|3PGGyDRh +a^S^!UvBz!#&(zdZ0cg_-4G%o<0G~E(ny3ei8Oqv@LI>~#{>qv!<_0j)9?(Y69vZfHjM?^c56qw0UtE +7f+XDX+FRhwAd-msOr}6ReeCEuVq8>m4@E03SJWq;N+afCdFXgEH^MTnzFx_#Sw|1P_5Wd)|Ufh4 +9pu{L9PBD{#}MO;2DB@pteCZvwzeSZ{_K@WPt2$z&4kH#$0+>vTHauU|h=5Aa8vhIBN>TT0tdOz;u<1 +Mn64W7M6pzCk!a-FCP73xPk;y)ZB^up5=(T(swH+qMZBP(D~Ur1l|bNKa4a2?+^;x7Ms#Bk)IAqs(Ck +-e?Etf8Y+;6#N5O8|?sX0Br*4q7NqAZ&EsQJv}{jRPQhC-n|=FkV5CFDVAS8=!DugL#Y-g7~N(l0hf2g)0L5RKhpo&cW0Slh^&zQ7-KqsS1@>wxdUODJ=+q35uf|F4&O +J^bzYAALl_F}5KsFtNrycI;UG?6c1b{z~w5*w%kQ1 +IA9sFX;ck2N;hqcA|_i=S10~9+dT6)C1np=cBJhKSpy3q1Paq|7qL>{@~p^@%ioe-M%k^zp`$Dat4jy +b>gF&BqLahX(1}YbO^Mmmr$kO{F$ngZ_+U&flrOt)hPEJoQT_NIrjwWZTIk1LGS8AA)WqZ(NvoPSTTME +fjh_t-O}|`6bQ|{mOadZjt{lcgVjp_2H{2&l-Duy0X_qSwEL${+k4ssLwr0{pR~f7&=qv8=>cdeg$jd +Sd0DQGUtbXyDMF97xdF}=FCZd>ZzwvfCFSF%pWj5qF={YguWWGEaVjU!H#E)wN76M9S`)KSks1n2W#@ +svHe;8m;=xpG?(TJla={B=DElhax}_Bne#wyvVWj28~vlC?}M&v)5XS?F6uoO8t{Y2-+u2y!#xiu6O3 +O!e}96%Vonk3n2Y2!!0|tGp7xWZH%&e(>3x;`1NQs~{SfqwVPt+$pC`LuOriN}I?1^y_WLkU|B!)!3& +x)hmga~xFsuh-Or!T^n>f;791FpzDO5aMULv>OLiZjN>%l&z&`E)?|Bqw<6ENg +lzq0QM6b~#Ck5)5$*Gb?iKpu)CT;hlXW!E^+Cr3e)QfZ^$$w^kbmrTr49A(zy;3+SwFG5P+E_@eBmcP +``7w7fFDyD@MEN`Gxd}Cv4NgW{O56*Fec$Sp1|o@}ps1rAs@L0RCz`Z{z?Z^-&S=$Wt{3Vwu+3AzoltY4ZrL4s%IWChlMOjcG_mcD%X@) +Wd1%=aOmgKpr0GJyHn>MWr*guV*vs;|py+b_!c1+)q1N1!V#(Z|@z0FQki4c)Ch|D$a^`sky%)c;Rb^ +aGd|U~Y#pLEnS2xNQB3fBa;U&=X*NdV{>azQ(RiK+j~6^<>2|4tNAVQodsePF=0v{+0O|+970qdp(Q2 +?hfVjXF8*!JKqvI7U=5c5)MVOuF>wfrT;_z7K;DNG0e*`}~(BHoKXkD9 +Vj34cIt|AQA$9^ggfZLf3s?oVA>`w +V(Ou;$_)^t(Em|sy_w5_E#)P*T^gSz-=NfN(!?sI2$gop +rfd$C~y4u@q0BI4WBY)idY9;v}lo7yHMsnD07%7e`RkY%A?_!j0b5_xX*~U?kNBD?b~+*wR7wZaF{xEswj8#2a1kF;Q?h +0S>Xp7Cu*~^vnLWS7m$pE54$nv|Fbz&7nBv1{o+ZJChdWa2W#{rMvUO73+UHqT(;>8Q0@vJDtkl}lg6 +q)s5~E|v|gn7`Oi%HWaH1CF3K7|(tvD-^2S;&co1vp&}*Q5*y|Bc2j~|N54fN#&~Ky91fDx~?0ACRos +L4Z|Ah+|rmtGHDn*%dqn?4o#EBERx3@PRGGvIrO-zES!M>`Q$6?YD6xX4|{STjY;C(f^pu= +E+D8Yw{TL(dR(7FmBv9p<_n7Kv+B|17(dD@-lQPklTrd<$ob>TmB8#u{C64c5OZVj>zgzONj@pCXs)!B@Pe)tb8_Gg{ztyA7R3n}=Mv4qp1&-mfw?& +5UYPq~-iLW-FwHw5!$772-srdRU=9O$@tvoqiZtw>>g&>)4%QJcXG8g+o-hU}dr&`^7c1l~$a|3WAZt +R_#e8G^@-mSI<{X0w57ghNQKN*O8+{nc;q>lRd`n5Vm`_4>hun^N1LjV%^n*km$=`Cmj>_fv=bsnyAo +hqruZFq=zciG^4_9swa{sIeHklj5ZbtdhxFGs1=;W|}Kp9K%Y%Gf4Kb<}*$`f;_(kzj`?M55$9{PIlD +e7|AuwkN1(NCi;zuEZ`e|yd#vHx?$^auIJ@4tfho0a(6w{I7+nzA1U{WfGS)Cc-gdt6}0SZ>e%2(Q$? +vL^{?VVp$%7>_VdK-%b+Y3whykB@#Dcq1K@1$0HA31c?alMom4Y>eHzckiwj7f+Gv`X~O;6zvPhV#}O8O~|N$pJWR&57YuSG?h@HD{*LNWBwIT62*@s>L~LP2`Yjamt +!23rjC3(C3WLo}r$elbu@--pypl4K0{3NuQHm&^IS*f+4RUFVom}LS9a2dO=RVLZ5Exob=qROnredMQ +VDq&1j +ujWz5h4ltLVdP68^7V*(hK5p3-hMv4c*kHtf&dNU?RL*W_oskzFS0C|Jy{a%e?>Xa}VoZ57)5%Hlpc0 +tiMv85lK-=Q86)bLk5i;DO>*g{?EN*5XOfm%`{P((V9m!<(f^J?V4kn*L<4!cK1#69q*g#`?&8@zOVW +2_5H^8cVADx&VG@8!~LfEE%IC8_qyL+zr%h%`2Fm6)z8WQ9{+a!_xlI=hxtF|zrz1R|9bw%cMg*Dzw*)!_wF`PJ=+mH|g8m4a790?w4M_}nE99Gyb0L>Pd_#jnhlQqx=7v5Rx* +&8(=*rObq3?x$9eN@3M(91-PTB!llXkAQT)RNnt5rPlmk}_F35XVO_%`!v7VX9bt@E81YKP&4?b6K9SIPV1s +6uCPy+ +9m@=GW7&uir?&Km1zwck$2kFY=%7zuNzG|Be1T{4e>lfVKex111E#74UU{b6~5$c7aiW6N%bq15X8h7 +g!S*859>}3|dIFbTH^;3dJ!f?p2)I{1g+--5kE{6lmhqe31HF^9YsvX!X+IAm?;zR;tg +S3+a83$;&bS7_hT?$Lg(J)ym!bq?zs<`WharVC3Bn-;b;ta-RM(fxD;6Ur*wr{Jb(t$9ZCg619Kz)`+ +)d>8qx_0#%i`~Mp7O5nyoJz-NFR1@@R@Rz~ULNS +?Ke$&+|TOd^Y%O@!9UPo9gYD&v!mQ`&{z5;nT&}-*>d{GT)WHANwBmJ?4Af*V*p@zctjNj`%h8Z{hhZZP5%}F-2?6q@CgVEhzN+Lc9#^88ju+ +cLB{9Le8$h{!}A%j9jhh&GW4>=IBDr{F+ZCLm4=H`uq9&h4{t!P4_GEo9 +Fkb-)DYqM3JX|XMZozLpw~rgeHgSS=s?i1pl_+?xIo-DKF?CEBvXrd!?%~;Q0mcM@!RM(#lK}hpMYTjTLKOSTn=yxaSDA(`=!2DBOu=_MUH5rHJ{^6!`}FqdBzMJ2I<_iid9-Ur*mo)VBY +>_Rg5KsVEG?DFn@spLxn;+bO_j?NQDj+I&_E-uwaD_9sJTx`Wx>11I{_z``qW{aNyk6x+Bc=g_<4xL*Eu!vSz{LOx_fvT} +q~GKANuSnZDUJyJGI|bHC@Fc`v*_-j(+-vy%Cic|TvWyYeJX>`xo>i{cs=x2QoM2xABA-Ms7jdR{-!k +M&bw^ppOgzshXC^n|%%?io)AePo`PSLrwDyY8Cz)_do*ywBdtOyv490WB2WWJ(4w?*^#}lS2pU${e*PXj6dtAeHq~NW{(Tb@{nUeD#!)3U^Qq5onR0QgR$tx>x`+ +CN~?leR87@Whw4OKs;HB6Af%R^iqnvp_r&=Tozz)f(GBrN_xk$xiAZ96La$<~;#S?7Fx7N7+)cM7ZPj +)=ZrAO(eRpVw{>VS~FT`zEegsj(5XU4E;?HR$h3^z*p^!!f5JxWvTX|`!B1$Nuf+}jLV-e4>gk?0af> +o@ei7m9zK^Hyrv5g(B58xBvhEegOa*0001RX>c!Jc4cm4Z*nhWX>)XJX<{#QHZ(3}cxB|h33wD$7BE_!PA8p +>>Ih8&h(u@LQqL3kcBni7C< +E^OEm==T#^n;>Obe+>Q2~Z=6mmZ@B7~O_()aV{oZrWJ@=e*&$%7Abp>bUI4&9fbe-esIQGxY{r7({_! +~5;eh~M5+NN{sO#V&hPMdRYW#0UX2k)u4^ZvZDJ0E!9K`HO9yYnjK2lDQHAkTCCjd}M!IQ#C4v$E11M +jhw={k0eG*4K8$|GM9q(KQ?1kKXlQ*CX`(K$n%iZ|#}~?|HwwxoZ~9yRNI4#@}b;zukD>Lf^l>w`>m9 +cc#9VcsXwNZ&SFU{lC6B9@oW<<}#AfIc_rq-e7U1qcM`{0@WJ)JxlR)W;!FEY08e*yyioj +gYWRdtZepg1n}{FtP25W*@SbJjtmy+Xw41ou*n#gj?(F|MGXws0a$IfFnUgP;?p`Fpd)h{$Lpb*26Z7 +OjZ!WHweW!FM$9;1dtCRZ`{B1iipBw&P%(8Jcg;)?eJOtiW)5-Z7E}qXa(lNqVxlDMUeM&y}#TAtmW$ +;a50VqOcPb8LC2 +Aeq1xmFC-I0_)fPuABXTz%omxt{POT@3pj1!BnK$W!fr4r)~fvv}?jvogkcG{*iophHB(bE@e47QA$;W% +P`}Bw}A2NH2j%n>8ksO60X%fi{XkS^IcSjR#$A<0XilN1hyy?O;VY+aWaI;7bLc4B1iTcBqeCQP8b8-opyW`ivJQxUbjPuE2Pd0>o5&TXoD2tp}Ppym%|AO5l~A^gcP$QINEUO +eV?HjppXVMA~XSZuMwB#YUeTkW~}sKXbnaOW1FTyB#e@D@J~n7?~g+-pmmXa +D%9c1RnKP4W4Zi3=z)5NmE-c4bYa8!OAc25fMe-zb-dAPe2ib>FrOVnVF|4bI-#{HXzjZ2jC?)d`nqB +`ztWNc$>lp8GfSpJUKS7N26X;2+pKK7xmr!DyGTV^{XnHT?B^|*AIa9X>;9H5M@SblF!Aco^l>mOZ5x +ruzy`Y1bo*Z*6QD_U^Eyb_#-I1>KDkY+lR4Ct(Zw +>nOV +bx8uh(#w@Y-tYY3%Pkk1xQ}s3I@^5Y3lCYR+pk@ZjTLL-O&n>LGa%Eq@F^+>lEm<1j*=u?ilNJHYPPH +xY2r%Mw{Vo3Vbr%q2d?3ddU4j2WQx;$h@`HL%ABgAEQzlwN|(|_JtDeVE56svfaFjtY+6{$rjab&gkAogefdcCfDcjJW3^&e`Bo+H}~-edJiUB&qzzw?uMW?AhuM3m6Mw9}SCoo8K +IX$Ml^P13_PShBXz?OC6O&*PcT)urTK4p9UzYPH4>!NK@zsQeNN>XI-fx+<{AfdBCcqTX +1%^sCNNEZ=^I_oq7yE2mC89=SS60{z!CXJ)dskC1+ssoM)_ +7N}4IOS-(&O-uOCkEU2ryBrrIqHsFpl#exg!w)2>1>FCu)xtg+h`u?D+rW(iY{cK&1%;Wwim!^D8a>_ +rT&rDk&9G+4dlF79<3^gY5_W#93xnHYUVJGTd~5~pp61H$_s>v@d6)bV}=+4w1QHk7TnlMag&<``&I# +Nr?A6q+~~d$Su`JM0On65+hH8CUCn{ER%274T=m5qSe#9oL#V5wjZ(I4A5!*^8F4-t+D=vXVlLbf^KN +U}sHK&=8l`MeiNLZkAwK;85puFfB2CT)*jHgIy@IyuClQfky?u^}!=1Hr9bG3m>Ys8bKy>@R*HH?5HH +4uxR(rh9uphW7JL*=Oav1=j@Q5OaknHNT9Ev|uhI%b_&F^rBtjIpb>o|!=#i1*`oeLMQp*wr9P2|13& +^0@B4Pla}P8kKe<~ca4UxR$MO2@A;!?4|~E+C+=_uvr5uEUrv?8!w%mIoasP8x)hFntswCEDw1{ZO1p +oI&-i#HUD_wX@U-kW2k*A`F>YcoAeLt*nz+@-$w7;$bttTA7FQGRZxYK|=^77 +N9)c|D3?Nft$P%~+$I~D?!X*HX4WW@UF!5@ZSYRZk)(uC@TR{1Z)nN!^N=p(TlJ3(Ruy +&u`CVvd|(J7+qcJNq^t19k9u~D+9{~S%By*%GUS+D2^z+M`-fYTSwvSC+U+bgaDAU&0W-yI7tMfyu8_mp7UYPo)yZZK6JQW)skWcpE#E-XTi{D-oOehm%WO +n<$ar#CU|Ty*dfIu)gAQ=#GVUr*+{4eEn~rRQ~z_ed>vx)S;+zEOM8T0;q0JBQU7YY!+W%k;_Bd(V>` +#4eDcC8fjYrz^u%|YzgKj;?rB@pM5Dgj``T$@Bl1gdmz{?pRcNe6BJJ#97o$l2#`4Ee#h-Iflzw*hJrB9b^e$wpRhVn%2g-novj4uwz7+d(X4oQ!|d<||@N=%pL!m7$wqYHGDCAX;JMJ& +3Mb_=QM`9duPh^TM!>CLdkQi$M=IR~c_@*IlpLfVZ0&q@INm2oh2qtC)wL~bT}Ib>0;&&?C_zXte&fZ +6kNbR3JbX$O3yB|02J{e19z*dZ6?`a`qw*beCCbX1N5t^sz- +07`?6BJljG8)3-MpN*pg#voe#AvcUe%)1d+1JWQA-MXRr`2L=&9-zh;6Sx^=vknXPLhMP&Whev($VMtrQ9)^o>I +4jg&5L{qur*%}j0Hws3c~;_1&WL77&p&yfTfkv#5z^s{lNOVQOGLrkce*QKS6;7AZFoLLIS@s!mr#gCKBJI&n#ydBp){BT=hOaF~*)jY(8#toWX`g+sKW%J&mZol+*Jot)w|R3ciU8K>gilkehzUpKI%GG)of!@qEy +m#Fo~8fbRBKtyM4qWU@_5uPRKJlk{~W>}4)<#bJQ+2(m8P4&AERw&<|Bc2K;R(OUuax*JV=&08Gnp`7 +YG6ny~#`H$EFi{qn6QroWPI9Ibg2HPiFM00Dr6D_n8k& +44TlXFqIt4&7b%@h2p +36C7sm;TsCIQC^>#dX$drIn!{ltd!#v13X1}q@Ex+*I%Vb^5Q3DbtFm&I_g1Ky=V&)Di-1yPJ|HMk#x +XPXyi$SDUTH!xJd~ee^2Cnujb$Q^(<6ldfL&Gt$tqahy_?% +dwd%IBDDiZ~zJq81NAF-Hb#(u7*z_ErF}5~BaC*iiGsSot*G#@ +q;J=CkV3&`llZi)X#t$T}Re;%STeb|PyxRH&|l_E)Hn45si*Uo`>~ifpJL%2- +8t@Rxu$QD67aZ!6TMzB1X!OQrZM$g4i(Hlk4Bryk)A1-!Z_iwYU3Fk^dpNe<+*A$SsQRABw4l)ieN@)Q=@zRG) +>0ug%an;qx4CsxA$Bkm#R!k1lu8WKfDu4_o2tFdaZK)oHcL235L-NsLMoVpWG7-$0aYL2*Ek?bZ)C7~ +fG6 +zc@Dm)I7lo@j<9|LGi-Ut_@1xZ7pz19%Le7x4BRB*hNjzZT1g@Bk5xFc0tA%e1L<^^Vfii=F`?>1RN6 +vQB5Bp_XJMJ@wb)s}YkFpLo7ESZo9hcz=HdCxK>pkvAP-psL=t_qoDUv?N_ +=I%5q+Vlt%1;FU^ALsSMW+TGRc$;*4GencA$pY1z)4H~(%dGebQ%i14 +_Ll`HNXKEsIG_1TKUs$dCrm$B0B}+j$PO&6(qzMtti+A9NJj-!6sDaE5FyWb$m={5$ZvTyPjWf873C} +d!RvY}5nyZ$6{*AouLYSpuzwMoE2lD7+Y79qxqMS4OPAn>Ywj^=oZ{l-VTg;1!q=GIF$vIj(F2eTm|FzBJ>K<-59$~rL{B&a +KQm3D(tG35hot+2{4IRVR%|MoAx+WSq^p!@u5`W~nX +w0K1GBrfhLXm(yGw+G2=Kk{2lZ`;>jhlr2eo{r9Qbe5gpi3n~#ZbgfK@PLr-zqJyM~(By^Kc8=1U!Uu +-~j`Xx}4Y2lp1+5Iyia^Sz{%ukRkDq +SBH6V#L>_d^=iz^V^G=&UnS-2YU4@OsK|1)rc|S5wNs%;k!!m=7*wDTxZ~RkQ*NJIzu5cpcqca5mGS8 +)s?PL6-Yz7ORn^vOkLrvSe%dkmW9#CDq7MavkeNI%{kYWV4;n6;F|q4<4lFgMJieHv*djD-{n~@IXs# +^0NxILl)g~w*?k7ki(Fi8}gp*3CSQi$od&-R{ab-^XLzbfb=hH`aq4) +O>nd)%0HlZTLF|8750KqI3`4!o#4b)M7lAA7cIPVc^d5IER|PZX4^KI+#B2*~;p=T`<`5<}zfH$(zXc +1DAwQxl^S!S7$;c_gP(zjc6V@SRiliNq{sc*yMMP}VTcQuaAXk;*vUqV2R?VsWWJ#Km9CypIZ1v`^bI}I!} +uxPzHFfUIC93HmK=MWPlkT>d{!WNh1GO{&a40~;2IACMPb+~!!_8=X}KT(px-5p383YKc-znB*G3gaL +TsG}QeorSDI0e+R@=|2RV#r&i+xNbO8!( +CK_D|p9=m13B-tZQk9a~VBGnJz{Fi0EJH{4i57zZypH>$tvhsg>*>pqZ#^* +OLx3t`cuK8uP=`zQZ4;t)fC5fb&WQ{Q6xzf)xukPf1NAoZyxfcJJEva~+}fAkhg6dU}=UIA;n3Bh%)A +6XiIXd3K(?I(*{be=_6e6yHo#_hUs&QU1R18%Rg4M30Q&FaE_C5Jzpwe>I(cpus73A?SXbSYnN@R{3{ +*!YSc!@?mYmc1~gE(^Jj>WBvl)=?p<7lfc|8k)pE3&ayiHu%2VCemq@(|{rS?ng!d8*J=69MfF`(p%! +`Luk68x8APi49N3hB2Oq+?QnqMw09e{7cQ{^Ug`GVzrkQVUMb$0fvnmv6dNNcbXjablJjnh8SB(u!$1lPoFLD|=MDC^ +3*N%P?qqdBRbhMTTa-q^dN3lB$p%2&6VGd4&R3!&w?Vhx^EzE4RHTVsgCd6UedQqhX8F~$B1U;hhdL; +Q?PBL34MVwfDhuCdy!%9EK!Ghrw~Baf=UQJmz8|3UtZutV=#f|3H=l)Cr0r5JKx;L8tIZQBM{LExzlISP_~|*`Id4)q;RgVl`X~Sgnz|LjUt +R&>?{RG5kxdBFaPeArX@gET0Hyd2Y!1zevTnk#y5mikAUy681_ +ILXAgZtTT4KT$CZH0%c}wdN9CeHHUn3qV3FN|lqeeHd|vNO;{|NXvJq>aTFUrRtwT%^q6wIV=Uj7t!z +_2>V?>$ris$l|J&5pK#c~o6vVbqD`YO+F#M`<#jqGkHJe_N!cO$t1Rj-81)iFt?&l-NIZj1Z3eKY!9D +VMEtcXW1{9X?U*ZZ;)0wBoQ6$va3wAbT}fD>&-Kj{VTig;2vePy@4 +38yBF9!rs3-(y^&|F#r!{&~QZ}RALhsOu>j9e%gso0cyf3%FT!U-j75Q@#U`*x5mVL*uTG2_e?!~y{$ +b^FBGqR9~p|zU>NEpG^;H5(PEFrjAAjv0mp`5Gj+B+WDhq{dPW7KldJs=R(o>fjDe9X%7;;gN!Fb&v* +iZe1fDgfOV^Vx=(+jw458LqUgVUr^+tLI+muv&Wyz0BZbJq7^%6yNL3ahGnL@|VgIBMRr{t=9FcNZ@COEukxFrL6fi^{vI>zyod;`<>Co;v +P8phUl+R7GB+kJpZO@7&P|&oMf{cDVIMJfd`T*5kBb=QQd6FOaxKA^*?r*^iD*#CsJC@ogkr +;BT~6f*L6X~^RC1$REW*r!Z%=+Yc~^+|UM-CoWl-HI=(Jjh2f9k3t1L|2ekEc*e7>^vw+g({FGmA#|z +#6_HYs8lpx6ak6N0bD*OEcc=*udUW=)$M1$#ALmDkstSF>McHf9okR1jxMh8l6^k%jYx`fX#XaYWZi5;>DlAT)Us%Hu_f8nN161dQbAuURv$$^9&I=fb*rgbFB$GndnymC>!C_z;jvConpP1!W@|`l{U5aa&}0Tu_%BsG*w(t&rkI$m$9IO +$BuKxONFd6Zk0y1=m5jb->96S&X7cza{p6Zr`b+*#L=RzLf|UpjH-K6F!dF3JG#C3ax#l!VF91T-{&UaaG2FE;D;3A7h~H+u0VhrRd-dhxU +1`dR+uzk%Wu-G&~%-lX0ET>pyj9cDbwc8%N%BL9-R#j>A(2CTBi6&ocY$?T$sF*bGeK3zwwOVL|^NI8 +_FLl$2GnIE%K1wt27AUyg!Wvdpl$iwOjJE+d#9xK&3{KV-^+V7dZpcA+1mQ&OPr`YNXxd^Q74)eq$`R +X1a7x7X06)DPp2*l?{$E$Pf*y4>g54E*@7q)a)i_DYBxit+B@k;0M(Bxb#RhgQbr)&mLPqm>AgETV}r +clO-Jaa$o4z{843Ym9wKT+?YtgvLkL$EwNmjtc`&sjI9(INCeYWVdW*V8egp`WPtkE5TaQ|Nn0)Y%PF +aGgp0Dhbs~I|XHn&Sv3`98@u(QHsCpI{@wk5Y4YuCU$btoNLLD&hAMt6SqUFM|aYrC<~A2B(sxFkyB8 +Po8+_9U!h>?YLUk1&Ct9<8{rKel7~W;B$&lvEK%S+sMP|_)4m}E>lpGaRO|Q(Qk$alQP)H#$%W=BP%H +20V{=tPtd*g93EFu&2=Fa7<)~wE8rcPL(&N45 +vvI&5(rMy-`V!`!j0SHdqg> +qCWPezu{hYB8;X}v@6^G36s5xCv?MG&QWIr(-gjLq*@>rWxKU3Uued0PD@eSzo4j>Rr4 +(t`r=t&WR%lQ%FGk=2QWBb1K!?^kk|>dWfv!BtH1P70n-{5v(&bkFfoAc*2v%q4`j+7@FCx&Q7LE2-&XgIE3S1_OI}XYj{Bb1SX3Z?3Q->NkH@yuX`05W%*sZ1 +!}U&Pl-U4?JZt)50Gl_hM$tW0c}aX*qX>=lqF>O&hC^eYJj+xQyPKnL)M9;wtYH1Y{T5uTX(~g0qS-S_=di}%Xy_&9s@Jf3Wv4n3zC58k?Sf##L*trLX|9p#c?WUM(D +qBqP=_5%OyJ8Joxn3#d=wxlK)qvJ899z=Ak}~LCG?IA&H&>%0OR?2Au+CxSq~sqhr?1JQ**_#uI|V(S +b=}nuxUKjrdtTG*~t5LN8D1Dx=c&-@mr_f9WhD6LXTLxBR0M!L@Cu|o3gu444Feyb74P%G^O(gr8Nn5 +q<^6upgcic^BMN5p+IzXNQ2aOSZEf6iFUE-SonsGhjL>zVLT$u$6YUfE}-2c6Es35JM`A +jWNYxyqr*I89Tb0g3L4L7H!E#<(1YmJfZ%9lH%95}lg^=jSwMO1kM+UWb{l+c8}PN6jan+q?Mq+7I0b +8-l;hk+HdFhakEbDZis^jK57c>Vs%^Q)QBZ5rhJH*57n)H)R^xQg(TH`HB@{2<_CZXnXuKnkuH(W*b( +t-A()`H;0+vzpuI%-Eu1nFn{O95mUl;tv3AC0vIh +^bOIvgk4NTq?)B*^j%Aj>`^%YzwN#wTh~Lf&?5h(V#z{|qVgxtNG~lLwIRuZ%<_-#n1-@=2i?<$eDH{ +XU83h&yL^org}L;D=A8;NLI`ejrZ4H^(XXI)j3jsAug@Q1D%4aSFa@AO)YFAiBRcDENH!t9=Fqe++@X +c^^{nC~}x;<338npDY_l#1{=D;{ElZS$w%CH1CeSfmFPT)h%D9F4)JY_=P~lFMx~_7#Y7~-vBcH>wSs +2-?cYE#!HYUoW>926n}_b<_eP8U&~*hmgr#AYzw)sDtrwR$5-8a5S5;*#_KvES2LzQ><}4F(r9_g^%tjxy$4`u)vR2w#iS#z+M{YlO|xG!- +_Ovix|HA(q23%?hqqKEo!3`8|V;}??wgY?kx42&;CYB^@m4Z)d39l^2t`mvWd%N3t#_WZdUbDYTPG}f +Yz*%9eUL>g&IOqi*nu*31L5Z{dz0^p$Wa+LcBHvWe=s(rZm{nrsOL3SUCf_C;4iGra5eQzBK*D0mk)o +0hfwp5rK5Hcso)256#?z6F5x$WRI>p^-!Vu^q%-e7+seFsHy{!*1iN^F3W{6=$7(ldLq*0Coz9GE9YH +Z_eFGzvTxK>@>p-)H6RYo?JiyJxy1UaiLaRld8?1&dR~yD-Uc;81DEZI&ujFK6a?0Ov}U*}1*eh^{wj +qo2WhKk`MgUCg*rU3@+KV;+K&tTC!0LA_s`PXq#-~vGe}cU`>Q7DRpq-rKlxFcWrY8{RTEqt0zat(Hq +%)@pj1koVn(Q|zl*cEYCHX;2S1$_K&yc0+(zwl^8={b%5uMh +ijL5@ +ze%$B`a%;)bc)FM6CRT)fa}?CyG~%+*9@c7mY&{F}Odt)`=Lf+kvkkr#wi2+VtjHf$-YprA}NAJI;B*eTZ^ZfC`_SMjbh&db(GpW4DCZ|Dia`a8q<^XPfeJXBt +Fx5q^B5R@_gfJ1d}oQ$L{I=b?r=^c_Aw%;+!y&dtk5LK6Zw+{#w#mm- +CE4WhgBNp2dskCVWc;hT1TJhz0@IFOt;d#nZMb;dXGok-22pJQqIuM%9?U{**o6XEQEb|d|~n-7hPfd4%L%rEuIxrtRGK*_jQ@1~ +vTGN4UFk>@PY^=U;Gb*277&Ab;zyn(r9t@sh;h;C_}=sH@NshY4nWiCIVwn3*bJVrkjJ8Vo12~wt7h$ +k7X>IGBSF83!KLgBiE7*6{)SUqoDzbL+t5-i=4^feX1DGyoZ50AYI&z;L+K4s!DPR^&?nVJGTx-XP`3 +|Wg@F+4es%CR9cUE`t24v;*xVLp<13|%Lhjg|`)~ih*T2+_j>fgh3lsV!idbYR^ba30F{?qA2K}LhgAv@g5qs-*Xy?m3tK|Qw!*4xz}1_gI +6-G2sGk~7IXc|x~4*G&yBp>_`$<0C5h5rji2)2A%5ak51)WouVK2cc7!3CjZs`7F +hCp`6W9-nm*`0V%=mrCZUe*^HFt6f3m66J&?nf&Qc6Hyj0h)Y`C}*$iB@A#QEhYGMwe+nGNiaL98&rm +XUj_5e8yd(mtUQPE9+IwzoM3Yu@tfWK*~0BoeXc)PB9@s!*99J&%-q|V)*SQ@boOxx)xocU)d1Gb12% +5$h_IF4d(eJYZGEqeFlTsN?mdtcUdKKM_LnGZdAjM{nR0n3A${BbBK*ozys(Ahb$bm3V({*$ +#p0UxtgeUG{*UNZ}1J@O2wJ|EHwNl&Fe2T745$a+)vaBmU#nnJ3&oy^yKPNhCCJKI)bQ}~*Z^y5ZJQevfi%@;IutCXX}?&NE-XsC>@! +7JRN`FLR!0j9JWFHS+Bu+)l1Z0GT7pyB$x8I@=Kr3KIj7kPf;)>yO~PxWA6)1n9I%?KmgHZd&NeI8Wz +Im8J)>k43aux|MJLm57Dj^NTs3)NVIJcunp4x1Inf|l{nTD$>~_l#V|s*8Thol;YON$Gqqzw){my>kb +RR0E_*4b7o*jW%^q-weiD3d^sFK}f_025V!Vfc>o9mz(X4;0JLJO#T3njD+LD}0QxQ+_^^+$nz&c^!@!hgdwv8Q81+nDtL8$a2iZwa<7wctV@h3dQpA1u +k9!+z2bo>ZX3iXKfeH=}^ELHmqu4B;Tw02{6+zX^DM^f>VbHNGatL{Ib5s$2zp4f-9SSOSU7=7Q)^Jn +OOvRmbj;CnJ{7?iCqb!>X!v6zd*6uexO>mMq(%KDP^R`|!Sv>nl|x9i&IIVo}ToOHU+O`_>~%4Z!0+I +VP5ML*_c&{=_m=QU|I$WD7O-CVo_RHKVaNe0oIkDcX8Njykb<0Dc+E>=&p_h-= +Grfx1^U#hD59&01DNVm%V0x8nylka&fzCUysx!vGtOKwBQK&~w(KN>lK8PN|bp9^E*|JuqBFc@2Y3g2 +Ql57~rrxOPN@oU)-n{hMKo0{QHnJT=yXYJ2Z)(mg@_(K3-dh9V1(7h4Ugr-gBsf)RP>R)*&7Y?p%l^Ok==hUIyc?&rA)vk-->v%LL$uPb!4x9O(jh&O?>Rv4!$KC;`^~EL0WFlha{q#Bioo3zWg8ErVwsb@>pMGqN= +CSF&BGT4cIR9^_LRl4xAC6f#V7vV=<$3BU04sAuAAzUB&i196>zZy>4X;~Qw`D10x1Wr=Ut&Uh5_aBD +@Z75EP~((Oo%OvR&L09!u#NzA7vdcyLJs$~L4JtyXPmX8+oM#?kM{XWOU68f|5xHy6A(I@c^z^Y>x%D +^yCdWnl0_lFhqazGuY+!IwG5YAkKTXcA_*iPdfq#2H2uRPJa;?;~07@0)w3`lOshY8B2ouHW +)-c)1GPXfdI2k#CkgNz0}HL{SiUqGp5vv#@GRhisjLQTwC^~pD*6liFh$W3389`E{gy=~MbYsHyR--& +Gw@N055Jcjh>wPC>u*Cwb=sB$f3Lo<6Z{i7M!ZtR_pP&tMrMw;u%a=9A~2q3D` +rvH6-9%^*I=blEx;Cug+#wqjXVlXMQ$bL=L=_28LD;yT8M +9>J?EU|M!UdcjSo3)qE61i-%IfdKj|pkV~bT#si1lbSultQ;_mnScYgv;OxBgNb_wa^rJjV2yGVXJpV +O27-MX6EjlHX5?dLVgmdB4X_05T)#g8PQ99B>88UkwQ8nS3uh@Lr+&=Y`3QnW+VfmTIg +K}+936}iTXi=frQaFQ-}ExYIq~-z}<-q>W>=+9QIH-7U9p%ebI0UWG`tnd{|MA_1V-1-lu|W58e{lfJ +eF@LgR_8VJl1TKrvMpQfJ?MWl?UjJeIigiqTC*vKOC=uR+D5@s(Q4x&LC4Q`Gz%j@w8rv&O~keZ_FrJ +JcH4^)M9x<9BDCEFX)o7JJnrRP1Sso0LCB3Ehh4==`rQDw1qsco{vbRw6dEK|L4`yIL!gA>HgFZS-94 +*JvzD1Zx1R@#3{VsMX5yhkRBc>^?@#3w(Gt1hwfskGAtV^)3s&hcD%!WGf#;`=I&)+PXqJp)}h3A%9X +#tUiLxF5X{V^f<>gkk!ae%Y2JM*=o)(;;t@Q0g3TwM3Cs?H2MjQ&ScSeysbT4UG(IDIJ8gI%BzdQ1LE ++8Snb!}n2LtWVp+3j?tqHql~C!5^-Lg~_6};L##XJTQ+__zVp;zUM_oJ;_YIxom3OiOUSkWrCMoO +tEwC^xth(J>5R4qX!|6ZVZ{vr$X9dV%ABhRd-H65C!pap|Ow8SDo0RGgC84FW^H7y*w44o_&>{DSqxq +*Afbk_Nu=Ki@-nEsw+*}JXSPTE56H_*;b~`03RvZxF*n4vVg>6(VXZw{K-D2!>zi4<~o^*DDU-_3t^(uFrKtSI*yr#9)K7!4n#p1K*mt-- +*R9lYFA1Twbad_G3*PJA82dprxp{0@8=!<8pK)8Z^T@gD<6Sf8#f>HDz5>k4(32-& +~Qf+84v3sUFW{)#@#YtJR$(YeYR}Y1i$q(YzZVcBpfk+C}}f|BZ3VRI45`YpJUAI-V%ubU#k>4!m66@ +In2Jp0MtOm9kLmH5!`3LI+rAJ_~)tLW@{v +GYyd{3Q&yrm_<-VBy7q59c6p)eoTm8gVOhLhn`zd^z1G@P0oQbH{)GH1Y@CKiaHMpu7E- +xZHv$1yR3M87EvPIqW%TlEnUSAH*%ab9BRpqU^pfXQm*FYG|Vxge^%#jW1hOU*VydF1swyf!`6a~=H5 +!p{AVF=NT(;~H+Y@SEp^P;N2JrsEaU&SDKW>FkgO}}j5%(ePq(sjC{`NpZ2Zm*e7EsT85ow~hr!1rv-0 +=Wz05mV>m-VFfoJ9mn8j7~$$m=3YdX*B0|?eg;;pm`&QLTkRBPvL9GyR51B>5npYJbKsyibhtki>|Da +89g`4#EGK0)!9&8MDMoBtY>#y-H;1A=ub@>{bj;LU`YIAo8KG}_?7MV3>vV{{-t;$yc1*V4_jLE?$q5m8 +6=v@4w^!&75i!oL*HCfJ>5(@!*xsy>LQ?$m`3sswUaBs*HXD&Bbuj}DgFhi_-i*%SFlUA^)z$tRM?7(yd9F+n|_>ZWSb&22wTa})$}#}$EJV$gx$3EtOE(ASiKgzI#B)OAzj)qcXzW@vO<#_GfQg=*f@3P~_Bw=|Tmj}903`tNPZ`ef(|#N(*=`hA&|DME&k57}8Lc}&C=ktb79;I8SCilB~or7(!@QKzjC2c+BIn%7^ce5F{1m*{V3r$)#FY`8&Y +Z$`aNpKkBFk6O#*z!=nRAHhHhqt7H83W~eCPX9}x?rdK3-VNro7n{u%2-d1%RJ>e +pXTf0UeZWyxp5Wt&(wy%qA4>lpQ43$-J=t6qDMSqQ(!iqbBOhA!0Oie81TVZk5eEaL4L(etAB#kb{A9lj!;D*<^#rP9KRArIO$s;|r-cl`R72bPgU`)EF_Wn{W8OaS>$$ZTl +^w6LMaB@jQXh|y{{0Bym7K&+OBE^Vd?0B-6Qj__v2p@dJWY~{Y;D>AP0-K;5OI|P@o)$icM=bm&fl?3 +IkEf<~6FW7%25(vLw(5N#DGox5TZA;g;w%RfeK*E|V{*iO1fGb4xRu>Kr9S#Og&SXk_e%k$NFxwO?yO +$Y`oroqoSfweyZdn1^!8eQrMI=X4>l%wILyKI0CM%L`UKr0N28zNsIWisDB3nqCH3tCMho^nG_t$Dl& +Ur2UHbz|)r#@9gheoN{_3-^An4trN@miw6Rx3@fHRE2KHL`*i2jSm92%cV +tAUR)tkRo%^zx54L^p$i@DS5I=FO)mW=ZhH-F3UEWf+dSO!&lmY#y=9xFV>vcV@E+LO#?0vWOkmqt`u +LuabhlU?X8T+%M*Q6fM5^b5ytwdNV*rv;IT4?d0iL`@g;kTSuzq7Rf)dKRZe2{Hsksb>_@BD{JFhbxd +Tb-QDZ0guad`=84xm3ara34hrLA8Dd$P3QpXGqD4cs%Ga}`(Pq36##+g53k_J*3*&o#z(eU3?-+Nmgx +9iJfP{nQeZJifoUsIaS`Xk-IPB0~tf#*P@FnH6)E#)1)By>XLE!?}%J5Pov5Yq^Iu^rr&j#j4gFZAQxsei1!mDYMn +B{K;o?r8N^gdlrXhPjoR#grb3M4}B@b;2+Kd=`7bCba)LqA~7w)udW)KB(dI*oh_lC6*4bB)f`WGz)P +u4jC@JY3!SVd4nlcKAfzZ)x;(LwmEEUNqn%Th;qEqLuRuN1nH+Y>0fdnBT*%Jo~D0<)~1R4$oT`CYLK +sdHl-MawSHiVl=8DPgGixM17OwE(bo&RqpDLnzhU50pT>5!JSiaRr55!uk27a;B_)eb5guiI+n6vsg3 +-~R(@que#BD8N_?s3Lj5qn=f+9HDVXXk25SPiai@>8;r3Hth3yX)V99kzd)C-%291O2A)rdY^GQ1p0d90_Vzpd +_p>_+?6C}p|OI<>XG+B3coTvKN6Qmyy)Gr!%x~^CB=kpF4<4E0>%=zHBeTP+|%JVZxzd0{bRQJ%9^ev +Lu}O3NwkXQsn%}6%uAX4hk{w@>=OU%H@Eto>rwqo-I@RP46Y-9Q-BDCumW+yLwLE?fNP)Fomzytn%1@ +(VqUVoRpZp}uZ`z2bm&{D4t+uyqN`>8x&d{BvhKxTDC<7t3%^t&dBt0l +M7>-T0kyUAANK$2nqaUe;$3m*Y|lqv_z(v8Z2Wa(n%K#DX}UoTy*?tL#Y*A?)ox&7g>yHV^XSv%krMY +0D`->|4J;iWBxa5D?9!SFmaxht;5Ve0sb6V(3xGE2ro99MKpvNRa={`4m%I+I0nBc1@LCj=`km@Nt9p +75R40J+Gap-;5PS`*gd4VN4}+@A$>_)cmt>_czvRA)o<7}a1NlGBB7z^u*(wA~02uoV#OSrA%RC`YYQ +wsJH>%2bXfOR0WX5#zLr{NxkVj{B*TxAHQ6bC6RW>>(ebCcWji_(UjZ77wl@Oe`W<;}-!b--?unSjNJ +)xz)9G$%SIsdg{UaTRL=QcB_@s8}T+cl67n$RPm{L=nyr0bfEecdY04#qCaZNUAur4`XklnZxQs*H4E +7QFV`**(xJ;~&}BZDtK%=}(Ehr1@xe5D8cll{J>JL2mMytr72s&lXJBcG?hI0E*9y;yI83H`>?w6J?8v;PYbgDuaBkw +fwSYD2~K@`N#a>2dyxdR(=`!(BcmUMCnxzT|U>k%IWmZHqq56@{`&{bGr!gZZ_tLe2l6f#Ju5na43dv +$`f5*RQNFMpC2=EcA^;3&0_fM7-i>Qzk?2KV>33gS+_q!!;n7Js@orDiLcPaZ?Hyn#CuG0bmH$6oOo| +K(g6*p0R4-4I`r1~T{i=ChErbw>`kY`&Cu;*jaE@(sBe+A6BTKv_n#Ddwu}ElyDNz=U$NXK>J2s9q&r +?sm4EWp>3#IyqrTM~^Q^2Ei7kMa8#Y+|=JjIFHlK5=Z_K9>?0O|JD0f3mw=_kJ9I(N65qwWDzR!j49Q +K)B(=D$O!yc2~gwH*F%$hF_o-LH`VoM!G!?w@C)+{g7 +P)RL#19wzfsOOt*hBgEOu+Y)|}{CCMr@G7Q%3e={;zsWBG2iY;vo0zolSY#y>HK#k{V7IxH*2Nuqa>V +r?w9lRu=Pr1#YG1LSWPjsb0$ULOs4nMNo6UtWSz1h!##@?XX8A@2Fg<=}r^!4@fVf1uPDffo5wN1YKR +^TzX@=2j&6WZ_~i(tV_QOsn+OzO}#EgRifHBfBshBl#+*+3n8-)PfE~D8QCE +VdM)pvR{oGS0@=^t1NeJNSY<|eXvPhFLfBoRt-xMPe#012RMzRCWQ1R76Y2Q3$v=zv5xmn(Z|(OHKQq +i@ulEnA=Joyo{V$OH==C^c8v$@F#&2vc%2Rri9?epE&GJxU$$Jx$&n1>zc!#pi!q8w)rU}o78HxgPs)m@q)&-TjMlCez3^$ItVQ6c +=?I7pRE~Bo_!wiBLJZa2pXv9y)J;_V4IAQ~QYy2_5DuBO&(-(i2^(0#44QxkP^(Y@%GVNrZ21@S3CEj +2{p6^hd?$u22R?>PD{{;tDEmj@WjA=1RuY)2mkP@zz7RQ_S?;86cYB|^sxOJ25u4;RfizRU&%X-Y9^R +TKWjVKz4fGa+I|kEx3CG!)1IT*%^L~~fG;%FT?u6{A=*jpV9^};SqqH0(mKneaH?Z@K+df8~ZwU4TWL +BPks!6wBaSN+#33@&5l+xTa-F(e_^rW*7fh2$c$hTjkEY2z6q{C&ypwcihQ5#cDl{S%NYflIYJCXg>avHuZJ~J$JawN1Da_CZBnoh<R{-%j3 +|J|%8UjMykjG>x%mzv==X=fW63Gyk;sW!zkJYix75%J$U1)?|uk7#Ex>ppr8;@pPPD!mz8Z!!)vU%T0 +G*W+uhGqH1>5@v`1gB$q~#$>kQF)#gf(^&{aFIlVG(S`^MjYj>_Q6c}h87=6FW;;sx$1G@Kzu4jD@OP +9-m=utxvu!oUHABC$D0ZAsF&mq1Z@!7u-OSN?N=-bTqj0*%;n7>PhY@Ee<|N7I@GH$AMuSwFUXH)`D) +3LOrG9FFb$;ZP;WZ%pmGp;#)Z4GZUm1ez@;xBVqJrsM!+VfyEXSg5)s@HsO=81zD5OcqUnjVlE6_<+fMN$8Rm +AbTmsp*aM_!I5TQl5foNpb4xP{vZ#Xy4wV@*67ap!t!K?PhUGRUCyW-Dxfh&Gdi2=k=hjetnSre9aU@ +=&z*rL)4@FIv)$~;Z@`NKN`T*S(sR$u2sMO6sf11lPLC*tpT_(kH%@2Mf(EK)yt<54B<6RCW%z3wu4e +wROw{g@we=L5v~&EjYaoC0Cx8de0Uzv$4@yKeEM`2@ur8&)D2hKViW4mJ<)NVh>K~{cB0~SlLn$;^-P +?yFY&!D@Z&>x;M;Ks-KQ)2AGmr2>)2SoG+ohw~CSzRqJM;p*3!DCGGXCUJd_)sY98o4v=w|iBQ+uzvMSMw{4AifYUa5%og{i8xaaI91@B+csH9TvAoMRi{YoT +Ft?Yq0DubW7=Y+~JPa-*)9T4@*6o+yNC{Sk83YfHt8ZzY22x7NuMwj$Xcx#aHejFwf~${TW=0_qVI0) +?AT|wjc7}4)B2QI&Urg8<4tj~+Z&BBaS_u=aPHV$i5rGEh(Jpu?uczDJ`!$=H_l_Bs?K`!XU|%>0l|> +ifj|>~LJQsfkg(OGl&fu0ZgsLUnaK7eJ$f7Q#Ez_UidFn-K_!upQ_m23uSI09)J3Sp90|i>I-*edWVbY;E8F@XWTh8!tM=*49UDZ3o8;TicgkNPu+p3j=IzuN-gK+ +WwQps!RGaroZr?Y;8}nSEZw}saGY6NB>4g!`GsXp{w}w4`4(~(AbFd7`Ce4evlZEVXMkUgzm6M@)NeI +IHG)rs?0Zpmltk`8{&3dA2-AWW(u=;!=LB06-|6s#9Dc9{I9a5&KJWQP +%bxs?rUu#{IC6c6C5QCHW44_hZ{qO#YkN<)DAN&=2|Fgg16CVP~ZhY<}f5p +|$CDaRHeN%U82KEYox^MU{BuNb|5fWKn%|LCun+~4gd{&6OM#p +bAk`72U)1(X_EJj+L);IHU~F2wy6_nhFb7O(Ws|7#A6)~6X-z?HPpLSrp8bPUEF*M=8_{{%32gd) +y-j~2dU2TuwVUb~T1_cF|92FG91pyO9laWDZa7f&(EI=8AWSNE;#c~0G0!Ivcy`Gho?R(G4T~pjQR9s +3+D@v;`VM!aJsrP@*z4to|2x{;5-f#K*`wo|L?tac)&)r$^!2^u@S{`5=%MUP)bvnQ}mK|Um`~S}Y#; +;z#*#Sl{@eO$r&jIXfet@ysK>mvd7{6PALTM=rr?mr&+n9ZZv;7SR7!!VQoU8lqKEOD1`%Mlo=4`*&0 +miG_{`3LHvammKfU$mCvjdC`x-#oc4lwTAb{hv64cl5jz?fLr>;NM_iiaY$;{@YB(kX?Gj-6l}f~)B` +LkC@u2edkkw>r@H$l_ZcXdKB7G!Aq+&{)9_G?o<%&$9VK*U8Q^*3M%aEDoz{b2y@@H372JMLyK%U+@T +?X~cmFKhrpdpJ_z%2#5Las@j3#NMj#yr11`Mq_LAY(%4=cX>2EsG~#}aR*p3O)S>kwjS+Yf@Ai%~dNe +q4rMA%NNF!@OU%pVSEg#oTtJ<(jSN4F9vFri2^k3i6myc|3$GMejOWk^~d(-g#?q8vqM&WleZrEJvH +msCgnn(|VMXP7V2tH85`I=G% +t%OKpc3FO3stcY9-JTivTM#_8uAgfCG=)yJzET&nb6zKH7``4V$pRr;O}l+;sLs{3Y5FoNpEo|^m6vUj?Lr_24Br~u6)bEyye)L8z!naxDr)7==hSKHvK0I|tay;SFQuC6_3U99Q?Pn^_No+ +~ZH#H#byTgacar8{sr2}CQ~{<=~4&e%QOAst@Smd9#}8iVF3A(-;fnmQjX>e@pn<)dp_gaK_gB=iXj& +c2w%TY7Kh^Cw^m_*;5`278{yV1G2!U_U43URa5fo;kwKBgr=g|56UZQ%8N#Mx6L3R!_ZsCGHig%i>2& +dc4B+0=&piG++wFbl<)V9FE4pQrCLw4H8wk`+`!^bhN=;S}`BvaDRFkdU~AswY!%t<5EO;J>}c^c?=) +FMA^ASW%)Rb^y<@&<$A{%ZC2M~@f;1lQFvTh17c-S$OL@39ghQt>~kOeGCxK`1J=e8Qm_CDk9CsseyY +0oqCc+LI_z@~bhumsF6&Mf{c+Xik8P-CpZnF9xSc)Lt!@hs#0Ray#Xy^_x5e@|59E0aqzqX5q|mWQ4z +=tT$w1i=mqvVd2~RvJV3<+ciAgO3R@iZ6MsKe(*!O6+VuZt@`3P3)T4iv(fLC-CU3RzB7Ej!!HrsUUrlQoZv6Y7k|fQOL3117``qH*}6gbJ>BpTNo-l9k&t9%i`>c{^ud(|jp{MB9}?NM_MN? +?z*#6jI-RGqxbg*e{jnxWm!4>XpgX!zyJ_RApFP^t1D+s7rT@mekW3s~!*huwA+4;I$M#JTY&!8U1d%}@6 +X>zeUIFqD^>toM1E*VFyljm*jXE|5PlFxt}Et0W~mo+z=WY?D(bj5vPfPU6N)dt--b-K2!SYH{ZfF`l-8~Z7=FT8?9V_`>dvQ!t;ZFFg|q9Tkr_!>9a7E-L`3p>FGb +!l-B_L=Bnb$@WNukK5z%r%cA)kktXW{Tj;}^>7A*&Po~aCP=`*uIC;J@dBTj-cTlEJrzlNf1$D=bdld>pnayVy>3 +n^;?|2laVs==w_4Xo}_|&3kVw<72+d1_IteuL6;cFfnEbJ5@h9GTVbMN-R<}Uv3S1FOZ#~HlstThNbDh=aiNeZsLlWQ>;=?;!hXG47V{*MuMJh4mBCQJsT>%BgV +7IYx}{4maBKRSIIPiXg_QQ8|ew%*!7Z&x8NUdW5PbO7BIEp9{!!9HH;Wb;pEvrmJv=QcJOiwCI0?(e7uAIc^<{+qQhYzV=uZ}U!D~ +lOvfwpJ3%4DJE5VO^H8lk>e{QeB@%r5QS%($ZHi~GKgO}oo*3}GV4rHk-nv-*tnoOze7$VE62@ +(PAe{8F!FAACj8)>j#q75Gd=&(nUIyc34;S?0jSt~$I3oQXDvPkt4bRBtJ95o9aN>`K@-;rYZ|ywZ5+ +6|LhxuOk2Rl`uYxg4jZ{OLE`h}}Fgkk~-tMX`x~y0fu8sM5 +K^R^&0t}R#QT@HrXy3QllTWUPvK>)0;PFWA5v17;`dNkSCg_-YOCMeIY=u>0X9h@ws`xHekrL~L*jeDn4Vl%h=M!d8oR^PM)F25tESd_kE%&=6n4$gu0(Xu!1ye#jIzPuIO(g>SYVs4aljq1hNgTK+ +6w*oJbq{*2yU8jGDg2w(Sx;1s??w0Amh!36uN8^;>De=(%C*GxM}8~?y}t|;!4*i-)1my(=`ZbPqVZB%v&cZcfY5qzmi))w2>%trPy6`JY +9J71jOXLOCH(4QF?Nmr-cp-Q31z2|v#j7@iYVF74?N{RM2XTHHms!)}OMX-p_w-_GtCdAZX!$+&>dGJ +Ni90flW$^|0z(AuXyJ&q+x;AVVWd6JW5I#ohxtVIcQCV}tGV2b#>wer%29BTv`Y5zJYTfYoRtD5wrK< +QM253JJk5X8ISXoW<;Ur{e +Z8ws)~28)xPPf;zwQhitBi`;<`#+amCGUIw%0T?E|nG7&bXLOI7j!F7Y<(j#U*8a%anW=as6W1~)vWx +*&LlV;QA3z}<1xtg#Hs59GlxdAT;6g@~TL^E#=v6J2@k$!By>*mbyQtFt%Ot}tNkU~jBV#zyGUZno&^8t;8>81!`p`yCtk+HIpF?)c(!s^Up}@fPwQmn{`6G+aSlj?WJ2qC2U +I)fC@@Y7fnCg_QaSUorvdTTl1$J!ZNXy5Q5=AFel#6mo%asbvpM;l8{S#)%xWHL6q>oQ6yPy3)zPCgZ +FEYo(0McorX*K8mVvDY)8RkM +sJt_^aKHvLSBz($_vOF9zdGJ@XW^W6{1%nY_TTl|r^Cyc-NQSb4=BbY#4bKuKVn&^Pxx6b;H!Sa$Mbb%FDtR__8ox62``08?qK( +o{5)S&R>vTR5<}(_X(bXOT?JG57y0**ND&0pTJz}yuYh6ikog(x=WsoB1Kij1&}1r8N|ky->1R+a8C! +h#HGw*AG9%S(YV5uCnaArW&vtH#v9C>){kqfj+<|XVY&6O)T0K&3t};1osciV?Zz*`4Pa(Ym*6%zbY4 +ilpoHMrLh|{R3(20^qVtzxuB*mh$8%6-zK(pf?R8{LtLwyuZ4Oke)7CtNZdU9f^&VCe^lfek&oxOVd2_1WsqFQUe +DwdPG#*4M$XY+8ja0ClrN(EahW;K9uATKCqGe@1B9kF&PHado_DqoOSm47?L3KOsE76{P?g-y0A;&Ltap}?`P}6pGvRu8*w)}7L; +c=Ehv9+iAAHdc7^|LwgBd6Q#k9+nePm|hPLEK8}x8=QL5hlhZbKJjj!Mhk1;q!G(;drgJ|%}Z@f{(Yo +Zo~;G$waZXV{_sipG`AUL>Q!}`>)crzorZU6&C2XS&Iwyw8>P!@gDV)77i8!k91Ii8=4#9Hs=#A=#|- +O_+kGPakI$F*BDyz0e@g=J{E*+#SdQvFQ6PA(Rhp}R(B+(YdUoT$YxxV{cAaM@GTXs{*~HD*}jHf6Dv +%Nn?8I&0$QsY?7@cmw2J>w(w6Xoo48o#VFJ3qG|!F_F7UUHdI=clAD3ds-nHt#oZs^j)@20Pkl^OI<(k2ZN%2MTz`(6BrCAh)o{&31t(fnjI# +|ow%ZOfj;{uTs3~vwkb-|_nNWKKUrN&!UAxm3Dz3R@46~Yt^%r{)Jke>t4kmi`I2l_T-mpik4eM)hJF +{3D*4G|lq+)pe#eKI<;fZD9ciA*kmD{D$Y*iR{QaV>6cd?L +Skj2824lT;AhmheM(U!cFbOkpwY)K5r`}$U;w=t6zkZO<0EfG?jR`0QJ8w*oexB!$SQpJ}U1GKGt$Y7 +QxnIo0z`%HRjPLz+Lh_RJvo7n)2jt@Xm;Dmnkh=za6}23yCAZ8sUGFj9fehhuy{S_*V#vWImC>| +2WA|G{oupzgR94Y6G#eAzi3$PJ{B<0D5ga{D@w+qD&PBahR7r`ePk1fehTaixsnzs+?}{N~(ND3UP-cuU?I3A{E`YzCTN2U!l54AO3` +L@5i7Qr&iTCyU%yvHb_kacK4RwGk1Ck87C|Be0`qfBjdPBS!*0aFlx1)h7|WEH@pum?^TH9Rq4C<$RE +oe#Or}SDq%O)c-Z%{CJ{`^fU=563L~SBN}2c(Tts74<#rT@XI)CLcdN&V1oi?YTeM8DyVdL6i8oGMoK +_X#!@&)4N`TbU8Q7a&UZ^Y2P@n)ATIWjRL?T@;=DlMYx~BoJ^x{Fon +4jsN13iegz!5qcwHK`PWs$~m_bZPRGA;}V-S~=q;AZJ%`#}ArI-~s?$VN8<Y&-SNFUibx=giOWF5Eg%NFTjgGzQmL>XmF~ZW`J~ +c;i1|G_-sFu5^hFVy-)S+y#irEc6WBMNmo~yEKkS%l$qNd0QLxgI+OWgJdKW%F?7h?tk72S64h=h8tg +3W77!*nJ8IXn@ZdPAzbe@6&>akT)6wG}9yqbZfL5z0_zF2wH<0%>vO(gJz-l0xp`@pt*$RoG`i +{P3w*972LNCg%ZYKC~Rbpa26qv{AJut*BQAj_y<*CaNXZBgY@)(oJTB!^hLEUPMO3q2+Z6ZnIvaWQd0 +&M)haPfS;8rrGRT8x5OIp)HuFd4)rcI|L&%sx(0oo%qbVeuKaWNW0|!6bCoFsNXbXN>{?t=CkLM5MMS +*iR@%-80ls`rhAEs|3rf)r(NoakWjup0oBeKMTWY57Zcncd<#ikZ>%~L>M+K$bO@53z<1fx(D2QX)j8RuGeoH8|qg6KKUOknh@V*PW2kGt{ar +znAMoeRfkutqiX~EFuNowQnG3$ +;E+v18sRu?Q_4Y6HVW&|ZSdP<_G+<3PoZZ42R6Y$Fnf>wheKg=4o?(MfAZ-Ur%d;GhO>W=M3vw--a;1{QdCN8p#(-Sf4VJ-sqRO@Fb +lrELp!gE-ob*gRE+GAIs1%c|RI$9bk+0Gl_%nM;V93`*&nBdzET3B`6NOYmM7vT_Hwcbrx*WW(QA6hUCZ?f2>ZqS0M`E1DsU$#;P9 +<6Th|Her9eM4-8QN9an{5pQ)j@KrZ3`wAEa1VM2GRNxAkC<-`AS6~>u6L0-&Zd-Is*gbQ;Bh1*iq5%v71_iNuwb>ISwQplERV-;)BWU-{cnB*546=Nrbt=p<->KY$Lat(}*M;z +=Qk+G`2^?_{{)<4?WPhgGpko8f=w{dQw01vF(FL`!%s<$O0!}an-3fhfGU3^KSb*MejjH_WdAsO +?t>IpYCF&UqMwZq|Gi?;-^gWg*^;Vb9_<6JbGGp@hXz!;wn{oh?`L(KkpLu97C^p1pLyzjjxc*ouW2b +}nX@jh3X|M8B?v)jx3?^3gSu0Vdsai*rs>R4>QvlH$*#(S^q@n&49WS3eW!3Q*O@*0PsZ0Z`tygFa8M +4rLefuy7X9UuYi^)UFXFC2z(+T11AdvO2B_$Gs25}~))3ypzNA9+|Z8(DJ&{TmccI~2}xlUkl}dfV8>$*lIBqetvGliD|M@aD_JuL);jPPi_#TX;&DMX6a}2!*v4mdLqWTm`P*mzl(k#Cu7Y^ +9AUHz^4Jo3vGC~rY4fgxh276wh!G12eWgUyfIu_odj@>;~u4BY*%fOpjY7_Borz<55wsufm>}I!1511 +kOp@wul&PpIu6s#jpb-+4OBkBlVF1cv7Bl8y#y~-d;jO51}y8t8Ja}Bi;cWfS|0sT7Q<^9bH!j*B5Q~My_3 +Fdo#!k@|a6i2?tYVoDxMk#bYZYEmA@)PoLrO5YK%=d6!FpGmLcw1z|4CXyk{B@SY(?t#^IrT?owi3YP +e~cgN@p_}c)|MUEs%-*IHR^aV# +!q>~)UkPdMqTH47Gv$TmL`O=yM$Lj#ns~j&yd?m+`YiSwBFt9;lE~IF3h?rO6yGKwQspT(Oo$aJ&NXa +E`A;JecDdhzD}~O~idTz6No^aTE`v-}F3f5tlfQhXSRu9Ir;an&Ybx-_3DcuaP!#yaw@iIW8f-n&b6| +KgIDz#7jAj3&GL?jw=y2b6kyh8pi_>pU!c%0o%y&P{d<79*%ev$DV^@8@^{;#)ahiuf9iS0Mf>$5$f0lH;opU&iq_5ij8Q8pN#}$Ge)OjIn +Hx%kPJP5pH@@UH8<-_^wNaae})vn)w)~1e15TNjNuAgUL(W_EZl(~SJ-Y_P;cRw2tu}$`u_fdK&E)bh7e!s +UpOmCm04x6I}Db58VvBw1$Nf5TO76WK@E^lI|Ao|u2XC8qU+bKci`QTAQhDdB% +Apq*YfE;SD&4A9{O_MdE&IhJ0!vJs9@?ux9$N!yCzHv$5&B==T_)vv(UYe1^@JlrHbKhUbg;x1|Q69KZ&VjTMwKARdIVCF~k3}9)j*#i2+xDBN +yvX;71<=F7DUcwb1P7yp%R0plU?bwvm7aA{uBLh!g&}hHx0?jph04=Vbp~dsVqHR2rnlb@-?ZLAP7=av{hSyWx19_Gp=h@dSGU}L9M(ts=6-mmb44dnR`32b~vTH}3 +kKQTOZ$Ga}(Hoyv(DTVv_!mm}8wpUA&h}<6P2z6zSREgV;YKWdnY-maHUq4e-@x=uy^jz2aTo37>(+K +O0Cz5m3%J>n2$k##&~)7}1sf}~i@;)bT7LR3j};t!1o2*D&Tnme-q +HH1BYD%3>EM$0rdjT5HLf)M+7Vt@L2&r6mYYEdj&i#;7l_xRb +J+6Jea6i6Q?0WQFtb(XoZ4A|H|!ZA{8v0f+!AW!7mTs6f&8NAp=OX2t(EnCU+4diFbrO +h1^37B#w+HI%XP|Yl+X#v?f_{XPNRKplk?j7ReVGHR6z7vU-xoXYLMBpc!M8XeE27ntaP-O*|*~AP`11cB(+kg+GGm* +t;1Pr-KV`k|r%xva1131b9EEWFeu~23Lzw^N)4Z^U1Z4Q|Yx*TwU+|OkpG=+usnam~?{AH3ygu7fY_k +z@r!$)^%@P8JwH;Fhk5SxvKkM_|0T|w#@GcM}Fsk4=XDhIV`ni1Fss0!3=(9iTvfEX948g$~nbtvYk@Yx$HT|H~1Fi>&ARHIi-6 +Xgfm&>kHulbQ#zNW9@ee@MEPi$Zs86-WSZpkYmI}nHqs*k+7&q*8_VIDB2{me8kiPHr*oKcctiii{G7 +))y?MQBExx<{h4`@4ru~cY4ROS0W;ur8&IR`t@MU9Rv{sYky4e(>9A4DFKz}j|)kN|c<%2}Y;yTPZIT +vrFe=r$#)BMhb*i3?AUcYmNJ+_K-S*bMLP?ns-Z(g2|DhzQJqcF{>?6lQSvLc6+ +->pg`&R_JA)^*?aETIef;-cRVmg}#H(*VJ--N1-ne`aq#q3w@B#S4v#pMd*`+zN;MG_gvpij$i2S5PH +4P_mJcJj_WmYd_vz-=r!lLK3`4`p`S0ucaG~Hk?9lqt3tm~=&8`J6#7I~_bp5=L3so7Vk+z7<;Ie#Nc)n!6};`YCSn=j?xp)6eBLf3jcA|8(;IFZgc +E(~SS_5};`M-R{?{1Spz*F1Pt>Dgpo1->vw^pFjMZbm*R9{Mant54TR ++~my>iFSUAy<}-M9b1!9!Jtj~uN&cKpQ2Pd+_$`m@i^oc-dRdu9rSKa`lnmy%R%ofODu +1pf1-uHqJ@4%3;mNV^nYuiU+dCbzpjNImn~7It^|e4J!4JsT;sINoV46|ldP%M%-kF_pOR;?jGy_CX_ +nQHlb&nIW){;#IACu~&9iD}Su^LFl5)*9v%{R5@!&`zgq%9tG&(n*`Ar#QAGiQ +1DnmVF3tqu8$Qwwxqz{-5n&ll9Ccg`0((8q=HhA&O-Y}Crv8=c@2cRq$J!Wq6sZ1EdXBx#JY@(45iW| +-)x>|Hs2u6>ESmVBukVn^Vm!+|I);-Kf$>-{?j;2=8GR;=7X5|AYlSy12Dr+D+IY%Z`#&gb +EzGKpI@<^0I>%k;{0%5=%}$aL`d<~!(+-UW^OF$FMO>3=hKs|MM{{3b#Fly914v!>3>l56Ia9MqtFIy97;)ErH!862j8AIvpqKnJ#PXECLwY0@pZ+2 +Df*(_5ZA!2Hae3G_IcY0bknlVyHp&TLIOBjg7AJd@SxWKHs{X~0gJ&774vi@T6*_y_j6Hf!4sz#bB%Z +TluZW&tBslg7+@9gQsy$>VmEgNHYe%_%mubMg6R=%~0)o}%C{J3AFH +NL7pi*y}qG@}Vzcc^RgesbH9unIjVVhHy-l?97~0mPo)l5I^8yTP_d|Y3P)lHw_HSy;CsU|GZ3V1}0^ +mHPzx|e4D{Gr4Qp$xM_udnSNeQox{2zz0yo9iJjeuY?(57%z)_D)3<#+EJvZ0N9Y&%Wb$al+ZTed03nx_dh&4rqmnXWNqo2~Qv-8#ORCXHN3Q-RP~SWM+Y#1bXjl$|S@&| +V}2dX-)v8-%dg;O2TlCQi~#I{Omsmz(4_c2lMOjeCqGeQ~ZcZukt8tMX<{h0K{h17t50u<~Z)WoDbRO +v!S4G9&-4s2LMYS*FxH(~LNyVG^@83fqC^w3+1gJ{-I$+PRQ+5iUu79hIbGnh)t122dwu|Nctip9X5O2hiUR={NiNx8r8u7xl8=VS59yYsBHbppC*7g|pBPx*sm8y$LnY9wYDZL%rYhiFHL;17522MfJ_zLc&p9nY10j9Vc0(HNBHb0+ +Nc&13vv(39#S4KicR4K}A0Zw6AuRuiYO}&kLEJEZJzR)~;yGS^WX1Sz$N2Z_=Edm)y1QALXp?Cfdl$6 +%Lka0C(=x!DbWNK;x=v0aU8Ba6u8IW0eQ35@Ik1og{KSgjBpQE1S%n3P>}wCU>6wSZ)Rx#;R5e9yhZU!k;Cl{o&Wf>rf~iI+7Um +X*Ds>EyMIDkd;-)z&xrV0o_a%`da*oJusYR_ctx}``#Irq-c1EjF$L6N5f6%vt3drI$J@~j+B^@^F+% +0=b2XQce&!}WF@RglO@4TsN*0eN)``(gZPGLlzL$bhpW#pu>_vj3f=KW$UFrjCI#v5ub};*;sFOIYUc +}4N)D}Gd2(*2mB4l1!x$uQ@0cCTtD4Ujm%9e3%f;#f?LXIQ!>+A*PrahDyU($JE$9g&SW%m;n6Y>?PN +6$Eyf2X!Mf|ml>{mueHN(%{jMy3nv>>W_2p7gHqtoEpMH@l^{Cb@)TUDc!AUEU-l>S5OqMY?PA9)Q

MH^uI}e81)*o$*(nq=_m +SI+5W}12w4Z}oSY6lm88RD73l!&LI(?L*;6pCaJk*s4Q+-M+Ke<`sP{hDc8GQZ6tq8q5I@vk)^6}LeI +3$tRjX-Q?I!9Z)O$z!&-ej8p#2LbVNKBkS84@+gn=t3wQWafxq@ +d^&!yQ-i5S}@CsLWxnLO!S9HL9^#U3JM(})9wCLmH^k@kg4@=}Yn(`{BzYFQ2DC0ChUIv9gKVyvoIwM +JEML3aV0zAN|=;1?pSp7(kG&Ph773tB`w +^WUoHc~hw{J3g63p_yA+3LZ?K@`huYJcH{!i^Y?xAqrj$5u6YqG}iA)ygQgwx0(w@D`F`SFC@nS9Qiy +h-BNOou$Z4r$AL+bk9sp2{IA-KV8yTF2yCCc&^c%Ow0}gUcL~1$@Wl=H%sOnc}RLtaupCS|LS{l)-*k&2+m3=UBt>jJWi2;T!rc5!~}O|As2{FOcj}g*NG%9D>qNpjff%tu^26+xc8b`TL1FBe=BnvRLxD6+YT)`YbJIoRC5YM4hNE|bgF^wDtDzi-18#1 +%fZBmxWWG1^@Cz?{zSm4Bpp(84@M1pRt6HuCGE3hoZ=giHtIpowrOwPa=UjvkZ>FAypZ1NVbwMixm%Zi*?Jh_0SXOW}Hn +X~4I^xJo1YXgB5uymZCXEkL{&IF$GSPBD1o)EPg4W<#Tt1&kfO8!hss%1X#^Eu1ki6&0QYF;~dtp@4g +Lnl2XDx~-WK(j3`0|OgvOHYSl0x|$|m4w+xauC;|-@B2b@$rd>`#`OLG|Eh4?N{n-6L|_#$fTHj9+{yLLRY2Usf_tO!sWUt=jBlvmz7af(kNZZH0( +uJQCG5PN>^cd*2vs6nwJ^hd+8u;K^Pa+dh|p_=K2GS9grAARe3F3EMELiLxU+_U*G@D?^gR`U0Qsu;*4;@bLjGmIA1}V+D`oXAK>QyF8H7Q)NOv;Ueo6 +HA1Cd<^yTv}cOl=tEWLbx+u<*IiD45!;GFRJgP&_i^5+kI9& +w}l6Q{qdxlG95Mcn6gXpiHZ?DMbkcGN1MS->m-GXzW%Fh#)W0wxKl7cg4DPyxFMs20#iK&60g0ulkQ{ +=s3RfWHY?FW?0MB>~S1SR>$R0rv~IRlv1>G!Oq>0bdnxm4FojmI|0JV1|Gx0?rUHNx*0ULk0A7Yc4Zs +gn6KVY5|o35}EHSf?ok^1gsXYQouI_tPrq3zzhLX1e`8ll7M;vV+D*BFkHY;0W|^!3aA!PDPZGeL7#x +t0#;sb9{w7kUoBvTfcXMu2$&>bw1E8u3>Hu=pwuYh6Y#%FE`4=i^Ld^BZT7cJi^w+o3wf>LH<8W_BHu +)O=E2SVxe2*Wo@*K?lpKD21c&G2{ylK9_dNec25z+<2?Ae@r`1G;kaK!8WOa(Yg8Wq0~8bA(@Y) ++6KU90Ca`UGa7I=fIUIgyMh~l6MF#-U_Ke(=3bnhtpF{-P~O1Y3a|>)yMQBH6aw`c@B)BWK%EEtD!{p +Y2q|u-Ao&2l?1Qu3KqtUyq0nvtJ{{mgp`89Kfb07aG8xQquf)1AXsZzi_;)A(`GBtkcySORPXXQtFm5 +pP6M*Xg+6MD*@&SGi>MWQ`0NX`yzLEf%Be)xc6#_^2X#`KJdVv0s&_;rL4Z!F~tT>Qg0JWgp08auq0h +AK($pGJuhTv +EM8{J!$f#e3w<=w12Angn7b<&tQ*bCfEx%YKY;26<`)2l>o_k6JH->S0L%jcri=ml0Y|uK49}wifWCU +L19LUN5A;0VYJi&!PzJz!E5J_^csQp4h8Uqd03HhPkwi}O0)Q`0hVlvKs{wAA0`(gG0{mtQPpk6)=S= +19vjC2q1~Ln{i3KLV!21?(I%fdNeuL9f$Dj(eM2l%Zp4_rh@LIEKwF&uy|7I43-0lr- +bJcIeW0CyE~_qzdJDdaq=mq7aosuA2EtSkoE5^#j^B|IEGz|N0}x(4t?fv*Nw^O&e>06%)1=lfcK{!c +(Xh4O&#S5PAW{|(@w3TQt8uL9U%g-Any=bq!`=RCmqt2k{704C#}JupuJ_|fyC-2m9}1s<a1adkEj#&FNVKFl-O+$72DW-V1F +7;0Rye2jvIwHvyj7$KyQ>@V)&&84EP#=DW@Qh05=01dK +&x#o&?bSGZ=ed{sN2x^)AK*F#R)5Kb||lGYY#wCP9e%{KFxw5dI|05#l~`#1ZxtIKpuPN0=vY+*AIvz +!9z$IKsmMM<@v#_arONa2)p>M+h7t?(ao<5I!T!5&l!)2=@yd;W>dLye@ErxbG5igi!*=y_b^({@3^a +_s7q)yR!8`5J?N#6SlTifNO-Md^yd@od+A2tOj!&S8W7{{;C0@y#x@~6~R#f4pIUE;@V-jqGdP=cEV5 +JiaDDTXvG}Ae5c~-Y+l-i`N}rT-)zHtV;koC+b}=fhPl*=InJ}-gBwZ<$d!d7`Sohp6_=n +|G9HkJ5`*3w*B5o3~&AI=D!yt{$aTm%w^oJNw=suyp%I&kj{3_}p{HsU#o2}qxF%O^Xvo10BRaHm#a)V1O{I4*6u7~( +3wI8iQ(!dPqyL$BUSDL|EahRLP8`qs09qqzg7Z#;bT)n4ybF}J9|{DO7_Z3ORZ%^K)G^2+3@#;ZpQDw+GElw +O;%z40ouM)#1uwW}H_vu5d!K}g&h-Lvb!PjhP)KBJ9W6J@FRxHY-jqjGVLYr!Ze0zI6RD=0+);SEh2N ++H}i`y17US`3O75Cte#P#&OEpn6a&=W0>bZ&l8tqM}G*Vj`I|X%czlkw==9@rsHH^7h+rleKHtvNHbZ +r=OBj7E(!ngN +R`bYZ01K&=WGG%+ZG3p(F$#W7O9#84IWV)!V@AmtrB$LJTmF?@MV0fFBWB7|H{qfSJHH4L77;h}<(Sx +czdQjpj6uF6#-FOJ4;^~BG6wA`-=C`GVgoKc=urLxH9!^G%97(iVEio7jEbS&tm_VjZol5S#_g?bA0} +qfzX=BLj*|W(*4?RS(v$KiCVqxva!i5XTOSVzuokvEJj~2y{qS^6e*_=4?RIZjhXNe_S3Wt;T3Jm1g! +kJ{lN;BE}#5hv@${Z59jgtO5DH*(%l2N-U8FG-45l1MQahQ_0lN97KN+x_oNgk*v-%xV@_ms@4p=9O- +N(u`LNm*GLS+QaT`Nu#0L7sW$8M12CDzbX@YVz7^ud)1Hvt|uhw{9J4%eHRaN>1!rLzetZ$+~(<_Uze +14jec@4j(>DjvYHjPM$nTKL7l4^2HZlkc;1*CMSNOhCFZ +iDg{`09HSqlDFf&cfxeMe2LE4z|8wBK7W`iX{|!$52 +lW9NUJGUYei)Zo30bq8kfShes^0~b@VFnLrw0@I#RNjnKTPNkD+sOsfY1gf|Nh{=7x)hc|96A`MDPz` +)x)@-&IkWX!TxqF-zxxOsY$kNVV}w4uiqI7w68gb@LXUmr^0|JT9)TJXOU{2vAXXTg7+lYga1fdKH|75w)E|9!xJf +AD`d_@55`9|r%+!2j#ue>?d9+{u6QFPVSNMsabYwWGBZ$2H7X3r`2?>T#3CZ0%1_gpWI0zLE`Xqz@QCjpImyq1GW5* +zF&u9$pr2!%hj_{KM{5y6WH%^ZMz-#c0OqZ4%r@rk;`F?Vzc5Dw73U+4fM;o--zD +CAU29)S)-`myi_$0R}$C&nivGA39Ia{2@P$-2R@NJ0XH(Phk-jvYIK1BZR`UG0)%2gO4K_kjH!W5zHN +x;gCQRPL(i_Tljfx1J08{w*Q4|g-PxY1CSqoU&Cn(UL4M{CE&wD)ko3(&Y^4Ben>ia$ +9Hos5t1b@7Nr`?yh1ToXu>J*E#7uvl-u_T!V|5=X^AStG?h-qFR;Z3dpDy^4!hk6j`2|I +B_DAM;4jJI%JPG^6w_4nek+$C626J5>M7VyNC?k4>AR`bNW-1O#Oz-4EX?`e)?(h+;h*7=bwL`y!6sb +uTBTP0p|IJtAn{U1$=g*%fb#-;*!i5Xum!B^ +(+2Hrze<#e)8ihR#^mo +8m;A`D^|fp-ZE88m3norr0=bP4Rz^UfaX_U-S0au(DpG$f>N$RIzps-G|DyY%ecw=cN$Q}-AYHYkjA> +vd=7pzdCS{J=qbU*9{r^$ZCe)rV34{;fQQ1P*C715d%9!zodR7tg3i0Qm#1eK)UTc)U0u6@EqLh;dWb))n}6TlVS@&R;mukQ|D9o +B!C_%N!x(?v;KMzAJ$o`OS**f!DZ&o`xRSOvUnrd1pnKfd--FK&;raFy=0tPTcJ?+t`3OQgC*>|;{qO +kxl?iX87q|Qe^ytw86BQL+8P~_t(-T@2_M9kQ2ai|CLrcMq4ah0}@A_OtxIVY(9@7=OM=buD7himF8u +U9`E?&I&-A_OL^gZ-F-~9OFkKY3P>bKv1y9ndb^JmYV{b1j|eRhRH5jJAPh(Us0%qKiD(wXoh9Y_o2tCvuS%STx7s7QBoo1L8<+1S{4gXB9XhlR(g$=g`VSsFNH=ZTM1elKapOit_qX4EOTYW>J6c^`O^+Qr#@wMFkP*=QJotI>gAY +DfxM9PFg&?xU7ZnwaH=E76<;#~Rfn1HW;c=F*&Ye3)mX(#=7ZDMGX&0!|=|VBwKTH3wzy3-=mRZreck +dyPhRc8W;Rjk-S?NgUqeqX@&p!K%(Fys(Xh*!JriPw5bB5`WCs~2a!yuHo-+uo2=SC=Ze?XYhl`B{1F +Tecq>nERlvgzEpb6-JRm(d;Y`8TL6iJCaapzGMOHwwLqVQ9 +l(RXie}(>CyLK&ueC!2fq8NGDxpOC@AIrz*pMTEs;OnoyW_qL%>jczc22Y$g!4%dF%nyW^Z&-KG&!Iz +y82y-sQ2#0B!}aU(E;Igt{tqy}iuO>4BmNBi4Gj$xx*=BnqobqyU^zyG^dCNam~Pp!g+iWFkeOK>#`M +ShIB?(qQ%L*%{rg#6Ieq#x!;uGU1F*bdJ;6Le+SdO>sp)e{M;)Ow>HwvK_D~wOgVKSOlukTI>D%8@`g +=pe38*XGZb`Wl{oA%}TM--_JOpI;<GHFbUcGvC)t{js+IojV`eh~Og{=OSdV=); +%geMcDII&7(zs6`{gDUAgS!q<8UZ}yoT9YhDy8YiC=K7{Sem#k`Y&C&gk^bIWMpJ7C=12N1LVUEydW) +Dj*!OI_`r0>G{-!`a)ad`+g%v5F@nYe{o~GX9!8&}^lqSaIPfq8%8mInr$6%qrNLXp{>$5>ANmX`xBp +oFp+BOiTIPvd&M{pvFR)x;*^v3bI*#QG%RSZ$8DhP_Z_?M4-UB=&K=~hYit{kCn$ls1IS=7b7y9p{G< +5r)ryttl6(J!ZLm(fPV?D#Rr8PdVthZIZF#XXU`vvre?Tqs`^*q#3zsyQ|M=!Dda&`G9RtwNo#!k@y8$Z*rw;{YYP(Svk#A=Pv^!mBJTT+(kbUColrw*BJ%K=sLxPlM#%N~ +0I$#3CiU6I>+^uEyiP-l+uFOijDE=HWl>R4y`ViWM*6XwwB!TJJ(la1e8{|DS;unpRn=Ph#=H^q728P +qLf+ks2mBtWrSx9GL(*528i6MLXHNAQc@Xt^Aht=+riMV9)Dw89OWPScof8o*Jo^#2JeG(-$ +iLZfCO2RulWPWzVEXKa%a&NS6$F@PF&{J1956Qs8{oex*PW3rK)MxDp-X=vK=KZtWCiMj#dT(j9U1Icue7|hSkRiQ +5Mkz-6v0X%nWd?abnMdXY&9JYP$8wC`fh8Terzw~@;`j|@IIIqvcmd`bR%s@yUYu={n*~)xCYxz?5nVE!*AP?Xu1h_Shr|6U9%vDz6 +(6Gtj~XkHfcq+mM)t!nwDn9(W2RLba9%F+HLpIFHco79-L*2fkMV;i+*VDS@{QgmLuIr7eb^7>Bjnib +jx{yZM?I5jQub2h~D}~W;9(>1uy!Hv0CfTDGxG4V;Ncm;Lk05i&}jO22Jn!sql?nw84vhjn>5@> +#u&1v_41Ex2KHenN1%H1%{S>g@4Q1%E|QgVp4_aST)TFSR=@oW8yYDi7Zif$<7xX +I~`-tu=9!e{Lhb_PZtIxm#wn=h*UJY&1D$6MP4|6R28}P6kcvuQNlt4KuH0cpMT5tc6e! +2X|#KiPL8j!xy(ozQxE%~?^FW0VJrC;xOmhM>=N4FP6(=DPtf9O=7Ullw&CwO=g%F*&UT3VLLdBBg!7 +|=f(K|TLH>wgcC8^0jTbLf9pOqehsAtxv2AkvEU5$nLBMT-~@&gJV?d4dq@RLe0|Yu~Be?>l4+tk315 +KDYR8D*qt;nD=_U9`k{|_10TV_Ci^vtgMXAojcdT!_D}(S)SmBZPMCBw^5&ghgRB|w!R=tr;3V-9nf~ +tzJ2@B-?3eTM@~G8nrOTErWA*xrFTP;y4$4BU@q%M2GKj_;9P?dSCa14VyV0((?5c@)mW4B#LkH3NRH_(Hx&TW!0=5iSW>oc}V&*mp0`L`T@j +TkYaEHN>$5X%pg^%XGgAF^)Ux_6-tQ?R4?`S}#;1V#P0apRbbuxHO6RvwUcq!sf>E?07XAb(i)aGZm3 +9p(kr2dvYqK0`h@*XOrd)aR-VFQOdy-0c*eVZ(+!^~^KRuz3)SThwJ*P*6apPMu17_wG&m_3KALwq~> +-9auM<74jgfmb{?CG9`zNZR_FZXVR@DvCuzr83X(0cNWIc4S$!DI_`H~wjq7Uc@`jDva_-uFXLH_K +y#rhk%h5U;w1=g)wcMd(BIdi6}sj1QXz#5?c{`>D&d3kyIefEGgn9dqZ-b*ewVyJu1Q=+PqJln!;Hug_5 +iuU9$&!5!wzai&dSaMQ@<8clUU&Rs_(~^VgdW*jC9wskinTt- +ek+kTEd%%{cxtwFwx9HIy4C3}LLum{*=cRa-Zxi5Rfe&Ek#y*%LpyE$Tjw8! +ap%c@(3-LegBtP2@J7aAHGl-Mlor`-+OOy?Tx47P}d{E!pTp`CR#Ha1dYw1y8Keyg;{={NDe@OvX`Fm +|!0b--_Ikoaz$Cm>V!+8%29ntt}i#1P;*$UU+I&(Wb>9Ol1uzIUVFE&tevL?4^D7Dj693l=O;J9qBX^ +6lok>3k1aLe_bW4}f-qk4Rj*?@Q3G>38S9;(N9sm-ryoVe0+Z4{RO&$h{7Dd-(8S^~^KRXn8g|OlRGu +Hc#BdYh=dY2VygyPfAMqGPK9(cl$+m4C9V%`q~q^Wm)=q*2VW(8}uSu*iP1BXqWi(z#!%Q3-m*a=$Dp +%@!uOw{?*r7OwH5ackB)Cu@455W6!WfURYp;5&(5uz$z_{s`X*kI6aVJ^NtlyX*t6vH93q?3m;f8rP6D4> +j$Yeq^^VIqyy0-L{C&P2B=MvqofHG3_)SpZU%Iac2(BJq*d?cvZbPmlLa2eeOwCH +!@eP>hO3nuf|6C-w=;U&N$2&Jwr4OOSr#l-g;*|ITZBQIire=!<;e68Izsyc4r*zjG4|@=Zq>g4rA>8 +yB)7*5RLOa$xa{P=_6L8-Y5Nc(mzSa7kLe$l2{Mytua@M#J*|b^Jn_~{vS%bKTT{t$FMneM$CPO$0eu +S`>$O}t-PpI_W2mbMlBdj;hx_pwcvH7&VQt7>5B%|`t1=TMto0lyXB(OUDz{;IX@PA`<~dPe~VpuOXB +mO#I{Q%2Ie;mcS}!|c;m{FcVjpiwNP-r?>n{JbJvvmZiYza +jma*xa*XH(%n$V5Z=W;9TG<)WoU9zIk1#_KyaH^^V3)uV263_taBQ*Lmfiq^v_-1#R9F0$r{M9F +MZm#c+cGJj+OI9j%?JYl+lzsUy1Q2YUrSo|_<#Sq?@6)(6IfJdQmUvkzu|;vY9wnuxzc3$4Y$CqgS@_1 +NoIE~#}NcBcV(%uSHTOb0W)*OA8roKDX#d6IAU?%la=I+zNN{ +V9gEp%dVp?)ix;s;jF@>gwv2y0KSipl$*$Xw=uinj#L~2hK!26nO+=0^8W&;7c|6vHtV*g_;H}kL@?H +@5K2NvEW1unEgN1kg4%5up(-j)W(fGQWpnb0h`bmmoxv`M<3L4O?S!Tq(5}ue`2!Dn>YLR?%kVz03XYxU~YC1U@V8hn7ffZPtAV0+ +-j_0B)5*M63xaRTboElz!Xze^{;nYK7MS)D@zP0ORqyFmKe|LLy(CO<I?am7t}+*3P`>3j75a{u9G{@mQ$zh`D<>bfh~bYWqkdi?Rnb$$m;#ugY`$^O8 +bYn^YY*8|JcuQp84X90{n2CE-btxuP!_uqY6sb1or$&)AFo0XMS%{pppYfBd|Ui@lWTAEt6Y?-bDZ`- +y_*Dg%%1J4=Zzd73oKN5X1jeE-X-VoX9GyWSlZrmKvdz}a3>%nEfmL$$n^XJdk>+Y@AoVYi}kDIfVa( +m7__x%HZ;XiXr{Ba2^k-G7W88dYK6&jW=U#|I%Jun!FkpWXfHu4~T;`5@Sq9r2B6%r%y!)|i^{&K3(@ +Je{UqoAPRG#C#x`Z;svDE0z;P5g2kFM#hx4$T=6Gm5YJRQS0@?$s#y`DIV+Cma2>(Wb`FJ&5h#H?>@3 +kXkyp2KwQ~5!eIl0@pzcyufZ_Gokaui4)sB1H&k^{%_s7)fWf^a!t<7K10KjB}>%Uv18Tj*|RlmrtW9 +(A-;#)7<<9F#MahUo(6Wu0Or>7Gbi?E!-fq@xgRxod_Fb@Y+>QTg&Jc$QD8x<0dGShwHa();_(uKTyU@#{RXp7{KgTln3sw^usFACB(rGm*!sjg5_mg2CV?VxvBI +?z!ilJaFJZH@g!Khp)&zN?&;41^vE!=eAHNG{ds2>2@2Bx$?6c_fdH40;X{Sz|qR#r6+@nL}?>c% +&Zj8J}B?o!`xu|b-#9YsJk!fN$6VDi(!j?VqUMy!KK7B*Nn(w~aEk5?(gP99mGdYnv7W7 +??<-kWi`hpw&So&dX6M6)#=Jy@#zuvE&D2>I2`A+Uc{z(2xu0XDmCb`mXp$n{)oE+Mbf97qjouOl#Ym +$TQxgNU*xj4BOxgU8Sd1t!hoy0K2RM3sxqLIT8FaGlB<@z4(_WozFnhtdYayIzKKH-DR8Pu15`hbqNi +1&!~h&73I$v47#H|u+lb7Tu0?BBe3^EA$l4TBFIZ2@(-ev-~7iQS3Y$s5R>*7~RGIUasTsV3peo;`bX +JjfXla5eT4c}a}L+fTLVxPNVaJmzMxFTy|Z3)*gh$#H(b_)^-z+R5rt$63u!a;Tpa>iMsm{YUn&^~fo +E`OrfTX`W)I*~`DZ5>&10r|a{d`>KARUVG_zu7A;7fBg7y9jlr1IM{7sF7^X^>ZXPN^6*zOc*V2UZu6w2#jF!gS{vbf)2pAe_BH35Uj3A{W +KV{#qQYOixTxA&Ra{h3F)6jOyyU)$`~rWmuVP$rVSagOMd@QJ#^sk5-{-3+9>4PLRBy4br0_9+h4~ws +lTz;Gwobtkzg+=}){)+gA?vEd ++l1upuo3s2Y{YBm){+*QStC&%;vUHihJk?uSI3=Gy!#FARF<()IKXr1(gkCPbIr)U%XU~|>jn<3_@kP +t)j0uLHlXIrzOqn)q#_Z{NdCq^ndOdWn`J3GowXI-NuqAjj*dDwP^oGWS3c^+4P2pYPrts15nec^hXS +gdoGLjM*6G@L`NAe;Ck*dh1$gW6Jg>bsp4cjk2ybbv1dKM>cz#$26xkr#ELcXE*0G=QS^CE@-wQE +zzUVlhHHL_UMIZN3=6~HQE*R*dy&xc8cw_$Jl9hx}9Zb+c|cgy~r-G%j_z<-ri*Iuy@&(-DJ1eN9~jL +8N1!SV0YM^_Eo#f_UH#oT6+Ez%WI9X(yVkV%gVNLtUPOxRbZ7_RaU*V$=YG<61U%EwOB{3lhzrl-MV0 +PSe@2YtIP5PMg~R&QUcz1lod2}*(M)=eb>c!Jc4cm4Z*nhWX>)XJX<{#RbZKlZaCyyreSh0FlJNij6l{DsQjSbJ>2~iqUzKd?x*J~;+h;r7y +_3BvEm9V1id0F;FMZk1e)9r=c%$sJyT5z%YaNLM27|$1Fc{1XHa9kd{c8D8=hyQ#i1r7;tKFBcw&Bko +gY$V7oIJGistnGmS$mh%S@2D@D$}IRt1^a~XIU1!Kioe!Iy;El`!-0*G}u2rIzK)9>f`zG=@~wRavS+ +#S=DVYt*Vw!X@aIrC-g%W&nx-uho& +m!_oBMK&dY20vufnG<-=rJEtYwqFsRkHX1;3kLj9_yH(9&U)(?9d0es}+rr5~tr`fU%4(Z83U03y95N +rm^I=NmXdqG)2w{EkVszLc+6dYA$*Uai_Sy$7nQAjlp>T8?SGYz>mTP)4r_w8MsEH@my+IgKNDfanOu +#-cwS}YzW3Ir0mgC`rv7ug1nOf2htoi{ji2h<{rv3QLXPFh(gYT6p$OxlNK)(oi&^nEA@J`C#QZjzVF +RXYsMsO;hKkkE5J(_}i&CfLfPsaEwAfUN4GT4p7E`Ju|;%e-xufYmU#UljFnieLTE8YtE>D(}wEPu>A +v7g;?FzDk;Gzba?>^{P(V3ZC31MGlOYW@Xz03(B`iUSjnrRb3`^gTFqWzNbML2LF>Uzk#tF2D1hx2uz +Y5P^OoocZ2a&0v)+Ze!2{)9LkP5yUy-mWXhn)vPF;tS +9u%Ele~U_5w3!}EVx?bMH;}<)iS77Fdb(>vq(TN)WI^(U?u>hyLmpH2Pk_MNts+{$yJe|Oxf5!{_x=~ +kf07Pnyn%HAM&Hg=>a~?Vlkg1dJ5z?{QBVNoGL^YcfX9|?aRT7aO2>w=cjKc`n#=P_VCZe-HXBAFCh? +uU%m*!LAdeV!Rgt_!9Em~Poe#-H{r&{>B0Ns6L=m*<1b&2KKuLSXz&Ys1A-`u%<{TH!2*mK>~*{~7>FJpV!1(FhRrNg2OXO0Z! +#rzn_&2N$1F<7S4%(Z(e2pkNWC2`h)HF<;{&E*D2EP!XSG|Cs&;WbQO!EHl40%N77(q`(UF#jtjO(5; +qmBjc**!I>fmNe-0St3`@LwMR`wz^MFv>{Y5~^s-sEv|n;RR2H!5gHIXOOMF4c`0^-0T +W(NXTjnr&5}eOVQVS2CLbgE{CN5@yu{gqUteh@pnepmx_bn%lFO=cF_46yDLCDbf~N +jS}n*8&LxNC&%XImUH;sdY-=hV}QJ1d&GzStm4}*NulZZa<(sgfQN{q;^53gkQe?Y!vP}VoxA|5*9cQ +f0=;VjMjM?T%9B1Szf02Ho`gsU#G?n+tHG{Ky)PBOSgC7^CpO%H-j*E9z@6u!yttJV$@)wF}{7?;5&d +!@bF)Nhz(s19FhaAvU{5scsYNZ9aK5Ftj44lMFOZkSHyHsx(;DJV)Ql9Fv9Oc0eHm!^yoSgvYOMQxs668LL5AM_Us!N)BsE7Wx_iXq_C +ugyh(=4i*7|X;^1sG!|?8X5fLuq>ZcX8HY)$|1)R?K?UxL3HHzP*EaG3~vvZi5vn4t!YA3!fA#3zlb3XOkT!fv{kekkkuuA=2Vs +q5MfmV64t<#ClcQYvI?|i@Q2+Q33=dvf!WJsYG{tqHVtM0?9OPhh1pO)U?I?)?_h?4mX&#Dkv=BzvRX +z4enSH8w(d%Tu6x`SyJsC0`}-v8Q^!VxT0fJnM^=xeP>XNht(asBmhU$jERF@Vy2q81_a&nuMw~ +-iGpzu6tlD4fQ*ogyXu=52t#9yH?$8YnxT_rF2)ZGkD4o-qU?0(T#4;qfe-1v;Bu +Aze@m*@<&lIw+HcArgGEpDT*pS&@dOiup$yMv?eChy;VJlcPEa5|X;X#xrWvS6}gmArUB8$nT(xb-Zv +EX`6FaNMI!=LtM)P%}jSY}(aTP$a8ziu(T|BV92eb4J{?9wfzG^3Vj!inT_gHmqukWO{rCk9i=dcSX{ +|lmuN1*2y%f@A5JvnHq(j4uo9y(GSdP;6I>#URNbi#2y3f{n*>mC0F91b?ck`<^tyE7{%pmz=dN9LmZ +j)l|o6n4Q%K^c*96VTwk-JXdJ3wOACW2-OnjxiON!trl5ACuquk`E=wmc)VL65Xt|j1%MpqZ6zsDE>e +DaL^b%JiDnmbED-XktGoix_*9v9kiI&=8X4cjE%>HoUy5~KP?M28W8G2H +s{R(x(Y8$KjI9^syi(K2cu{ZHcy=LsB5}jI1pTH-;U_qKPbxh8SQN++sOV#b1#6DmE`8u|bKjrboFT- +DMPK0?ld&{oxP$23doIbknO0rt-xw>R+zz+ZF<&6bpSYFZN7Lmn +Fc?-at<)9peMl8h9| +74IdiV^qLkGEK*%31TV`Yi5T<*w8?a=-_`X`jdkcgCaHj4jW}0|oCQ!yCdvN_fCR!j*4w05Wda!UJJc +JvD~-YKT2+&ipUUx1;`U8?9j7@d(M?v&oVIWxATs7$@U8K8HS|u&VDYcT+y6{qOzrmw<0mn=A)pw2S3 +rSSKmPg{bkq#wH3<<_6f!6@~Vej}hZ~0cd1Vn+_huV>(AHQh~?if27YN{ky_y +yv%lJq(Ma6ara_u3iu6}@dB{0X{O+cFD?PL<67y~^E_KVtt!iOjGga#cKv|39JPz+kNm4!s<+@r(7YFZ$i|g +6F$};8vvbd-c>cJ(zxA63(RfCw$+CQCVI>iN3#Um-5NfR#|mi8!Ob7+6umO(SEb5M;EVPO+Ci)OV1l%O`0{aAviZ`u +bms3C6i1kH4`5(;ARnHjCV3+kuJ3SgNH +aqUl~uWo7;WdxJmBID@}xE*8K29t%{Qpn;Uj~|AD{skMyrAOJCEg%N;Lpv7m$x^FFWC$%_0)KZk&+M9 +xW_?qh{g2$DV4PjGhr!gt!m_y|5kBIj)+jShd+RSi=-oI^efo{wDZ98zv1@G#g+m2mEY=-5no`O|`OJ +ve^Sg|EdO7R;$!ys +yUgAcdznQOLce<*xlw^y3!bvZ=8JLw-jmv7+zWy9b+Kuun07@uXiv>=Q32Gj&HTJg)lxikZP)b@2Gi{ +THz$b|UBFJDJ>7Yv7;bLtI97Ir~jMyZu8Y(liJ27zSt^~6YM48qMOuh3Age5eG)1Tkd#sF)hG!=4+00 +^mxpHp$d)YiC*fvL|WVB+7ywt=l@0A_(g2l~L4U068t8A>#St3ZX^Dy*g;U3x&tGC^8pO&PWxOlCM(S +pTYmSwwZss(Hg*!DRxpA8hTRTA`s?!J_`k_G1=+!3nGZ2|7R_TeA$*u|$k$_E3`=VnHzHadYDzBTbA=P-mBvfbS^gBY}iQGI +q<0ag!W{hyu3xoc6`AoH*z^wASUSN#R9v?Q@hsV>MF1-PrMhP595V=91Rcd_GWHhXTlz2nSlNMv~(rzBpqscyVwoo|A(E83AZd#D1K`1K| +@8GhV1rLjt1IA(%cMLGqDU0P0S92AVrr|li!D^Nk#hOAClXI_t5ZkVwJY!G6s0G>~Yea+9L`8@{T;(# +d#8fgFStb4qyvvfdKCBwyy!M#H44&<}3j;(fxu;c~`Uk!I2+bggqmd1e7#LJ#;L8-aG@EeTugW)f^G| +NKKishJsIjAupwo!#n-FTNN +CyVbwJhlrr~OPeF!y^iqqv6V&B#Yb$hrL(26{j(JTp(t3*aG$zr+NMb_k^=G?HoVVvi`lb3HD8-c9cu +QhriEf_?^w{+%LXw_iyLgpTfcX=sF2n7rM?a0)dR>t=>V-uKnx*RuUgZXa ++j38h^C`&7i*@R+O@6@6{I2Us0LJLQ>e4#E%MkRV$okZypac-J@wh@l=hlB9-p|zRzpn!&lZ5TAw8oh +_$$q>R@YH@ib&ChO_^@-3@3mMyJ9o1+vMX@mB?ls4D|wAJ8wl9=^E-xV}A`bXvT~emOmE}KZCk^yB?x +aYq+JNz1%0TKUJbV*HZ_I9n*)n`25bnshWOz2tc1aFos3$k&!X2cLpkI?&Ms6oG85$M|miic1kt{BOS +Ov??mdKZ3c8Go=h=fR0t6G{g=t{w=U6KcQy9u)K*hNH@5MTrCGK;#T`zGLUjzom>X^glAa(27kO)2e0 +5{YK9vwATF@(m%jqy+BhyS;Z-Ezwq7_wFl=WMAgrwJ4${j?PFNW?cHifcf;eMq5byXC2o@GSZc53^AUwBrllr%556dwVW-SIh(2gJ`u<7>q?MxegMsx9%+<@2f}Mwyc%n@m^kLr#T6zK4lJKcbUf54nud;Reo|8%YI+)2(oyM1ha +pe-;&9+Xk?sTlZOD}={9;$z|09XRcR(Ic2jpA!*vTG`kn|stu{rGNW0_GzN +MdQ8dB6)5vST?h(M#b1H4?DRm(&jWb>P1&1^;BZizvj&_rR8m9RY~#G<1e~^M>i~VIxLi^F=DkBgJ`^W5ntlBtu=Kc6*5k}c@5>G5mtH=VakKivu$;&;qhQyh +geklQkl|xNy&c5QM#0OzL$iMxy3QT(Ls)AM@l%;nJtw~92~MIOlK +29#|HwZoF9f56PqiCjTkdlutNqj6{r`tIqn~4Dg#NQLFBbt3ok>%W*7@ZLJ@PDqnnEYCEQAm%iu40nO +1kOCxv3~kN4lce|vKB_1p8eh!DWb%g%#DgcB|(;|n|}87?>9G^+*s43al}haDfZ$ow$mAW7Tujv^J4N +JRBW#7>US4*$xvD}|;HOUfC*m=ap(gjk17Ft3F2*R`}QoGmdn@_q@Rv1kA(?eUI{e +R)6qzh!(*dXy(tj4p-X$eY7*SbnBT*O2!bW=Ih*5woz3u^O8jwYBYS*n*LuZe=!Aow59Fvz&L%5159) +<1lE~!gk-6;H8@s03jyILtfFlpc0W4opvFKd$AaTUPBpyVb)>wytw>vTrNgcDGTfGfa?6GtSx#AtFTDXuGEfcXN8pu42VC$t$Gf<7r9KyrX`^8NQxB&9XFvjY= +}-;SBD2NVI6XDG>nz0JXn_$LGy!sVoDfB-Xq=4SYj +%@sY=xVeH{kW6)sC*+Ik`f&f%cm%d@B81r&V|NStLzGoL|`!+E5IGLz9WMxS&#c0*TcXY=21b_czcW< +yU11#<%f4|8DksLWd6N&y7LoKV=8u-M+QN3l|zQA_+2323gRnSq2h#Lv+vLSLj(^(P?BOG6L=wdAR|@ +0?Oc#I&Kfs+}x5)N$roosO*97X)!DN#r$!O(dP1tk9Q1hG6L{1i#p=UcF-A>d~4c0^*cJgrGN=+7m4k +@WpOGNx@tn1e~2Y2my{gh7}Fnakc6iqiBYY{-AfGNz>|qpYHrZm}YY)1k>u^$?5TbVt%=!w;v8BZ;!s +7UR+a-pp&Dn36~6;Y_?f7vnjk8xK*g*J%a ++&#IDp_QDlUrhvSrttz-4u|k?oCSwoKKtK_|l~#8FBpv~HLLlr|1kQ;G%6v>{s-=730>_ZklJ>v(U$Z +Um9ocI7jJ&ZHos!+>fscpb0uv^MQ_xHFH5n#@rq-1Cl9+d(jX`MHUufk>Vj +Gov_Gnvf$bI9sGdBc)zN%XB&jKz}aIWR0hKF#a$5NRHgK!YbUps*%I)6J^tH8Gr)=i%+jc>Y81N%>@p +D(CR$qa^KF364SD+zEHapqDQhsG0b%%vVm51@veXm`&^P#uGQB3j3GZ^7Z8UnYFK=4Cjf2E%T*rUd1$b5vH=s8ajGRZeeRgseG)Zu!~qyrNz_kHwebDIPOz$ +M4|4tRtU9_t&mfF2pGC5B_7Fx-f+u3&iZB4wWQYOx(6aoeA@PIhranr&TX}x@B%C7E>27Fsi3-gFElNMY_FG*+Oe!aW1bcXIx5mI?FlzP3DWU{P;IHyDSh4XCSkPLSR~ajHpZJWA9t{zRP)k0fIb~7%mH75gs +L;%qha=rp;lEB%_1Rv-ZUU^HeY`J$AAB09DI}C^N`Tav(lUiHpR{pc6h6%1+gZZ2N&_YdfJ|#kJ4TeuJmY8?UJD32-=6}=U>SLMRV>nZm +5-va~-pXRKA~_+2&0^ZFV>(WS6s*gRgbi4pA0oL6mlU~zq(~lvMlGOL2^BB1d(8zhe77u!?| +La`Hs-R8rYrcyDZYnXwqmw^8(=WW(WQgg<@g@nN%hd;!V_8smkmz#3NaS2kH@%u@x~c)GZJ5 +oyn?ii%S+C$S7lNS#pLEYN)LSb|!^oSo!!%i5RLMn$bkgh!A6(A)i8CT9l +lbh9<RPo5KQm$0x`^OMxAU5bX#uK=8lg8TaO7Vp3S)qWue)9;@3Bp@ZYu2&%R0XW0)}=nT=IYr`GR +fRo}N*X9#B=yzl7~bXkXPLLF_!braLBCT9LexePs$?pRH9)6=7xd0n{=>SY}?~a<6cm7O*>C>ne%`9% +~OsDP7;qLsdF2EyeMSbnsKewKL?Ewojfa3HxK~1lJo===yR)H9EF2BWGtmS5EwBPMTJG_%VWXnY()-n +O^ZWwEnbt9+JjvjW&RY5!Om|o@?~JO`dXH6Tj1G#Z4*_$ +7Mb8wJyex>5@fe@LfaJ`3PZam=3IS$o2Iy>R&_X!bjiS6Axe+6tue^DuCP_M1IiV&M#OP(iduYx+iP? +LQpsC4PVoS>D{^X5l6GrESJ67iwx71^vc>M +EWULZF9jdpPx!lZyXeF{_jo|EwW)G5~}}m4*dw0czAv3CzG~Sq!X{tzMF&-l;*;Y2Qn4l7UHg1%zUDT +^gA~&_4p)ecCwl`IiY}?Mh3j7aii#_Em6CG%!>ImJB9?Z6)qEX6DKHid$8CeBYEOWEbOX{K13;d+9}MT0_wmqw61E*=Qo4X0W%U=dBl6eO|8IH6SRiQ<;Af};BliHX}4kEH@ftJ{!?n-z?G +cnMPP<$Wvgz@%XiF!Ph&a)e^0DwFr?O744Hzb)>SK+xk#o4RbW)MAwOjWi>Zq7SZ2k506|5DnG7T^_- +6{5^61L8r;94V))R`L5!h_#iUr@7d3%u`{ad5t#mOR)ISY-Rt*I!5K3kMFl;%OGKU|0bsdxwaZJvoI3_~l_f#jU5Vk|UY8MmcO2a88L+8URJD!#+qpz2%LP`>SHe%?0>1rNX5<9O +eC-<;Uxt`r?CemQ~0Y3&5KOR{}D<{(`8n`uxXUOA-rME8CHC-o0W`TW(tkvklKDjp;-ykDkTEJ0<3UBN^-op!UhOtbq51qRVk-F +R1fv>rEa&D*(Y@>lAyAJj6_4nEGhPIBEGhj0w#@ua=Ib<5w>;53z +p(W~A7MJYg`(!<#wTN}gZ3GN5;__5em||W{W5ql3SL@b2S_U!Qqxtte(nPoSQ8N0eyw~CQbL>BgHTwPgVM3JQQ%L&+{s0#Ch42}1bmouHG+9Tr>X$Oka4zy +PG9M1rPX)^p15eg(lN>m*eSKpyj4It_0;icqxxL9%Tb^cUDaKu3a;gVvst0PS2hrL7{%`L)&kVie7Iz +-bg72{?JB9~%-JsY}!6IsP={hUPw-yaffR(+z+W3t0dFc|;BiAe`BR{^&!1PZy5F;@kQ33E1&C_aUXI +;x`27f^3uv>ecY$n`F*CX;)i#+YR%^)jOwaiPeT|}gR%r#JhX4rG&wwGjw<3dDlADzY?A@1bt)nlaH^ +)RiROfB7d5~ew?BYzHl4sC1HbZV)?zhy%+{db4o9ZU}XdVX+(u9AE +^d<>=I>!0XC7yNql(<}L%{soAAHY_Y9YhLlc(3W&XT?s_9Nc=nL{KxTLO+2|BiYwB@^?*jEX2nbNw7X +1Vt#d!eH~X$PB7g+8**IrZQMmgvgf4Z*Em@e3YnNjX2<0W}*&GD(*fxvs#U!wxM(B5u%6 +->TZT7eo59$g5Dv0evA@mwIUx*>HLR@%oT=#6;Fj-^T1>!`4XCybc7sesXQ4nIOZi`+#22|%$__rS}z +BOKn)R$qsr@whxi)uPtt!?tEw@C!>)HZq6^|t~q{jKONG}&*lZ-^beY>nLCh{tSfnO_Xuwd0hL7*?|f +9drFpzQip29*F>baQ5vzY0LQrmXQQYQM6=3bk|jRUz>E`?@?Jb31fy7xO>&EFEAPu^GKecZin1_txxX +}>{{v3KcPq6SbZkOiZndm{cT_B*SFyZbNyzfckRo6d-=uZUDQ2p)<|eg`Ih$vZ@xh}JG1}^;>r6;Das +(piw5l>qJdZOJzHiL*#b|eIDM?{n8lz}Q<#hD?b-g}AtrM}sCdM=jfR;bOZetFJXBqvCvDzZP%wKcDF +7=*Slr7)0RU`KVbB1CR}MEhG4u&ZM-JNEKr;5;>oDErOMnmwgZh>+`O!-=L#m&>%bUbZ5FR$z+DbsBo +NVNs$ns7Fm7AQGePAh0s4Km@IzJtFWw?D&x=wQHP6A99+Z-N?96L@lS6;=UgqRblwvwrq=nWk~NkJn6 +g`eF$qg>oSY00?Bcav^eNB2CDEL%8r-6h41(*?bvoP#~dsAsF9u-(46Eps}`Pn}_LEHTEO?YZgQ#GU9 +?7q%j>c+NT^u7Ka-pAY!w&*3mUhyPE)&VTkq)HTl@S7K +2CN%QgO+oR*Z9EH7}rm%;-O^VSjrY^t7Z!dRu-BS;KCp8jOs>GAmBLShaeW8L5&*WwSw&Fogp#)7|49 +I*#np|c?{;GFbkt`c}w`;yg5i=P;s=B+vgbeav2XMJH%U +{Ge{AS>`sWGoRz=e=oiEb;)fHH)T2FKl|-fS?_kl+&8Ltku;Q)7qsIKE)xoD6i3&I{kvHYpL=nzS4IJ +u2+QtaCT$(LWff=J$X3w!I5#n9!eN(C0eRzoqf8Ca@^fDRLU2tMNh^%ZbM8x3oBw79H5R>dfI?rc%}%#a3L1!agRP(&>}@rB2Ek6CsH;EkY4G{yY4H3xD!a +GqtQ<%c)}1CP-u#4qD9ohtr%9wpKE|23%gL^N)3=+WBZX=oZQi`uqyIYcY!Yp|ru6XNO|$a$_8$GWj< +#J+50nf|ThB;3gwNmYJ^!%x{0tTVdUH*;FsUvMJSQjX>_Z3VZ=cRqDv4zHHM}#oKq~dF5HF@$$H_i}W +qS1=_=m1LK)pv7cP= +wwiV&y>O!zO1vDvB=ruEG;@h4D`9lg@>^O{tsV5AzAdxNxeL%o?;c(UQSy{2(I;!X-J{eoWlok>(xlv +QPKNs>%CcQ|99;vmsIWuQPsdr2669F()eaL=s=kPXupR!nsIJ_g&C|pEcauNAKmN)NQNQ>(8vpIr%dN +o$nkOgw?+*6Aotz%*e>^=yL!z(B_-{KG7sH<~FSahWe!)Nd;MdCzz=y-L4{y(*$+LrVyZYb8fBX4z>* +Cj6E`Fw#|3#&u$gcr+GVe|BTeqoDQK|U&O1Fy2q|i&c^gGzvA_@F+wQOGw;m<4l^ZBo_mc`54MVaZrZ +W}**8yP^zMRGrUA3U%3pj*Hv4O$B5(X*|sXTbu~mB|pTqyW)jIB5E=BIDaexLFHJosPc^$3@;ys66@C +XQ*7)H?YwTf2J#e!e7HrM^A>^*~2A9(RnVSg7fKoq8ao>O-Ln!R~O70;XmDI}T|HgNj(;Xf7)09;d#lO`h6Oy +R9cqn|^v}Z)zMspdv=r*j=tWMH=niRsyP9P;o05>D|k-)jj{u_pFuI}5RD%U`uaCA1Q2^emhhEG +WbU-9owsqWBgUoZLa($sA;g@K_?8I6Fn2#JGD&1@HN<#pvSJ#IPII1V%vM>f=8AFf+``j +SXC18{sQNF{&iT@wkBXkLca``N`Qk4xvZe%U4O0>CbSd57K8cuNpFUu1Si$5A&FFp0e;kd4dZXf!kM3 +H{#aD+pNZ{jZHA^sx>>*7(7g?1)2+STKO4id8p&q@ZGiy~&+|16-6{f0$pQa*DA^Z +oV80QSs{Fx$FesHX0CUY3%f%uMlfojz{b6e)7=WS9rX;%QRpb-aIU^{IqRLC;W;o~nLfJK&PgD|SjlZ +IPv3TXK3>^-GhxNmK-%oO|vCdRAy-gzT+NI3#M#&*2yzRrH6bLpmt_YY3bL5cXUkB6rRUpqDWZ`AR^I +XXT%SWh7+c~>XP2@hR_|A=9^$@tDk@sr@w@BW##4y}>;_GthBLz#(agxH>(9-klYAHSc#u-v}-{1dSe +LoqT2#^Yl6=ph(EW3CWn?ARpo;OWX!Q9G{43#-8_I9Tua1V)W3^>dUQiyl@GkTJ;x^>8wsCo*)n8%J} +PT?AEBissknV6vXK1tKI4%r;w=-=s!(YTUwnbm|j9Iu>GNy_|bQB_@Qhgm~ez+z`IPrNzkqPU1ASVJ8E>u +eFz?^RcIR8C{WR;#>0T8rPTya$cLOaxutyUm>NBqwkv{09d!KF6NbPE$tlk_r!=Bw#4QPN@U{WI#&j$ +V>h4$BJb?{2l}1N?10diA+V=|2^Mt=V79Nt$uM&?Oe@kcCfF}BV%S*xJ1ycq*sJDe1`YqLY#`i7@i$Y +Pd3_g}kGRtg5l?t2iNOdLLL6K}sy%6X~l1{mm5_KsHJB6nXooi2~^Qyx1Cj=GsQ!SiS3`x9}JCxPSR* +lz&az4JO2*)>VDi{@d%bT;pnJE_TjtLq+IB6&;6LnwAnc7GfiyyBf*3VW1{Y1=KHwzhet0f};~AGXE +D884Lv+5S<{tDCsgMhN>{lC_)su=9CzriHpLLsZNd9px_|}0o6ARg~XS07--6xLHly7CAZ<*D9 +f%^d65zeXDACv8e=*V0ZU?n!%QvaEpfWmpti^!1FhsjYwqr~cC8f`DYJeKGBe9*V`Q`=ltdD{fcE@}P +W1!^Zn~-;;pwnjs`ffw7H0Clet5rqda^I_LGjj>>;Sp~)6@2cRl?aX-CojT&Ko%}F>Bn@OQ2!# +f5Fh{zQMA_x6qU`$;v>`KVs-8J5#}FEoOJ~Hy+mSyoY#ODzK!k|MZKINS=6)s3;P7C;!O&ahA+bhBi) +NeH`a(VUihY7ds>UFHgwRMV+F2%y0xeqBdzuMFv#Hl`!9C?T`u7mqKc(x!bIj$vTiQPkD;YRb47!Z-z +?=#tEysPwGQB-fY?xkwe@bi>j`S%LgZC9=`w+4t_|5~X%sLw==`r+B73|R9IRgImo*vsk3Q=}t_V;`e +N1LNUoV&*XSOFWoXK=X>rY_3Phvie0hLwcQ5MuVL?ml@vWZ1n9z>Tri-V5_PhoXq^o7VI#<67I6HYq* +QB1E!_$iFv6@G;I4LiK(-Y1y|dp~{};pa)yiVOO#RXrn>`UKTYeKvJZ`-S$Z&bCfKpr&2$rEOUsOGPtrn7uY6PiW_szrWjXv!>uP&B#{7DDkX!W#cL($ +L@$X!LL%NCtLl-2tXBs$opo~8-UT;q +hVUdXM#r6&NtQ{ciI^S)F+2bU%i!vMpn{u$29e>r`u``TycaubU9blpKy~d7P@;)(JfHjyee4&L1C?c +P79&thLe);GTjc6`mz+@Zot<3yd$(FG!?_^>0G2H8s9r?mzfTPx^D;Me9h{3u_o@~B9Z#oz8NCj2bg5 +Bd*t%`ROO!gTMpujS=`r*ixZF}E`XBmE +ZrSY&gFm_WGm!`eQq8LwPAqcoDxT19@)P58t)C#*i*Ve8oy|B;4d|0SbTI2puFl+5j^9M#lt&$%qbj1 +jyeB$>X>us>Q0(#syoZi@+pH=`!i9wAU-Sp!OsNS@9j@Q)MMP +L(W_}$BJ~kY5`UzL}=NzYhIBzvb#OYlcX-qa1Pyu(khQmO|+KY-#M3rj-)33N622nv5{!%IipG#Bc?v +9FTHHgL%bk5fz=j4WUY456>hH!-Z@+OQ1e3R=s$)b)lY$8;jWLmdwSFt~ob#DzW9gOkKC7*pWnc?SC_ +LWXw#2~HPLCMEcZV!6TTbpR$xfDel{6$lX)Kl3eCYmp9v4DDy-r|h~JofCE_T@Qbz;3cRT?`3ZAT4c= +*y`(`#+RX)T#CXaZGA*kzoB(kH#_`gFTKbc6*INDG9mWYkUe;L|9yDKv&6#+C2dbd^ +}poaK9$#T@lr*JJ}FpY^qK_K`HMvRj%o7Tw~+vt9Ggo;{QI**yiQ+NG`W{+Bvh70QU-?Sude*U8Riw9ICr2OOXj)+(w$Qb +Imkawkw%DC$BMK#&Xqmi|(1K;JH4)vj75}uVA~vIc0|`EY?{IkxHU0bVz(NU#pPXkpiQq`c!)NFpx@^ +a5w7B4W8hIF(vd|UdpFB7mAL{%?FYu%P9@NJoryKEF?rJQiCX;bw(dbS3+7&7Zr?(9Y*9(WJN_fU(-S +ddQymMT{lRf3Us8?DcP}FPwuBi?Tl#KfW(Nr23wD<)(xp)$tF73XVucXgV)E(F?zy^C==Fl=Xxxt9VI +zr896A&bvK|FjY@VX1kET=%i|2%IjFWN3VVZe88RI!xsboD ++m5EzDshW!IvzNjat?d>2mWp9~;G@5Cbhy5em_NM&r0HRME?}F1r$-i_+Z%FGbi-NuFc*Pkb|}ezO@! +j3fCH#S^Fg5SN3ATR?*%2~G}9f-iPImjY%p&@WfxT9iyP&2D#=*|Nbu+q+O>XHzwvZd1Y(-5OYDF|ZX +Vaodyl@&(`cD>5p`>pD077f?$B1QY-O00;m!mS#zy{RLL982|vETmS$b0001RX>c!Jc4cm4Z*nhWX>) +XJX<{#SWpZ9;fiZ{{R&%-$KpydVU?3=f5PR}k*z5F_7el%xqzB_yW?(N^cfB)UP3;YQ6 +I(vJ2oww^`#n(K_sWpoi%x8-gzYb?B&bBNVw^&LWN1%oBi^{GR10)SBiu3C}v6>C|7Xrc- +vzM%G!JuKiW`GoSw;y0BcPef-wXVF;<^c3AmieZ!Z2aHBO4ADSy)$T4Wu)u-kL-$#;41x}}F8mHKB$@ +8h8sWs_zaPT~ZVMr=?Q2Y&jv!~O@U-RkI>2x~5%Fi;^0@eP(Uu`%&IzvJO$ou{>%ozOdM{H9zQjEMiraR2SD9imQ;5OBF88Fz2*Xpf!Bq})Ug!MWF$`Wo3-_#E?&d%bz;D0_BRJ7pThq6!=urPu(k!@x +~9m^?!PhtLokJFOVWk+!ite|xkE*SDFl{)Ovv3RT2D$#lm#S)pokD@qd)CH{bCn+taC#l7rFrzmettt +Phn51eiVh(DEi)tl#U>&ECIbp{FmVDQ{i+F2y5)h6-028>$?lc&y{EtWZRV&8J_TDs%ZHY4BCh9SecJ ++anBe|0r_XTTUd|#-``#}|2;xf;Z;j?G+ILN$&bcz?J%V#NH@RY-%dj?9yU&nL4+85FQKwbLT<#ei{C +O!!6u3?3Rwl*oopi-Wstu6PSWVZDL7TliVb?BVd;B@LKspuM##{dqWT4C#rM4K-_vn3!&ZVCutHce6> +1BrtgoObzf-XK4e^x&Cim4aL<4O7rc(JV#^;_)nwxExlP^QIY#OlDR^>)?=`_=L7$?@&0+mqWz$G6A74BW$CZ$BM7ugBR_d-P$PxswCuu_b^+n{^Y6@%+ +FZd+^(N`q(O1Ym1r))eaAlSch+s&!r6lcKC;}pmJOF?Vvl{I85e?6P~Z0 +oYXWyz3jVRZ+kwzWzo*MUL7}90?8I2UNw++RX3p@w^ui6-KW|4aK4B-vUJ35g! +*G1mT>Vke`LFs4YSs3j&}apjybAM;%-W>UO4FoRA6deKaB%}1AfYg&Uscn4*%WJKLCDqNt#MK5mINS+ +!hC%fUa**val`pg>Q@cMGL1J0BCz(vqit0YC5}FpHAlTkv-R_l-zbE!fwzjUKma&m&e4<(fHqyQd3cn +CdAQ|L^@mv;Wd*2U1%pMSccPC{c0HJwBMqQs4#SPe+8PB4G0`1Lr=p>kC95#EE!T1;28^Pr2F&cmm=L>UH8opDJ7_xRPqsva(ix(lm(7p{evWQ ++3lQZp(Hx<+EoI0($Xg#o=D6%DAF!^qCPC!+Ndn8jw&TRrU^#7$A9-*#HPs9@DYr@2$nLe-QjRMAyrK +C)r|MD#BubZ7z~Px3cfsvmr)WO}MEtdCFr+p2ce(?G +(XQ%Iqi!YKwQU*21S#hL13dmBdJ>2;O+9zLQ*^-sb`lIX>ltW)JnU>57;y#Ue0Ho@C^i!zKOZgH!U8Q74@kI*p0h>7l(q0QKrp}OKLC`Z(fn%YA9wHmZgT~r!sDpQU^)cj)uD20Uv~d@Jf9#s+MDwlfR +Jn6Avz>Hnd0DJHf$x8>z)-_@--@$u2tQH7YnQ{I!*pn#gZDz)h0owc}mlMglTg?UO4f_M}eH8~_ke4Ng6NM~+2i=I`-X)>0vAgJ7Qq{y*6v1ym)Fr&}xj!i;TVU7 +WFcT9o0R5;(qS&}pD;zy%c=VT&U8T|mZX4X~h8Ei|DB*o?3=R5kY+*$qD<$5C62+e|gHk2WND?;9 +W}`4GTRJPiY-XEHSFPZ(~o1@SWV6L6kf=5OP0UV$U6cCaf!Zm-!qOhEvzZd^9oi74xXsp;7I6EB +JgF|*}e)f&NxgFx&yo`L$)qj28%EPVDbyCet(hkv>F^D7R6HFp6YbgA)6x+Ys&J$I_mbFk_V97sy+Ip2!t=X{5l4i)ZtNl1@wwPGCwDW2aNBW;;Q<9JcD{rP+zvzRP?=XU=3r^n;Nu{YtkY +DLt|-GBq{QU1-4Z8q%fsiO`uEGk&2h(q)RfF3}crtauK>K7y-F?Ezi*Ts`UCTQRw)lE@7_`I{{FlF{B +8&=40BIzXuOfO^WS_OTaA_W**c8E^=8fTs~E{TgJBxjl{M9(Sn(}iu{8!iF8wWv6jhRe+=3Y}(O0xAO +sm!{R^=8{=1-5!?pF(8(ld14!IoH|!KDt4XCUOQm9dC(j0jZZ@ISo&K@|gk +yk7C3&D}oxdwd170Iv{C9|r8Dd}OkF5E}#x$mB!P2jF+1E2u~9?N8uDc}L!Jujdqzh%~$c#_k5!VscID9kJ +J^5KvW#w20mf9I8fsy7`8cGIKx>`7;ZbN{X0^WTK2nJ?nrFM-|ia2HFRjR&S=wRn4juBz0E5taE2f)4 +tGE^ED0=NvZB812Sf(c&qb`VE|XH?%BCGH{+Zq1aCD)a}yMN{GPD`|HClB(~3j4>MQjJRes@z}r|8aJ +sG@gPoWs8xj94EEdwPA85U(#f$_vl`WFj7C<}h(0@JVQFJ7P{e{*^L~uO$R43|4Ta7Lk?qZ9lNvpd2~ +6o-j1oXQHQFx!O=$b-{~>LQ2<=}%TXTJx^sRHjzY(Sy0E^Vtln># +rTx3Q`Ypm;Zqk{h6vnP%Sb=SR5W#F!`S)s!o!SB%*7I+^d~^Ek>Dhbq2W@I?YkMcw$UEpx9$OB$g!rr +J2SXF<7_7@83Xp7~AkS*RQtQLWo7m&IgP>BY=Z*VSp!>`_!&p=g{`h!&0BprNRsg3v*@;w%70_qC8!4 +56`B +3NSZlVm`OZ0B*n2l$)zgqaWesbwM;~By9SMXB6#lTjUC47b1Pf*Yd1S6zWd<#$XAfR=sm|0NnnLRXMj +}Fn?Pv@arl$HMM8P9z=%N9Q0YnpMHTzvo4S8xAukJa*FH2maEVZ|KmV9xt;rZsY(?m6~oJlVzS1+-0c +{BWhJ6xb&al%j&80^^))`iMmwwc*j-<6+@jT-T(p(O}v_|HfN#8>MzM;MmXm9i))m3XHG7*m{P!q&EbUsnW7Cq|q94 +Ty1B#EBsWnX*VoHhoi&cWP)iRt-uXR$VS7%NyAj!(UoSq6zGWuBh>*zMf6qMRJ@Cg1n;f=Ec2HlxFrD +>rS;X+AoE*jXf7=A*)g&astA{Bl1ARZg|LK>WL*nEP%vH`OQ9~YDh49k;K6iZ`vX~D$0W>9_JKH33us +s7S;d(!MQB~R=|c3P5S(Q_?chKR0|4=gGqDV}ymY-~d{0pC?SkFJ8x^@UtB5_K5F?Z2CZQdA+-r!cBQ +P1pWUKHa3ML0Tj|l#n4((#wEl&Q*-ZK_#Qn_CROoBcIl%L<6zxCMH1k7ji%{qZ51Sr2m@)zOV +4UzNw<_)|IdcBt}I~sic0^wsCgP74S8yxlr%zl38y*zv(x5^rV(x}c*;)Br;EtO|PIu1wXZ}J#gg0_% +Mq~@l}4v$_OG5hnr*E=e}U*QC8GBMde#NRd@yAkNKH%W95 +jhQIvN6T#@heLK{U$4DU@!UhRag!*|sH2a@+(Y3mHC;u}qtU^lp^bY<2l#Ta{K~Uons%WgY?k}Qg6rUAbn?piHf%Hm|DnJ3L`yQF?GbEx5B=OH#$9V(p_Q;WzM3F|iNNd?dVCBM0gC5VqIq&kt0+ZBmmhpU%%l1Hd9D2RyUhn0egpN9ha-6aud+~zVp9Ub@fdy1X +mpSh7tam`fv|m3O&z<&hGymD_Ss+$L6c?L=>=e&A?Ex|TJ)B5->g{>#qPXP(B-}z}*z8lXir0YZ;OIH +CUwF?y+l4J+D&|Ns-ttxdq_U8ZlPzMcv$Hdc<^EC}Pr{`PFHJP?Ufa~*7JiSt6d6EgF#KBKuz*N{U3H +bpggK(KNSLWM=c{lXHjkkz5}=)(>&It8>w%U;Ss|AH9Fvgt=yVepPD0(!G2bv|grv;4s;(Yy+@;lXOY +OBm_3r5NVI2VjiN2gd%H7ck32QMlp(u(jg;1I|^+JtqMSU8}p4kB&RI*Zwd}3mSF7ZHy`}-o5Pi1c5S +J{YxXgKowUfS=;Wecn#R<1K-dfUD2)>si+HA*`gGo~ki +RH2{`xi1^^y@nNZ4w}$`>L%*2j`7>zP$P(x;_y+g<}Jg#sJElq?C12ZYM=&u?ADVN1%mL+tf20>r1(GAKB#d-yx6hP +R9{7TS8QZHzx$frS{**)*G-Eto&05ESQ+}o}pkOB~_gOkd_3RchFe?&o-vAyJaPaT{LQ*&9Z{q&;}_Z +1td#>s}F*=f!zd+NTHdYUyk)nL5u(>|2A!Km;+z*Gu&MqZDNXXMjxw#m76J(C0NIz`Ii`IqnB*MgsTo +@8=x3q!mGIS69VLKD+_>vXhKMT%<_d14r0$IPlgW>i^nHjHmwd?TsXRiD7B*K6QXhxaekJG_t|CEmQ^ +^;Z>6SkdT><1P3duUn!tA-gd}wVLTq5gVN(GG14BMU^~x46am3K}RJMmsO5fV^&x_SstS@JqvRhlF_g +~!3XQ5)qF}AJ4?KuF)!Hu{2|ASDFpP?Vh1d#l?zf78Tn49xxjiV+>o6+#8t8uByFArq=;c;)(+BR4fc +wu&g-KS0a4j6sz(`Kl&5@T!)^;ffFdDRg`rgjsBu48C82$H^0nBlHI +~C~%)XVAX=W?oobEn743lPS2ZFCF2ZD*7*VTE)uQgg;YjfXtZdPL0cq70p<^IPuZZ)WUzZ_d*Mg&ETG +}(C=R+TK1v8VrOrxPgqE^7N;_hoUC6rQ^iWVIcKQRx(Fd&9?t!64Lhxox +0?mKuLCj`Fmr+9*(atX18PA;_r^pP37WYsRD8Wb3xOiHdwG(a7DEK~-E=h~bW=?K}M0Xa7xCbXeuFa= +Leib}>o%Wg?bN*LNP$r5=mTe2F^<6+p8aiYIhY&C}TvxiLzq{24aP!u4iF7lBmH7}hTOC_{#8bGEu>d%b50t&|AJ0 +5&$irESC4Xs2vYF_9hQXu7qZ!!02ofuI7kO$z!sU!-V;px4+xuzH%Gj!Rj$Y7>sCV8x3d3^c@hZH-L+s=5^tf_vSi5lx4+xMZOhRav&w*3%+v0M$Mb6@w+fY5lENHv?Y7>&g4p`-b?!N1huQ@mZMVI2D1JK +tyW4lT_^#{CK04fOHi3$_UPYMwPV)|W?(e%5@mUfZ +P-CnG@V|&`TOa&rx&FoUq&my+cwu}C6eLR53IHBXB9s?5&-0Gm?fN;dhexk(F$e=~l(sUE^rY1al}hp{P2te`j=ld8c(FXQ(h2lBOgf~LA{DxC6A0L2vs$!UmUlIK1T6Xq;Bx +0i*e)?dIZ=sza&OjGU@yuP)h>@6aWAK2mm&gW=Yt60Et?r0000^0RS5S003}la4%nWWo~3|axY|Qb98 +KJVlQ_yGA?C!W$e9ecvRK30DR^vIY}lt10)!}BLoWuH9Eu+hu{F25S8FS$P6il*ek~ANLvi&0Ja1YPl +o1XGiqDxt@qY@GhgETg*i7PQK&x0#qo%sYLp4fF1_(LtTKk-t1giJm=Xrm;e_kHuoU`{{` ++Kdm*IIk+ovQCW$XPg!v%*i)IPNf~|8sNy`#%c5oEd-0;hxEO?efE><*!}7I`D%{1sfZGd{^W5e^_wG +_kZ-GABzS5bZ0@M^rM0w{HUP(*6M;E{&@YJS7&Eu78+$7%G&VzGePr(``_7n)er6nV0p>5dOaMs++^cE{B)H+8Q061OEFMePV)ScMAhV*wj1qV*j4{h~pOGM}diZ%=-<4*=*t-<)PRp$4 +&ho#(d8Em&^^cv(ohK@K=j>ZWZBu!;?mXu&>sOVG20z_NyD$e_#AQ$6axy(f4`q+kY_})a$-l2jlv#h +DX0q=Ba;xi(K8fsqqf@W_^V|bF1Ke`Wwn?ymP~k0Wd9xV`IR|TV%QvZppXz@c;k!|K?u}IqeG+|JBWD +dF2r|NBZ}O*^9YQM4A*D6t52~gcP5a=Z2)cdV)APa5#(Of?U7>q!938R*4UCT929mkamD{M%LAJK*24 +it$=BJto;!6XT>utH}RY_KkRXMHOU?h4WHMvfCkJbfC%ZOmtV(mdaRe;scD-0Qhv~+<#E`os$u7Av?Z +P6y0KtV#rvIFxMJ8V9I^F`xH<1iy4TKe@=JDT;FM=Eie$KW$xIUAN)z$$MbU71@v!;^iPf{F$*1S}0| +97z*fZ?Z0)ec>oL6ZYR+{=Lg<725u9&bp8rTRBE9te+n4sCONyD^iJg`Z4`^ItH!-|L6hDWfWg-Xq7# +glNwnk-6FqS^*FN#?_iHAu)lo;Uiv+Z_M9& +A3@V#cdS9aDH1a7O9bZyf3r}!ZF%Prl)ck&>yl|?PH +yN$DH85m%2 +pA7>Vm9O(b;(WiC{=$U_o2!V0b4bYo01FOkZ+jteJsp6ViCGJCPhz&GAsdwWwVoKD@92reEb&)*;((s +Gf&NKPT+R~j)e}vDKaY2FvGT&(aP89aDxod_&c__{yneqQCeg2n&?qg>0cr4=8wjuxz6&J~fC9pT*!; +aXywIrv9SX+Fi|y9*?|i*npl%i{#GdbB#q^)YhCsAKC+AmTLRP}KlQMVI%{{jtfU04V)!E?+9{7ZCh- +-k+o*^e@ij#x9mugu!tiY7)05+_>!_eSOXCyR;2>m>(V;9r`=vrGVck&JLjWdJhwbBe{q(NRZGr*m4b +HeV3m)-?H&PZ*8l4dzmYdLQuS7P!*kX#AL!lAUB~8u2$c@R!Ov@Pn2VjX3k6kGS +?y_!ex6b+sEn`_9vV=SuJqC)mSpc@p5m0Fuc*Mj>Fo_$=b5yPP0+ +nr^*3@)cML0RdLyFsxp35WXO+uNzLQ2MuXFoFpfRSg +CMkZAWQjGYg$wc(#(P0qnu@`fw1DX)E8^SNx%-h3`oOkeEkYWzYqlP{Cg@f6E;;Ve#hbvQI|0jo&kii +UjtARmZdKol%ywCs#HPrA-vo)auj_gS2s2BlTPOtrP)1Nd$zeFR_PBYL(-qA~P1g{PpQ}TnEX(DA`N=FRSQZ`r=idMy4xPrK@+pttn=XU~DWN_b$w=uV_znc# +Gmyw~R*yx%!0u%1-xDynEC(!W;Yu?wL`$r}^`6p|pD!GFxvMHs?_y^xR(389m +aaP(Nh(q#!_K7UxemiN&oV0leVY@p{o9P2u0kH(NlV`!osIL)4{FV^>A)%W@7unk#Mv7bH%Nbo8xgkH +bu%0{G?%x5~{Wx)7@_CP;CQ|o1bADYtC=Zug#-t__0a}4> +M7^NdG=g>nGqE$3xC+`cEupKIBxpVQFqCbx8%ZDpg!?B<$(;2Cy-7OFmos)jhCOIDFN#-hp9<;^~Wda +Dmon2IKX8^gkeL2QI_MU>UCMAR1e8Bp&$51lpem#ZFwO6w}@CMLN~OKr@HyoCD+)I-V`pb|nok!wUUK +rxAqWVEtjmz*5pcYV0cC;CfjcFGqk@`G!!p)Zb9*5Mi}2zyi-lQP^6ouPAwery%InB`gTrplw=@0gCP +Hf?8`aQfHh&p86(Z%i%+uq<6tbCr`r_*hf!-=HR1M6Yv>f-%qmVqm%KeOvX{kUpLxo=!F2>#6faG-J) +4LCU;t0lD+YCvP*K=sp*S3PMj3LH@$rpRETuJ+JjNG^x>HxzXhNV0WUo09&9f1veiC+;Lt*d$pe7Hm5 +_F1IXr4f!qvG+An8zyS?iHwR@X@5mvUJz)>FSuoD#qO;9ORXn{Jh +d{n_7?=4{n?nO)YsF=KuN^+yJ&yn2;Vn1WIU)2Y&Sc43P!1_sgX`DZD8trFEwyTdC)Sn1kii^(dYbtW;9hqdpn +)^lgAKXld%(3a?G$03iuy41}l8s(upl^loDSz0C$d?0wP3Yp)a +8H1?eIWvCA>GgZ?L=g+8q?s3?NcKQP(VUYCkx0_wxbSQNg3998r%1|fp}#0auH^!-^(nx)^t2@7aQ=6 +`?&zN(`S$YkPGx^_^)Wy1L6-Nw*d%J)%uJmRb_%6X|1LbXa-67g2zoccgEM@<3Ce{B{*qkKOo<(GPf# +R+r?WI<%4rC3tcu)>2Z*sbTU1|B4z@7?lapI7k$`Kal-SHwn{n#Ak$Sm`sFS{ujv$@%EVyyXLYIV>NjQ|du>5Ob0_+>k +^1YHbI?{*7chUwKg*8QE?*D}Sju-;j@5TR!AWrWUc6+&m1>v#wLcNzu3iKJD;nR=euMOSH8e;Uy#W_` +JZL!|-Hd8TRDkxJbD=AH><%`W?nel3e1n0~9hCayv+LO%A0hq0|kBG;y-rl*@^^zydF$4>?lHzyb%33 +KNuwln+{_UGCDH$A^YWJ-M4Nm(OdWy*db5S7WiR&<%>wQGhK6gg-Rp4prFgfbyWNkq<}&7mXiuA40xH)_7yGy=UpcnK`nGO4GTYe4kG;8^(a$H3Hq~ZIBxECt7(y`DN*zRtRHi +mhDlR@JOog#x`D>qhrvw_;gE+X*{cU(1vq3~tWHDT5j2H8yccZ<>vgtcxg3=X{8ia +!MZ1&eYp({p1!8oahqkEMsovcWpMZMtJE0bkh8ACiJP5j%D6O}G;$3eInyP(tM8{JQ@?9OmuJhP0KhQ +J}nIyhwnKeEezDPQ`l_w{P-c{-b29H|Ah2-t%IUC7+=uyz9)bzs}k$P9(=%J)0b)zxjqt$+ +UEd>+Qy`ArGR2G=+4;adm4wzV!>bG}X@d&)_k*%x)4|pJBCIL&qil@|uD8J`C0+h?FRbT8>7~+n}cK) +JL#Rkg|w{)mjX--pf{5pn+@k&H(001!NfybZzNUGnyA6 +QWqRXgDK3)76-Z2J{aXiekh729??RU<+F;hR;!3bg46`~Pdoz_&+xi>;0b_}Uc||#?TA`X3dn{qb$N7 +^JvA|3XR(P<=OBvgwiz-22Cf9;s{IDJ@4xJZ-1n~SBDs%L*dLcA2P;u89Lv2+?)?ImPm@w%mvVgcFMz +!!k6pgg!PWZcN6=fyR@)l6mzR5o0Y;tpxJexUI4|Zrf!&nSV-@*01Ue%7C||^g|1VdgVF?Bbh+KFm8e +XiyatGbrh~0fD>yqx?k!lf5GrD^tksQDdGvyJJXp=|G(qCEstw#TS2C>aB1l4~Wg~zgtQFzmO(J1)kH +#AsSbLr=qsY-tipII@re6YeUiwk^Ih1UB>g1&t%%915lqQx%lS|(?+iGM>=$CHYwsHcMVHv~;+mH(S4R=cj-dy;>kvyqP_*i`si1 +dR0rjh*gT!gtGIjKOUN>9c3E7+-43hZyOUd{~5c&gM6r-KF~}hYDd-sp_LAC!+uZ($Q2}jX +j~ubBzcGUBV*zVLX7F(huii!o7TO3JndSK9CncgX~KvD(@))aW@xwNKef-pmmG^bupOZFolDjmrPGcJ$FEr~b&~iP!rBa`i25R)zFvJud>ea+^n(!n;sXFCd +Nh_GmtApH0iRTo6%T0Y8!v812$KYX14+yh#7GPor4MCIRC|0uhX*oRyCTs5;4wzDQAwKg8@HuTNK1=f +PS(XdWhFy7X_R5~mUeg@xWwW!_Y@WTYvcl^(57-vKi+H%b^Vr+Ew;0~A8th$&VWu_5Y+IS+Y~uD{;@) +`>irEU_nPKH3FO~2*; +N&&yV7Y%5%T;ZAFj}#jxlP{RU3px2e4euZ^W?F?YnD0gA~bM-gQY#G@Ib#IwWUN7p3p0&w +Q$4c4;EU9IModZR?R?U<<3xLd8VOYj!)p8=YX`&o)c +Gv%uB(Wl5Oby`vCFBP5$~E9-x|I>Z%$M+KuO$f^_HE+) +vcIB5b@K!5oK6r{7bsr%I_DL`Zhde(*ep$4Vi?m90{Y`KeZ4iMdydS02K)K8UfbtD%knuQo0qub4BC} +G1gE-fWS09)Bx31e%JzP@UWG4PW*5TihOO|PbIRQBY3xX5t9Gwa5iIlF(PSFl)9~U)#`d7y^;g==3dDQ*MpH`bkeW^N&ycxQ=~t>I~%9*r{?Wca5JIWZz;lNDCW +8&3NIT1lbZE9|6#*TV}i?BNI9)&`vk!@P%Us8T&l*1{@Am8#S7`4O=`d=rrVTC#j+Zn%7>L-F(z&>It +>ZZVg*+MW46DKmK=f9fIPKI%fop2B~ViB5JPvHm~c?K#x9Nz=!5bm>7u{Vqe)c)S>h$Fy5 +^Er&0wwSCzU*O@Jh&u`>9%KwOwevRl|)DR_rTuF(kz&Ax7dZ=ITNROm!|Pq7&-lp+n9ty7&_fuqTkOZM16}9ooiRx=2?Q>lh4lLopv +lt7AtE6vLCb+C5XXd-An==FmI?@Tirm@%gLCXSjFgJnkHHYTB{2sNa##$d@DvJo69Nqd)_x-H@(npP) +I`=MQqL0-LWxZ;B&rXz5>zyYd?f`Bf`%yO|y^jLt`S4!DNjIryR%7=pa;YwG~&ZqvfnuQ~Wq7O*uzE0 +$yV$;CjlSI8rU+un3W-1X}^TAn;3o?0{0|YAJ~wI_3-OJ(Cx~BI~8IFp=q{<7gU|qFtYo(Lv;K^g^d?P!L^;`;6 +|bFmw}{J*G!Zhe<)rFj?;bP*Lf0tTb@rd>pz5QHgrgvX~oPWFLdj-pBFr6h8J_7LSqaN%p{7FrTGfE3 +knt?;f;UBpw*FtF!U+-Q9Le6~E3E-DJaLw&SLiU>W+lf_q2B*w)%}I6){BG@W4k1X(+75%Wk#&|F&-6 +=%YahaY@POX-jqw@v{NR=QlY1+E67I)Y8ygAcVv+j1Lulh)x7g*WmfO{u~PKy;6G6LYDysm3sP6m0yZ +hFJ}Z@tj_adCiF*)o6mskBO4VD+vfCkET10MLuT=HKmaX4~`~qU;k!%XX33@!qJ`Eoh7A&ng)ij +Azoq_=+{@axDalGa^rM^eexTvHhr!vndV}`b6eYIB8TdPij!6Z#5Q2!VCAV=Rq8Lxw-UEHj3#FK1O8u +9cf%ho$1l!vhyMS{Z@&HCQwFAhdVgIY<%GDdO`*#0SQ9om@Z58E>|@T>z?40r(x0~Vu|6n>2e_*l}bX +o^ +_(=a-tRBS+!-NQpx_|`UWpkD#;)sCG$x*M9)0o6h~p!h=c(g8L`r<~Wh0s5@q_MBFNJtPVG5@zjT!?h +xi3#0+;{?S5a6|W5qiZ}RlNUh}6G2;Vsksk!DCo#gDfbtIG*sQQ>N}8JCqi=qUs5=NXJrhC3+qsVIXz +xHt3+q8+*v}CLQ(zdk;xPX6Afz(uVQT_8Sw$gK0(7vG0anb@LtFLGd_5G@LksoLZFYCFZth#R+)ZU +5phL{aAp1vNikzvPPorI7e_ZpNVv_{z;J?8OhZ=)`W4#;%!2hi^l%uY%kWIOjdjL}#f+lh2U#9@k1^nZc!g9v(P&eusdwylUu=^-EdhvdKQZT7pXz3CTEzYg>35V`Ua~}7H%X!@0o+n51TzvW%m`Nqs8a%7I{? +MBLm{i5RZ@`59Q2n?&POYTAG-YcKxM-|8fD3B>_QDNd0e(6^GE19T{iqdLm*Hvs+LQnCs6dqD;Anw8_ +oiWrS_nMOC`7t`Du9Pt=zw>wt?sY_1&&P;z&d4`pz_w!o@3Q~7_hsN@q}D(8z3d(}pCJ1 +i>mP~RP(F&A>m=bkS*yHYg=$>qh1LxK2;$Do3)%KK2tnz3MCn4^6$97~2gN|b=g^jx5gZDk^?CpbOnn +swF&8wN7f%2I`{`a+%F>7DTmtCScqG%hnDbRP>>Z!B*l?kI?!1{90A>VEzvAYqee~{RKGB}EKooqT!7 +}w-NN_`|7H+=MN3VoH*y`DhjH;{X^`Pb0*+3r@Q1os!EGkJ;o%BNB6ht1uX8HW|>C&VvaG!Pny9{yvo +{IZ47{C#yvq#XIpQ$! +%p$D-mfM!{gzFxx3v~C#ohoXB?AtKQf-G#b=qxL$FuNnH%<*{!P=-r=>YCLrv!XK*aKJq2-9a9Ae!6U +s}CisHUA*nZsr04%+HnBVgWTnlct6}XwQmyPUATi& +?FRzdKIZxtKpfOVlK>HiK}DVOs%SKYdZ1tw&kniAdk12&NCq^#uds&Jh`gijFi^(wcWNz6CR1k)XcWb +4QH!d4%#zsv^{T}X6>o#s3vs|MqiwU +Co3A7bmR9=$uly94$qP(l&qtHbGI|iJS};?prBA_^vOx8ce7^y>TLbio~S|ePVD%uY +u8h+%0C)uhnF2>c`d2laHIkiOM?b;|`$}2ZF5N<=zn`N2$QV&^e&X4Br3&3;7f1WhBj`C4JC@NP(+gw +9~ol+wJO?ve9*P#tNNg(tY%mD)=0#u%mm3UubP+;ww)Ug)2=;4q1_3l(0P2$ +$z26dE27xFq{=Rz)x;_C*%5IfiORh*$g$`-TeLULVr4!hs_pQaK{q$(wibxFL34HWO8QVa$IUtl2#44 +-8)|K@;@fz2A}9cUbd1)(s}v>ELci~6=Db78_l3|S8g;zB_=hK@KCbbii +w@;>X;VyKN9fF&r+1|=eSP5&tF8qQ-Of<>G^mH?B5Kq-E6yy(JBxs&}j>hfp+8O4A9GwwAHk*^+urY6 +k!7@ddJeT4`_J_(sCxFWzEx@BV;zl7M$smyVL +C45D{k=ToV1vLEgQDVP|c2k{j>*$M=5&LRJ>St=!6P7=dzn|v)KkXrle +_`^R>;qkFHN=K00@$>G+Q>gF-8g3sX$)!%fc$`+d?%AH5;n@Y5^y(W~|E5wQ?tm&+j#P1t_P;qC&|%PScQY8#Y&Evi$b#8>yRUk3}6EdR +`ik?UC5@A8aDC4ku{3vv{KUt+-C~2aLWZ8&HXgR`vAk6K%}e2!x!6lS4lH8ws8iveTvgU)lZUu^!`tD +dRSpYZ+PgMAN|Ml-jVd^Cu!}=i>-rElax!lK4F=EpUSKTTFxP@Y+0ey4Y=METGODA!KhgXU4Z_T*4f3 +9_VVIFbEGHH<{1%=L@I;UT5(dPltYdV^&tP1KN?YL9Hh>!)b*=B(PO1abe&#P`6nqv`1Eg@re05u9-~ +T?!xe3`C>{qQcyt2lQMHgANMSl1|4CA?pp)4rZw$tdtf=@UouWTm1i1vIJZBD)^Xi;=M6kR*xY$}rI> +eu}-(+h(n<+Lj-|7uom7}?7glo$pLU^gk*nH_M&#`5SULv$F&zX(D9tM148&3qco&!P6I_T_7X*L7B0 +zoG;(A*>_fLU~~D>8#zxQecXZh1+%Ha|_v>teEx(7M%v+cz}SEwud*K3!D~;b-eHF5Of$5H3%%4sy*x +E7}vGX0yWs1 +*sTCz!cdzIFwR})C(Wv@-2{y%9Y +vmgoB-&g5b8mO2qTEbwp-e>TD!NVEsgJF(xO{9*sThnkMEcOl{eXNLM6RMjCgXPykmu4?*TYarfPMEi4v`-*H+v=RzOXY+`N`|gjT697kKXl^Z +plKBzb)*62kKh1xxu~xH7{ztDT9f)go*q3sh2FpsX@1guo|&`cs?)f61!6RsseaOfb}P?m;7&q_uuZU +mxU9d)WzKF_2T0?V2o$6&pIEGR0#0N#$p14^uw5t^<3qfB7SQ5dB%rg|;YhnD2hOwiIIR!9wI#_z{v6_BVEb9)?S153l}+X%D1p%fK#1bWeS@-o1(ZHN(I*Uca5 +?E20R$Fl2#h^Z&H@~&x&S5Kz32H2v}DnIOnRv#xFz^0Qd`i$;aOwxrT<;7M|^~FxzJKf`$5^=+7I^HN +|s5i+>)kD>^yvFdb#NjTsnnXj+uBN{@oAfMIFQZ3$Q+2=G%gRBw&ZNP|ZWw&7{SZw(b$m75RWsI?f;o +NeNYzVc_8RgFaXUsA{aje|(Y59K?0D}4x&ol|6Ix$=0HfBaRx*w`5oDakaX!{e-Zt*>POEhj4)6P5z1!wATpCKGnP~QPhYjPQ1?hAXK +F&t2X?qI<>A1%v99S}%1D)ER80?iU|}7q* +Z-VmHi=D`gv|6@=SZj&xuE*BWh-Z?|yGx6f#nZ+CKf``}rS35~l3mRo3&<#lM3>saG)IcC+X*!CZ48e +v~fEp&2wBf1zcTkUNqarsHraC-(wA7a&Dl$Ww#$a?fWpfWN9h)-fb34r~U`8qLRW>7pl!|hyKg_Uich +AZqTmm;ARl>@DUmpuvVGR-sWI=}6H=Sgw~i(tcsz5^PFl~8wD^9pOTdQWGCwFN{ATX1lVni*cojF@ud +Yp-FGNywTeE(vMkB7drFPNqdEi(omBuoSnNfop*kKKXxWlQ<9Bqh=ylEDfn@seIld>AdA%PmSedyD#Nr4;Wx#3XEQM>i@#Ys_AdM-^Ql~N5=4}$)hFDJoT-7N; +#F}Q+?hPpQ<*F2#~Jk4=v7<&1cP$`w7(C#Zpin{A5v4BBX7f=lA;b%`-2}FVoLY#3TXowMOn0gB}&b3(({f~+6SYucui>yFOBoko3Uj +`3ez6(fBU10EPvFm4B^}8r7>~Ho#G7CmL<{kpq8I*(UI` +}p%lFxaq=}tq7<*j7N58wmP{O=>7*dXyq>RC46e&y~ijJ72se|rvP$Gh6YF~lkJxNdt=BahX&`dalW* +D!2f5E7vK@u>UnvYgj84AxuIA7ZdSjGW8+x=91*Psoyb;3xX5{Li7yJJY;>34P9{`I?KNuc#o64+&c- +ID^Nx$pkpNZ{eBOGp5a|1ZYYiz?6=qZNMx%Kz%!B+7qT^^b>Q#Oa`oP6pkW7I$h|OM`t#zdJ!mQ$TO7 +u#R!iCS1z`=CgIBywzcm3W+~HTL?PO|r|k^C;2B`&f +iYKOju1?A2u5?aGSVNu^aj%L^ftv4VxQWczLM`cj^gqxP1wSpK%Z6OL?OUj|}pM9PR&tVilmx0gMb4C +4l#`lGU+C&M_u>bkODCc}7qP+d_LPKMEzpe`zVAQ?uDL%q7}7s+rthNqVuFdN}8hI7iE!Eic+QGV7ou +MhIt@mgj3df+V3!IcaPCV-|_w5Ne2^flX|ms!DB@*~snR8R??KYW2%(9)YxOF_~3~)F$0O)!&{XJAQ?3;nkk`?&NKYc=dhN9Um&G|;0r(4m=}Czql_e8uACMYoA(v9(vAwPpr8Uuq9mfZ{$=vXXu^8~yd58_)^p!?8H +%g5z&um78x{0v+m>zQn%342m_ZjXX5rmW3JOvd~GfOgIwp0`M$)dzIeF?DjP1p58eveYB@)HZ3ziERX +<6HTH_Q4|oz}PwzByIAWN=5zk=d~jp1pYVNxjpD{nqjZnDf%GQ%Y!g{a9YV?hA +qM)9j6xb7*;#)jQzy^gH`qLsI&YTcKpt5jrE;NoV%BWgG|kQC7dgoS28+R!XoIX6BY>Z$nMXSQGrtLD +b_4BDgzT8`7ljl-e9H&6{VyfF{s0eJ4fZmmZ13PWn*}d07`wQ-v_87fWjT7)wGn@_#O?XoKmR~ZUzO{>We6QD|`?iW4DlN2Cw?dvq8 +F$+jzvX;AT&cz2New{oAfrlj;j*K}hu}s}_sdq-}F$R^wBw6N!tmwvijKM)dnKMk*y1O+MiiWDp*p+*#K~U83!W*S&xcy=>u;hd)W9!vWF8{ +4;h8VJo>5DbogNYVjf4#(~ri8P)wXivU`Ei3>}+QmEYREHQhL(^|)Ic-%^ElGg@1!2Jmo^Ty@&|1a2p +YmW-zU#|y*^J)Kvx9(Rc8dcZ-)mE&Nj5Z6ckDKvCuEQ*D44SK<{JH%G +t8$%}CeeCmQ_BLBK}9bl(yufvt}*N42@WmoCouN2zcKw6`aZcqZaOhpnm}R?ufmiMD|G#|Lp;hhJg%o +Nf5BiOX8)i^gZk${{VyVkK8q@6sL27Utmo9Mm}JYSa;Tu$IRFV~#avObybO^`oC|V2yk?f+F*g=6>me +)0WPU3rP4D!KnACh&*$?9xM}`HN5NB4c@Z=2Q6&_ZZ47&HX*bY&qf~cj5xJQp>;Y0DuvK86K?PJX(J%;o8#lro5<|~&nfW{@@T +HMXB<7IyvsJ+Ts2;b(sRYDui@o@DJpE2`Lf3vSaRXB~x_LMZvi)0wo=HydxlC>w!?G#TJ}`;i8&dBtE +Mij;`gL&wUnlhPD_(2OvDPqq0dNGxpl7qMD8^%V7AU|6u_LCadwQ55rr%gb1Am(0`cr??gRGstR5xIW +nN9|sV(fZ>SOrowjqx~h@p4|f#v-v)tuOO9yV5&1B^`J)|~FE=+`;M#cUa>mW4U@nABWz +=(7oB4u^ILUU#Nw%iQHpxqZ7Gx!WIc(LI1roT=77)_uQ{h_%pr?rcZ2#6%nh{Rf#of$;T?@P)bciP2xDTzgX{rbW +mpgmMi0&5Y7GGAHhR1rlAP$mFdRxM{RHb*UQ#S#=83UOaR+IzX%)J}xFKy}*=ae?}>LZJ1uh~Qx{Tb~ +sElU{!*kw>-58=_vwXr@nAT~N9)qdPDX~kp2pcsWtN|Wi6T`8OX3ixCj4(tFi^E(hf08uqJT-8qxy~m +DP$y;+dX>rj9!Xc|mPAqQBmJ{FG!h`H09O_riq+d9cj?q~doyMXga?Gq%ImGgY(4cr@gR5WcP#2)MDI +BtR>A#iZVd#E6obILfmooyw?J1TG@{5_6(}p>_ghTMZvnbjOTFp8URF8!G{f!q!{Vd9sgV@ITqJyq`jbqCa^kBYv89_3upqaNr{k8sHJ4?T*q9znZ~W4n694%V)tMNxG^kQ?=K +l9^r8k=pae8^CmbRa7B)EF%w!$J;Bj8(e0Ihl1s!X7v+@6b@w;McGxT)jod>GXDS{V0ZV@dDR?Om-OM +h^!(U$>}Xr%u(OMr_OtV24&t4&ig*iG(OkB#!vDkZF+3DkUg)Ut21f#pz@=y5@ZM3Y?z;+5bMP!2o`T +cF8{}<;^E5HdB^J)xd{ub%S2Gd}9st`#=h@J2Nb!Z{=B2@AK}Ys +EH54zkitR@qBe@{)~pt)qJ7bB_*!R+D9X5UlGKURi2Y?zY#g^scF`t6h84%4t0v^pCGFFLFLOkv;>Tw +SzVg!8x-yE@%n>*|~!j+SkFjD11HjN8kkdKNxR6`WpeiBTYPsl4F)m*T`nxl@RWG6k5@8mhCJ}P3|mB +@cZOX1^E-fHL|W=vc-S2gyV){>?*L_XxuD+WRcJEjdRcJ(+VHz2|}A=f5JpLZf&%K6m99!3PXKAfO#z +p_d@c6@LrGa0f;Mrk8=3UI@X@nmfl`rYFlP%uP{TgZOhDZr$vsj!e31l9=>T5mO+{1PNXA*`fUp8K^; +c!L>S!Ig4DLLWyIk14E&yg-(&Fm4g7Y)Zx{Spu@B|<_bKHM^ue3Lo5K4vyidcsAKv}&9)R}%yc6(Fz< +U_p!(l7h#yCsAC6OEr4LeQYHvm8WZqz>cb@kmH4`K_)e(SwAVxWx|jR*`!5;iPeI~?9tI&92A;piM>U +pTXG80y`y0qY%l7e;#O2G-x?oSfC?qzLC^utJ_krP3vFW{9~=V*K%;Z^xkdg0n=IUiww8;_E`Zk@_!Yx%0sP$XtAw8yes^qOb2AmjdMdp0;hhi +fTzKcg+W~I}yzTI|!<&aU4{s~HtryRYK1SQ%*$Thi@Oym2n7OI2K&!{h1q)w14`bsln!C{rWpTVr`IZ +Imy@&o&UV85zfK2OB8#yI-UJCE|@@sFCpP>+mrX?>14v!5yGd2(z4TS5xF%OS?vE`?U2++QmK`cg^{L +^7H=`FP;!yOK-ikF~(w*cOTMMCVTI~z6wuc<>Z9-H<&J0tS{QL}*WbdYi^wuTJf**4Q9VYejTMIZY18l6LP>UFN6Wf!Sf-Tz8ry`eS-l7p#Dkb +bSF>8f+f#$MLm$L(Bpn)&1&shqx(0zt>xaehWSMm|Iv=Cu7#q`=k7i)-qB%x+$EBm@d><)x4T*F7$^s +fhH%~kn;-jDA{SS+{T1jXbVMo5weRLD<-;mfkwzb5L6+eyw<=z)T!27TZw?_6bciD=K;!Jt_22PwxU& +iQ-8`yEV0{Tx+vEy>|;EQO@vD4WvC65i3pg*qMxxq(k**&de4(KqG#Sws>-hsKLzK*LN111JlP^);EO +tVFMrD$GYMt8ZAhj*j@lA&Q%#+GeYk$3@*7GtuC +d{xCEBx3#ic`rWQr<3M}pa{%oOVMIY|L@W+J@&!Z)2fKuW7FXAniA7PjH@rI=(}M-8=-=OCYkK=q6G) +J)5$SCZ$2Q~NEWU8inmY{S}ZU79A1qiVF;t*&X11iLE+v +UM((8VFAd3oA2NBb@t7ORfK?bbYuD!?cxsBKpo4w#zW_8azreSJ|~r4M5))Ca}Jh}_O^l6-^p={U2imYCNKCH+{ey_*aKaNo9QnA26;Ns +PNC!GvW?<2c?aO;Wn@dhK+9L2(9v?n3y7B4^!{k_{N$E^BK5gSm_PXSKp2yKV~$de=tn7i^a;$r2Z5A +j0m7gmoA2U-u*_I?KcFvEusSlvis`6^nL)kd#$%eMOv}gH&__n3=`kCAGTT)i54f|SZdmjfYJj>>9=R +Zm9}8jy5cQ-yGAxb9dm`M{(M0tn%$trI0k?0wKsrb5>jf8G6Juvv*mS*q(rHj>;$0(B4(XtOV%Les@p +2~U7$_Wv-52meW86(c<8Gw54DED{pSEc90-kXaQGV3o>^s0Nfr@#xJbP64XYt`RQ637o$A|)>zKe&Vk +kGF8z6oDp>5KN9)^4E{5P%a7Rsf}R$DiOXDyI9dczUc4 +in+VHSdn_e|LxW1MlFJs8i;JJaBz`uFrvbc^|m)JghamFH4RELEpsI{e};c#qSK7qcs($2nx|LpUKpp4`T +7#HBJZ>!=Q(kPJb3xlxCiH-z1%d<&lnqEKsUa&8rq=6L0V=omKr5S(W;qr6oAeLTL2}^HWP5lKT69Fh +a-;P$YzrXCbw!SECC$aCViZQxtE^A@u>6b9xV6|WvJKjhI!!_d +L?k>=o^>Qif=jJ?=Rp6+Qhx6|_O|aW#*57&utdlSTa%-KEMMwqQ0$(m5baheODRJnXv%J1oV6@72_M#Pp9)!5mR`vMc1?t06_KAf+UK%KZNM)L6R +$mJ**07eMXh(SQNb2iC>TB5eGPq6QD7V4CZUR_CJa(TSW`%xrM0Z1#%jTn5L-A0lDX{+pPRVcBt|TI% +16AxYb~gO66KpDwb+CgL?D#c^jDg*luonx_-obD)3ol58*R$}#WO#3R7W=a-j=*xgM2vGo+#Y<8Dyko +oc16WyrP&B8-sr`{()dXdc)vPGQu9J5#W~m*aZD;y$|GmV4ZBWW@9$6E|bq*?_zkDXulXy@ +w?*3$dGr=fS`nt%&A4^o$eaqmkdM4SQ!KYJ$i-$ZV8xHLUKLpgr50qXOk$4| +FTm(QBF+vT$sDR&Rv6kFH9UP`tepnrWj#TS~MHu%EeV!InA@m?ONUc1St-9FM!&=*0>mVXMI2P6i&DNS7@e~100g6+jHDD9k9WhbxD-RSD+;pIh|lq27Gr +6iD7_TNaiYwYfCZpUBnf(RS&3@ho$V|gv7o6VQpOJ~>r)B`9aXvqzSpBi(gTp#;GCXcgcKYMnuCuPr9 ++4C{>#2enX8N$I<-VO0VK1!|Yln_R{I)&CRP;E%Bbw!1r6+k&!Vd#UOp|^z`#sP&<+cjoHyT*)he`<{5p +Jw2e)lr!ih?O$6i1Uj&#lp%;F&6?ts2fr<4j_2^2z<(6{ItgZnEE!we+%C&>>Ksu_&=wT%y9zW&F8L^ +=E*UuKKW$Fu<`=71V~ufFk0deyIC;)J%}N!rFTa%g(EMA%lRI?*t!4QBvCvwAZ%Jsq3g +26W*4g-8BeYJ#7VJaZfEUg!7Y-rud4+>Vz4WR)<{!}>LS(EJXOb|IWSF5L{a27k+bsraw!-@R5Q>pwA +?`&n_qlW(R}$-m2M(bI&{|{0Eyil$0d%Agm&JQWTh^?T{3CB{|d;*1!hKc=!xXkR +wm7Siv=JYhuY8TGcs@5SoUQ&Lyd +7N#{r1_H3PvM)n2W{{WZIjsE53OeU)FD+VUwfUU8byYbn<#u39TuZot;oHot)Fyi3Z*o8?9UDn|iaS4 +rcH2{o~03j0wVe~I;mwI_@Vw|b>aHwmpGFbE)!*0rdh;!1JEl$?YZTj22!lz}w*B;sFM1?C0t?F_)Wv +NMGD%@((X{=#zM(uC?)eB20|Xa_Qe%SIUK4Mq#Ze0@L$qaX_jFD@Hatw??ks}o=xG1BrdESkqhfu@9x +@3?H6H5A!2Zs>%3oE!S^4ZeuX%;r7Z8jsg +oNHV+l+Jo)<#&RG?2H^BiNVb`dMM$dEdI%}TUOvq?goHgA +x*S~v>hL42QU|T0VO~32m@x70FPxW(&Vp`e1)&A6|dGmtx)(2SdThMFB&A+;#=u+0~Z(mvHSw#lKKRR +QYfNtY-lF?qz*r&>r>|BJ`$m+paS@CC)WE^$(-=(V0s|O@09x5$N+8lRfE2Ak)kHSX?b(%X_<}jmZ +G5c(pAf7Uy7lPkcQae2-sawS>_KuJ(M3DBtgKF}NJU+@&=8(OU^CXJ(S|2BD$gv7`@>dnlDV|XR=I%Y@6*dL>nCL|B+i +Wy$og?1?Qjc-3Y29?!7dztl&|H#eJ2;@NjL;TBWz3k%u5os#@;cxZhF{?(~&_Uje?_qmjTX~nwI7Z_! +;I2%;(bx9D6dhv@FX4quSs?w!F&Yr=mtSj@KQxJ*Ub<@XCC6x{UUa$4JG$G2;yI<%^s1AXp~|SCXP@p +Q$(nre0h?2#rk7p^jbVRr<^IVj&zi%1@J&0e8mp!m6X16OzR&*~E;S3-vlyPGO%8UV<@afL?nRnG*Y3 +k>H|XMhDaEVrG5w|nl9oKUG*TU&svjJ(=zr0neffeyb9c{K<&i=tvn_lhJe$v&MO*V(lk^=@}UDp>-FUH?RIZ;H7(mv +%9nsmbn6`RoET%5{ouJoqVa~6zvOG(}Y$p?ug{&LOOYb4GGKaj3}XbI4B;6uyd9T +xw89jxPoCO5R^lA;hs?zIZ()eo6lyVn{R09-_Y615|g(Ar_F2k&Tp$3Xsh~KzI_3QC(j4G>Mg>NsF(I ++=;sq|AYrVt=oL$q!x?eAx`dtkn4@4gRQ@+y_UY=3QJ=V9fDE@(V+~QK1WnaCke3#Zfx%lQ@SsW17Oo +mt88n5%2(uEn4R*`Ot>yJb^!rFbyTEHHKpMr~dVSbN62eXq4u(#@stZRv6D3rZnS>ErEKwzdxKnxnGY +Y!~QI328`wxpfIv}RXM0e5ALOVSJ*%uZ3-z+0SnuJ~ZA)tk@e2tYJ$F1vyCegakEL|=fayq-^5g6$x` +dP8Yn3V(AKP8Mc8-S}c7Du;U34`3=VuK`vZo+z4p=P6<;@n{N8n43A=`9xlPi5^`z}kVW0d`f&>J#oe +djYjey!j%heS!|twpy4^a+GpmLHr9d{_!P5%>{^>dmz~S0^$tF?t0OWBh@lYE3E?Dx`3GcigU1tAwoD +*2~Ss*W78Gw6P7Mk9>Ga#K9?zF>Fwy`vfUMJ4tGV%h&F-a8vjE2^(;mGINo#gIb<>4JdI1SItFKAO?P +z)yIdI8QN$R63vVXafC}{NRMX8u=>KW&O8}y*zP>M;;*y|Qp;?ZKOW`uCGt3My2&j-Kih|~XD1)MG!i +-|6U_gqarvElAO-n6X{$-0=sR?TCrKXjsxurRXB_$~(dB5|!&+`lef?5CG_x;}Q>wz=(K6gFm+;i7+p +L;*6i}V1@9@c^%gu8?}L>AeO1@aLdo9=cwy53VE$s)!+c$EorAnR9|EWPzvA?%ylI0>nD`5dIRl89=QoORT +o<&^qgOGubB{4SdJEv&4d3b}A0lJzMQQ@J>6SzLmA?1reB$FREeyj+U}?L@||xP?W5h};kZ%q?9uAfW +zK{{9O2>T*f6$z`-v5b7fntyS330^^Y|!UZvL>I>h15IjI@Pxc;(r-f@Hg%FFlb<-~teF(Fp7j6|{%) +KVNjSUu6(9+iCveMp(wOEPMDk{R{>gll(9k;JS3mS7HjZ6fN1={xFt0iySj+YR>1LE(0N&2jM4&~F-p=FkG1WYE0koOlX{?=|K=r!Z)Bf(N&f!(rQ3ccK1mK1YY%3tTybaL$XePo_L+EQwZmuPS6A3m +zOkaw&&0>SqCO^~N!EKk%|2wAm61v56kVL1NN88G5zN%4% +%y1l!0h;*+AA=FSPWSh72wX%#~6wP#vYI9qqjH+p;L8=O6gYz(P&*dl+ALJy|GE04ST4>@f@?TWnmt^P$>M>X?9m?UT3QOzX%@V?(yvQp~SBt36q=gY** +=oq2f{s4ONb(UPQ@JX~#O5@3$7!d+cWZ2=wFGB4;o{G(SdGGFZu?&Dy*unFx{Kpwao=CTyRVbg*jY)_{8B$hmW<`YpJ?^)mllR ++ER!}Z_n%ByByAGrKfPy-E%zj6n0v(K|bVh|1j^i{wK)hPPUfUk6%Alc$``HS&vx1K|W)*drGsiYeu1 +C%5!Jt_TpTqKH|{nkHi(I`Z9}KVJm2;n~eEG)l!6_S_&kI@z@025_Ma)=b%Q4a(6Bar(bF->zAPTo7HmR!Vj>UV#87Vt~ih1;)rnh$zxy02t|P2g}@{O%OL>+t*R8Tw7tf8|lMr +a4CQBVB$i*}CcmM$3rdu^>;<{-hRGL;tg>zWzs~CFy_Ej`|-sL;o{aeAm;|WA0s&_GkaglJ*DWV!g$I +-eV3NsJ3&U{0y`|o9bzQe9C0)&qksBLGbcTLZ7Qdm97Y%Hu!H+vOUPxmN3;I5D)bP-$KkzZK4rM1hivNLtB<*&Lc_neAmJks-N<~!Z*dEsGqRNY9B1a7X=85#iPhaSn@oIIt$APkD_)$^ +#idWdQlaIE)){BTa>cc%yb{Bb9rS`nd}sgr+kG5V4I@B!M%RC%P-vQNdoYwbT5fV@mZSm7D9uwR8C2f +YO7$eM6_|?)|wm2Li^TAQ5>iX#d|$U7CB=_Ai`p~z5JBW`yi5}_u0#8Ik%NL`dOOF?$)g$CmKb%Z4(- +w9j@0zD3w(7)=@PjE0C#2(XUYVoUpHX!m)7eWxe~P +p=1LD$2?xH3(y)R*pa1Dv_*=m6FiFYgvLm)P-u)G$*CnS&=`q^)@8S7)CAhsT@?W`?k-09&FxYoX^NI +XQ*_E2QEiQ{DgP2jvbLetW1=Ndl1j18|A>CiY-0Tnz7snv&vYY73ojKur=_o+`U|kn3d;1ThjFwLB|83bZ`mDOw)U3_^(`l1p^d@} +w4S1)@;%oNx@`pymk^Y97HKBCo$xUlYsQ-2^#RqRl}6*%W;77OI}dYlMgwEmu@MpNn0-2qh_bMCnT0m +y|p+u`fYAf+Y0-7$AZcmJXr!&u@q;2O+JA(DD>3?WspG-fQc&xr1aeO8kMwCqig^B5IaZ+$Z}HYZa}J +2qil=sQFPSmb0v*`4Jq2=Ep7(?F&VdtZ07V4$Y5{5LxpBA{K7AA@nMuyICl8LAA;sFho-RxLw25uIiE +%3vSd={(v!(@~0RH3H^^!IixnUL^NFHu|of|t3azZ$8%ACtwI8&c4`+>R~SUY7htcnl7DRluV^+{Xo; +G*lofN!RUhGfxLV4ka4RYl6~a2PCIS@J8O=Vg3&oG?sQ_*Cdv$^eL)yUM6g$G3PC*|a=Th +USbhz8SVs~BepQC!#3;$88e)G19?Nxjlw+kByHfSr#NdW%zh1L9b>VjN~&aa7cW15!(fV79rxD8&nHP +anzZYUySbxm2{Dtd`QY?ig(ASwHo2g?qy73hiVY^7D4yKF^(k;NzS*H`o|TqrWG=qlA{i6SmaQK3sj+$d{$@WN*L%LJJpmI=CrWrb%1r(YTz?n;fWeTq3{nyl +*?zs$(SKW}8u5L_Y9FEz6M1Pcj@mdUyv9NV5)T$(phT2ROxB7L4+DNc5lR3si{-!~~VwBnXP`HBbZA+ +tPKXk%ti>>{z;9Y49M!aaWSFBLBFldti6I$({yX-S7B{-vWT?zO$Xz`jE9?gC|H$bNK+HP&4m;G^F^b +CmurfkV6%7c*Obs&~4yv|1BXXi#&rTDfiF0iXS5&uFuIbR$?4wroN(&5C<$U23uLSs>2Xa6C|4UTN{N +c}N)As;my{Pj!}D+S@9uQkX;bFt%K>R(yHur|s7w-3jN=(SZyX8Pgi%ZFv^SqzCvMQx!I7<7x`2mr(a&vdF^i8+6rF;!8)~(*K;#2Swga& +1zf6DQ;zXrd6Z)v~ida~D~NuZ(&m=JqjeAIq&atqsCPsz6eirszCjkK_Beo8uRuw>S;LT>a}s7K=!uo +cNdqk(fAN-SrruENDloIhIWQTQDCtbVRemQjVXY0|1C40Di>|A`3VgmAn6R#v!`j5%51f&)8EHO$rn1 +vl#?v)s3EY|D6wZlr0xKVBlFaF?;7&^qgw)pCZ?4_*WghzQ^BqF^+Y_L1-`yV-=8dB)A9vcz(}5SMq% +=wIFwr!?TC)Au*oH{zR<7q%2JN}S|VPpz%zY!@_b&%JM#(Uldt^Ib-_<~W|Mu+&JAD!whd=vFf8yd(( ++3(s~eJFAq}E(lJd4LW*o)zxwFQ8}LHLJ7W{X<>VOA+S&NxKcVK9(O-@P=tKz_QG@dWwxefjl9!5)g# +}DAlwr_D*UMNW5iD!e#YS^dtnKNF#{}zioY;xtlMcmYxbycq2>hf7e;#yuv{xV=V9((-R^&)?2@zDy` +SHobCY@P!UtG>8#Q8w_1N_jg*!Zbj`)`jwH_%v2S2Cq7|U;E6^KJAxjtg4ezbfzSlOK4q +oUfn8lOD-mttXfvC#j{vo8$aZJRL9aY6Xyx(mW>Y>{?v+r_z57mqi(5Zpv81b-fHOINPXla7&gGW*8c +uArYFq4E}A$XHs)>*rDD@fpE+Chjt9XS+04eBn~!Zu@NR?M_q#Qqt=1${NRSkFXXQTWQ<5T&!5Nw8mD +=AKtcTn9~E)s^U!IHg(ppxwW*v^k-C+;-gL9QV)7zgEd%*pr9n- +G!oGZ>*fA*=I?>?_(6JwFsD}9xswBF^+Y_=zBcS`S)&bO@nP@)Bnf_UC6zOBW=W$`uKapG=kZWeb?R> +US&sKs?X33Wc6=usx$KsPqn4VU$pjR`jWBI%6N2MTYVnYKT{=7V?Jbr)`MLx5wag;oNn1uaAFc}?<<5JwMMEtT9-jUb1`iY|r6x%AmU7sk}=UibcNOsMyxU1Hupi@CH#txRI;uy0rJHU*ttdvn7W@HW*lZr#l-zc=NSH>2 +i`r!uhyT-Mkp2A(6)gktPU=_FUa@*A4D0k_Oq4)%`u6^0|(o$S*dD%Lst^W!Ae#RHJ>VLi++qO|8Je}jg=h22E;TiqDw-^OQR-K+nh*@4ekCh``jxD)=vSH&3`SRzh^{7yo +U&4>tI5iwt|n_5bv0SDv&my3x}Pj`Khx3uX~dslg8}$7&Bm>Lq7Y4Shp(y?wxm +^2vBCLlf(ea)sf{;y*k{-H)P>JZ+9Px=iyRz|K1j5Bg>mNXUy)}RB^4s%4Y3Z&K^Y*uv1~0tL^7Zd@1 +a1yClq(wsXStv>g{_TiX}H^s?=P8D!fbURAcu!t}PiFU%gcH-*{Lwpy5K+l#^sustoz4mPVWwYEZG8f +=eeq7^anX+~SNaEi1|66OHgIAIR7jSyy>El!xjYy*Tj!e$iaXq#4;<7{eSrr3H2bCOLZ%ygTVFtcr*! +Zh35g_&n#!klTV&X7@;c>x6YVtSf|d +6|Daf)-|xs6;|xyu+7Y{A1p96!+tD4s<1*IW*a4}=yGjw!ioxGi&9X=nF2PA@W4?Aww}U@qr7aLg!Lq +>_X_J7p+gr|oH1-;!U}b$?HBCW*mzmcFRbFwfz!fTDd-p0DnY-nRtx%tRa~q0zObUU+tvvyjykoi5LS +E?Yx`Haj52OFvK0vre8Oj&A*^j-%@kHISSJW8mX>WJgjEG=tgw2++E-Y6z^V~e+(2jRDXeN(I|*w5to +I757Sm^|w0PE=~GRgz-c361C!MaOWamBW6v#^eUb-l2ThIOs5j)V0Dk%-sWI +!CCRM_QZc-Nca4v%d`M};DVddm*;)pQa2-yB79G4 +?blN8mLkV%CZ*)5cbg=;T%Rml+UniXWtR(*iZZl<<6_Sf +q@3vTWu}Urmz1uUg%M8iIsCQc`yG)c^BK2;|WtZWS%K*LGD%mAMxJ(pIn`Z{|Fti!#esr- +@I9j#Gqt^1<2US@YAbz0X7_j2oYpRxh^?X#R{>f=>1raE|xx21(REgZMFMR{8T)#4=D;4wWg{_^s8wi +G&U*H1AcrooUm{|aAFSL$zw-H$`bd3JIW^nOa3)M)se4IO70&dm3LaBsek)O&G>P-gaMYQ%bm1`SvNbS(20ZccQUEbT`U?A7cSsi$i(^2G +V?E6eS)){N#2Qs_RJF%bt0lxcI7SrL-B@Q;>u=2N>wtU^kk^+@zt{HSuY`Gx{)Tzd?xw)JaJPF!`#4+ +REyzoU(^J4O8U<1ol@7V!3)lGg;4vzTYkYh~6K+w7o7}1s<3X9&x +)XE4Ie}Gh62r`k@s>h}Zv5TQYLu{(u0+LAc4gFP1YyFLBcS)N&oJ+ij@W-VW +mqK?gt|H8zcDF5JhBCFgm?x%oG=B5~5@Q!BJ48H+(VM1H)%*yzj-=|#rUmJ*nms7_7K!l*HqT{(3AXA +yW#5MF2c#u$-;mG3!gHIetENXNm7Z6XFPosNw#;{1i!mP6 +tb6KF^p+jdBN$(WX66UZ5HI-|L5@R*h!#p3(mSauuAm}X%`xm;Wh{3QAVkP +@|2kWxO1%M*!u_k%ty*xy#!D^VCyO0C;Xi<_+{G;4UlghtvMw08$CTdTny-B|Y_xXnc@4w%nj@6X;kw +>3-SLsy?YG&wrdWsh}dS4Q%w-;>kaS~l_-D=TsJ-q8z_#bQ=b?szrnFVA5fs$5Ol&SshJcr~d&qdde( +zMOQ#bo=F`XV*EI@5B8exSA9vY}LD(6qf?x4DZR#g=emeYO%w9?O{*bvstzGla^%Fxt}!u8)?;vT6-T +@Ywss5WcK?>o#p#UefF0OaxLb{1*P4N$(!hEDhA0{E{2HW`x6(G-V=}gM +?x5^&N?ScZ;I4Sm+WNe+Wfrvfijz?F5KDDjvQO-l3gsGg=MaV+g+QVw|rrx$?=ZG_m>_%Q&{S>6+7O{x{AJ(9=g^zxjSLjg)l4J?WDVy(?s{(bZ6)9b-T&7gKWEWXDlsn2iIZ$y}C2zX4 +vw@bDXb#V=Wtn^Wy4O-vi?4%7NaVE%xB_M@utY#dZDcc25?6{j9tVEXBL6i)1_Na%2>F@vhGhQU7l|Y +MQcy62uWqCdeb0Pw*1K2Ly)*E)zIkV9bjkfFOooEI}s0Y=XrEs|Y?M*hg@apw0J;btdRdpd%PaFqXhf +@Fc+t1RDvC64(gXMM|H*NDxObn!rp@M6j6PC4#pIHWGYJaEhRcpe4<-ya>7x_z^@B3?)b*c#Pl~f;R| +u5}YFVk-)W_u?Gpd5d;tz31SEm2qqDj32@cMa|EvvY$y1N;5Mkco1I{^`wjls$aFo7w?=Y!&R!gv2otq>EJ5}ug3lR?$jXVzOEbsiWKA&T<}#MSa@hoy#d4U5{( +7?%mQH_+sko8l5lo;z3dV-BVXPnP#k3A~Ulzm$vM7}${Q+NT|kk=`;X1Sp>-Qm9P}{%OJ|nc}6f$K-HXFVm(+Na!sey9unMx6il$=LnKE8h-SGSh8$${Syl+G}@TypF_5{I({*HEwj +E99a+9cnur3Qh{&8loVjUVJ}lTa@?~QKI8zF5Zp{-~sTvwZ8f>&0j3P>4L)B*RzK53;GNBK}u8pVt#@ +4{IW$!A>C;dK8IpiL>dj%9HlPSrl_PB@E7n;5~-S4p1{11EK$-MN=_-oTk-d0!M82%EXvI!V=UF@EZH +Be;4~qP4X0aIj(`nPnjkPsagdqYxA(pd^3!lS8FDL^CTd)cNHxXY22A3JCx6z31T9P*TjjMSj%|?RBas1 +F7~%Jx(^gr-_&<(K}@emmKk~U?Igxsly9p3{|ktC@y>NK_;fyhxQsphRS6`7BbSwto +l`Dc=e1)9-h#)`U;Bl>Cdzo0EawEaq}5W#%tPeq)oJGvT3w(%4b+@2w5Z!YtpxAo;rQz?78pGU-mNXBStuCQaR&HE+@Ku2vqNt=rt)_MUt1^J>@r{tgd3*iq +G~a~JQf-MaU9=wY9py?Xai`}+9@1O{oe!8*MmBs9#JJbproDRttcw8>M_GcvQXr{?6EEz_pw&3J6o=r +LoH#x?H$_{>?e^Z%#m|DVqPKjwdU--yVle*FhT$2>AHcF^FsAw%Pb4NpiMG4fG~|Bd_qU%`Jj8aB0%T +f_&*?kd}#bFkw|WOv!V$ie=UgMG1seTjqpUk>)C9qhO!S+Q?$uw(VTnUtQ`n}=rr{po1rg0V}kSSe#P +dX)ZpGOTe(e=57n4Ec`<_ddeCkL* +NBIcZUV#NGqhTV=ij+A${ScOU#IASa~fnlk>ANh|LYbv$l!x*vBQ0pS$tKg{MrQoCBpyaLOE9Eo8p0| +>(lBbdn(n%Jx+Z-|Xk#OiIu&sT^N(VyZI=Cf@QGKRZ?ND5YQ7FgvSTSd*jT0|$b9_%0v`G0W`6y{C=_ +%KhyXeOLC4BCOK1BDIcVdbde^~LOMu;;>|!Bh>y64!{U?8 +mYkGikw(9qG+`Sy$&!;RyCs@ZGEMT!FpFf1&B_!G@fO)kHX|j?@}@>mQqZfXzH7lm&k@w$zXN5{QOMSfMPMqX40fd?(R+Vva_dWXWx?ke|0zV2i>^P3JfBE-TX}LsM0c31CuS86DFB3ZyYbx_vEy6Q;N!*rOL`SWvWbhrU@2v^7wQJ{qRg!;Fn4TuS(8 +TC1+Eh6bg@8KmyU*Axw@bIYpJ4la)cCMReAslf<)_tnrk$UCdNdEvB3qX_*sMsUq`R{Buoavx7IwHK! +2jDVFT?v8cS%HLv$(L^fdD%uqxM_oa5kp2g%j)K~N?8H$bm~vm|Sd>C_3EViIh0^q1K_d|1C;+FR4@ +-le-LS;idPuaj~Ecy#a7o#;wW&zdgEvdb;(ZXizMJZPX?b0%6cOqu3fRS(lNsx@h;DpN+bdB#Jx&u6? +zr3hUzbaD_oML+}-GE5m+)Q@y#U8yJSOyirbVui8pyYviTfBnHGutTSeVhlDkJ~IBbUYlZ!QO5^99kB +Yb`_`U4hc&tg-Dva?xuX-PKxd4megvIG?&#dKjO=t%Qo7uZj2>!AHzntqM)w~c9WT6;7N&Q03R;-;eH +c6BOU?15hH=67IxvsQrt)6pWvt_0TF?LZ{l?qIpQF0H|K-lN_y4)e?ft*-uIoR~!9TE@kwtf_>wl9B;`=hJ5F?ejTnx_!B|%D%n-mpQjj|Fvni_fILgJ^lepZlC|<)ph;%)boF +LZ7m;vSkpKkhrVWHwsZEN>=^c4l+y6+e68Eh3mNf2Xu@Z8+AiJ5W=!?J1-V5gA-(2t3=xEj+w +xX_w-W|31ts!Jw?POd4RZgU$m?$=PDl58E&7(gvS2iMAXnnPD@s5%bA<(h$y$i12kKg0TrwOd4ESvf+ +`)N?n!lV{N${aUGsHNg$OHl{bN=%oLXj2q>|&;7a4(F44J>rty}E6HPgB#8wE#k1Pt*MC7EIiD~KaR6 +YWiV3&cWBTzU5D9sP3?x=zMElsjkMEa)gj&PLL3zte-~C!_p>9kufd1wT&T$%n_MU5ey2+Hyo|5Y}JQ7)sNF@%U%O=4d9udcw2B{2=iiN#7Ng$P3T8e0CXpYQ|N;QF`iTVVoo=A0?Lc +itkPHdtObHPK0cEgp@lkv^U>1V<^j!BX1M5lh~mfT4|t*<3DmB!FCS`@hrHAzAhkJO?vQwFC>B^cvey +HbO2)XKOFjEE)l1WSpd-jXE9I3+gRrT+8$Kk#7gHRyZe=6Bm|i^O|rt8k{6k|s-jJR6SdbgOe6f9Jmo +(SM%*FCNGfzMWTO$3-@wGs0dRT&aok25@*G^f@>d4f-5+*=#18&1Jt94u1E_abbGM>3Yg;*#FZ;2Do> +U-2>(KaQQt#evgym43*vEWiwGuf25puy6m38nAjZwJqq>=<;b`;k;50rIM0#ICuILZ*}q6m2bTe3h5I +G>{bd=SHFAEh$?ltE{63fczn1;Ino7J-c&6~&(PV$py)pkk8@@6B|H+5TkMDFNyA$}|{`}E?3Fmr`i~ +K0@<32O8p$CnEZw1Y7m(!g+Dz~TGIlkBLPaBrp;f2($zN1ZsjF1S$eAf|dk~p!#bgyG&psI +8Shf;3UB@f};e72o4bJA=pV!O0b3C1A=t~s|c3L;TIFkBPbv+6QmQ2BN#>yM=+4UNYIl&MbON(R>r;P +-IKtbfDu%GWn`5EHiBaWdk8)xSVORwpnxEqAcbHw!7ze>1d#*=f&hY^1l|N42-*^~B&hk4(j+)ZaOg` +Z{7y1IBv?oA3_%e=Ho<6uVFUvSv;>|6HAjt-eEjD{+Tc@q&G@&zJF#1F#kl~=135i**vLj4As$m)b+w +WG*FT<(K9awx(dWMbx&MZzac!gI-?+B&e-`h*^ZEZ>2IS{|xhUZJc_(LA_che>jeBCo6SC@=y?Rpm;{IVH?t2<>Kh}u5tpRt8{i?~`y|WXu5%b +Q=n;|Q`ofr;XQr^9~Ik9!_weO|9o!BI|+V>s-SNMUNgZ#jC^4?AF?(}kn;?n!{>3FvtJaFKE +c*m53xzo=TUXv>Pr_Zc(zf6(&F8O`>LHBCJPfe|n-t!Uuz`@kigS+MT8p$7LSk>U2(yt+ZJQOBhN?&? +Uzb?WbIB;;6Y9TEr6T-6&VL`it-3~dBRui9e0en&-h%%~!X|kmyf{bUnB*1RXi#+*6kIKa%r+fB+U78_VM3#QfKYGFnsv%ZK(qT-Xt?=O3c*3oNq|tvrD>f8#O$M<@43sHVj94A1y +-q`JDf7{rY+)r1){hW_Rq!J)3sq%tZ!v8&JYDmBB;e6L@44d~$D`N%VB>+LihE_%O9v%|b##Sa^6ii; +j*Kyc;rP2unyvU?WG4WMjsRVY5^Ev56BWvdNPtvy6-kmXnhs+K*YYX0ewoVeHMvLfHGW^{jAW6k9MQf +<2QJ&R)zhvdwdJ?B4~^?1eew*`}r0Y}ZqdutTe-upXaq)^j^&zPmUJ+sRqrKF$oEb2j=j&LWO-_Q-M0 +hMeXsmtgog&PHA2Y{D7N#$V=a&YU@{q@;u`S+ayZ|NQf8*|KG9`SRs#)v8r&?b@}XeAlmE&o*q>AlkA +mTeh$xJJz!&e&TFHC1;<0`YGGHcQ5L215YeGWfzL>G*BsVRnvbUlNtm1802=`^9_z*UOPi0H_61IWA%Z~EHN_ +)!MQvA*oUrq5tDE>f-Ka%24r1*KfHJeZIms9+=DSj!%|AOM5cZlDO;u|UcqZHpv@fT72*D3yXihr2mA +EWrEDE@a8zntPK@3; +5VLX)LkEZyKQT*pA{zi&_)FD1=#p2j~RA)P}#mtAQZ4f(1l3&T98E^e4;lt +N`|&VKggtZE2n*QRoIeFMf-;!mac3n>1p6n`7VKkg8}?vo@vj!qE~eZ%{P3;hxs_;8P|-km#l +>u>iB?;8^x9T^!D5f&C6nbfOC_wHT2`}gmnq!1ZR-t-?$mdMB?pN9~je}9$i9}^o96%$6uM@58(^$kz +zi2z-@cJ3tmN5>k&W5OdMBPc%b>fO`FCp4)R$(Yy}<>`07*L_L7drK*JckZO>(jW0D{g{~Ou$ZI=?r! +Hr{uH2x9H3hg#SaTd3Cyk_-qS^G~GjtB)lX$414(3L-=f3jYcJq)1;QP>7*4+V|^s +_uY3>0K0!uP?IEMpD4;;5cxmYub)7ngWW&E!_7n6N*xsw8B1L5*HIAhKtEYL!gS%`el8wv>ae8Pq}b> +v8OvBjx}qZj`bP9|b!t9H_5iPBHAYCV831d6dSVI)Yk{^6QHwSO}g_cqbw8PS(yIUp +b+qSiktsc-mTeXFK!L1c|cLh8|xwfQGSAjn|-UCvF7@Q(;1agAZM{@@P@n6X9cR)dowV#D+#Ym7OjFF +gZ1TL;I66Ca};ypevS@FsVSe}q1|uD2vVlzt=$VsuoXuAa9;`ox;(a9urb7E||$t>?{oX@0dwLD(4@N +R<9Ppuw?R0Sl`)p1b`xMH$Zx9XeEuM`oM)+s7WS<%P0&X;ExxP6Yeli72-Ih1pEAhsG4t&JFmQ +vxIZfm?4kM=bn3xz4+pbY{iNd?B$nVW^2~05o3k--+y0>2S5J!V=-3vvh+3fB8@lJ(^z5W&YkS@&p#J +qgY)N3vvcRpvGeE8vxHY8xhjzA4C+g@l)X`DBTs(m~x*6 +2bJw+YetE@Hufcf%I*bu&lP31?}5`L1s%P&y>UFi^?I>b1d(PvX1XTAAh_^eb2cce)!=6nWw9&s;&r%!X5e{=W~4V?PfZ*4YPInjFdi!Z)-sjRFlzi;2Z{!A(-Y{9vYNn2! +q3(B>*46rL(g0S`G0ff!S$ndYOuKtao8N74++Y!GHQXLFH8XAqJ8}K8%1pfQ>?c*PP^bsfg_=g{UDDb +{;;R65u`|tUoLx=d`!-qvU#Gx?)+|N^-mG8d$?yOClHqD|TTU23T;o$7-?8rrn7RAxH8n|J5kk5Vh-R +ECYQu3&upC5SV6&V@X1L^)*{I6cU%4saKq)V4BfyBc_mo8o6rKP2IJ|8@Ikbm>dHv&&8AAvjUXU?4AC +r+FY@1RKm8uJK~WUlI`pMI()xw}DW+J5`(H~#a_KVSXw%P&9r?z`_!Q(nI!9MSnS)we*xVG-i~S^Q}{ +g}m$l{1pHV3ZP6B0R9Rcid}*Fv?xG0+kwj54vy}Czk>gc9Xl3KId&$QC;|=Jw{I8tLq3ilKQ7AP?Af# +89XO&+P#qTLkt0V0pl+Z%V4~bmcMxa){`~@flp)oBj&itp^CowE==}z{*TA3Zu-~7-|Jt={oVp<)|5~ +lK8{`-O{6G8bGroEAW=>_!Y0NC@F!+!1*t>VH0N}o7&mK`%jvYHD?4SW{0OSqz1Z4!=HvY)D={V +`$FKB>;Bt9Q+2pkOR;Hyup8z@hg`(kNk>r;}@Lk4|1+Kz`6e(qG2cJ4-*aDwsPM2W6l?yEUAqQSIV?gwL)+329gy|L(imo0$GO~oj&jZe{H& +fueOBnmvTb|4S2?sb3Rh0A?`Hi0|}=A-#FA~&>+|6-e{AkP3=l;QYWIJInkLxWuj +H;vpmM={z=35qrFh%U#HV`Ls=+*`U<>(8*o=>LEDe^9`hQso9L_1x8eEZ2`&GKXxK1Y$Jfu)^S6kG`t +|u)YLk{^g!2Vc`to^c5xj6>1kX>2pt^wi3>sdMX;>!HuoyH@IKM-j$EJ7CcSJ45e@T+hGLSVIVN#CsA!YI9mW{%S2W!I1Aj&S^?H3b-~ +jyQ&6{VZp*|hAqviMCYxvo+7xhVJw94DCPrrP@fOJYT-4%(R^d|G<$tk#u& +@w`n;Ix!XM$kWy=;18tV*G@bA^DS5RtdYGz7GN(Hr}q8wg%nd#7z`z`v9WU?K +P2l*Xx<;VVZ(;Es19@T<9T^`oazL}`y-D$BE|@xe)_492jC7|QAUbfDdhqBAbXhSU|ff?Kz%@+7WJ9R +!LdHSUavkM*t8Pkz!&dCc!Gn2pINqSnOFxw-f~^$1qB5>At8Zx>C%Ni^w2|`#?}HC;DNf~2%tfM`m_K +bQ%c%sTR&Sdo^L5OQvWQCG0;E1IV*y1dU_&1v411K_RB9vsJ!oZ{bA|SrM#%9=<1RsOZXE{Jn_q;k3P +!N)6)gtXkbCses4G~Hz&sLe7$c$VKuZG;k^k!{@aWI3{~$8e-BsDy*{ +2_W{PCN>Gchqy0P3_t!^00h%%@MEF3JIYhO)M!&;fjbzq00wxdBYn2h2_0pg{r9pv-$Q7sL1(at}OVLWV$_qikVJh49pt +{L9b5)8UkLn(?gc?XL7j<*MX1kPw{8_QfInC_r1~LfNKQ`X0|yQivbAQ-8i7A}4W7deyip +I({=gk$Q^*g-+NcMp1E>>77i}=%ev{HE^78UBQn|mfb0<#M5jvlycZxsqbsYaFd<9^>2z;n)IgKr_t6 +0J^uFFZ;L+gop;_5@xW{1la1Q8G1N!SB;2=?8*Unh-s4X7H +)8yT@ekU6s*j8Cj`{`@xS+gIXGu=QSRx}ML$s|_*G2z^wg&R8$RX+h>Ltnqa)L5Io9s9qf*t9ij8Gov +&xu}qQG<5V?GACb6r1_~Jm2f!?ges{{VM^zvKLu`kqCQOY}jYLs{=f`+ +>F&{gERb;O)kZ8~F<_yddORslx!!t*p&s+=O??jG{lFHuE(X7nlD8cRT)${i5R-#&K+OyD|Z+TD3~V2 +VDpc+JG-)3vDN8QE;d6>8pQH-fzJlxKRBP@=yJDkuv|f9WBb5r=q_@*}x6upy=dKW@w9`OMngvv;cR? +UUGM<)74i=JQ4dHS*ZhsR3;Z3|KdGItum6As^qm; +Lp#6g!pg%(22_9q43Era|l=WSd1K!c*qpd|dMso_G*C3kzZrla_klowKd1LbK*cQQGS+@Y6K_g_H*;FHr=8<`z*mxv4Qs*BDfsQ+eDvp> +fAzD#<#srL)(&oNZW@}~O{F?rjrNSjoWD?eTTboLWonm>)A;-q8rx2$F)+Si@FnO>&e&(5H5`Y87PMANSe?+^Ez6fnK#uK|w#f%BwGlHN4_oTT?v_76D9BlJViGaAVJvaU>aM4v+Q*JK*!COGcHK>1?~3|!Fv +Y+jZj*1)hHj5T>Bf56yFlHL>gHX)D4BwZVHJdj7|sG#eFo^a%T5p|D}Kl*W+?`O`MHEXh?zFQg3!o=A +6?b#7xEfMRvSVwfsAG%lQj}z<3qfyq;K-UKy6XelntJFRy`D6U!s4K0ne+Mpj*30^d)zhT)*s3d+_?( +~W;sAL}s3(tMvd+|BmdAQ}I*~uklaiM$TbAI62l9rT!^8u98`e~zU%;C1#^~V@76ve*R=f-79dwx(RrJ2kYz5HT_%G_d(Bu^-#zobWG4~6w3OgnG+;#@fk%cS;yvZ5c +rya01M@C0oScu{5hhVOeiPUs1+KD}OEUti-;C!lAt%6hVV83#N<9x30^1ShZ8t^dmW4D}FWen&lvqwW +rT`Ximuk?rpY9Sd}IMTEm_S=Z?B+|vFbf2-A+{L)J=B|tZX@i_2M=GDr+LEr&ipgn>g9_Vl1eyp}mG$ +fA>vesbxk1_VlnKLuz&Yhb9K0Ni*Q=;8NyNkXL?LTAz{D3SXZ%3WekLQl^AI^P6b)ud;ria^gWw*;8e +G1k&u%-(hV}3<-(Y}^mUl*p74a(xvC2_p+{84`8yRT~H(OfH!FU}r`>>KR=DSc-p|Ad5uvteOjV%-(G +>9n*oK7amvF~0*&N?V|`l_($Z=Bn*D|NP}C{G-Bfu@^v*$5&?b$c;+UcGt^r+P2uf#~a@mw| +4H##wySs8NFM#@3qamyOboD|;&`dF*?>{RjTUf82VB4lwA*Mif#mo3iew=!Xyva-*~t*q8X;d+*^$%zN%2Z;?OpMEg@%SU4H +!VND)=KH41U7RHPjBXrED7YK_7JW$qnF<(2VfmlP+n#^@H7v(93G_!fIXR+jz+P2lT@mF4UW0 +D5$w!VHdG$}`E%HY`)Ygdhzac!7G4Q+ZzROpvSRvMm(KceuNzp0(#k@uS$VcgaAxofF8H1zlDSAoZ02 +zah1M5$lHf>V&3I5f*?eyQt8YtQsw0$V&_3PI|{(c}{lrU-i%AfddSJfz<)E{y0P$AZZ}NORy#Ki|>~|3a +`4Z4>Gda8z_4JXKRC(Iu)f5lt@a}_nsm6j1+(6wSt4%{LC$oKWx(PE5qmF8eCR!M1KE{ +?eu=6;y>Vcw~wc_+p&7*hdnv|D&EhrxL9{b#3&G#sCb8`7E%))6pg1OHG?=!29!sGFaR65}n5_b}GOS +QBGi%s1XzULw-KoMQmtf$|$Ua-`66qYVQe&g^`dZ!8EA^GS@|F>c4a0duEWrv4(2_|u%PBfh-&;)`ND +h&>|EtD!6*FZIXbhsxHAasR9d_Axhz-2nbkzaZKz=;W|}KW;xv(el~VqYJ+$? +ZQL-Xnb9$FCv&1||L{pL`<5YRY~bwA&bSp*+x@I^qI5`f^A4M|h +?Dl|4yF3;iVWM}LHQ0@6miOnra8V|=vJz#Hj+7tj@fCiK}@PeNSGv(b0&+_|$(Ts*Uzz7_6Cz+7Ztw* +e(gQyDzq?!=lhmC93`_JkAHoNxlCc*A*X&J5>j;^Y9Fw&ucc3Mbxh)|x9*tEJWnC#|{3Aywj>wI*^%l +{jUsDKjMJ=9)6br_WI3Wu#~3hIF>%Wa@G!OfqF8=l04-n~;;0o0V$rH6bfQmzFnEE-8uBG<|>uJoMXuqcc$E7YW`9@ikWMgV97}{&ye5ACC4eeul<{$Aw2mMi1&gVuWn@=l$<{M<;xS>Y1Cmg}RNpqq>{gM{QKcsVAskQEyj&sjg8s@qN(uXW +yZIQ~aLwd&6&|-$B2Ven0zp_;>RU@gL`J@}KL!-2Ws0ulz6gU-kD0@CxW15Eu{^@JPU;0Z9Q<1M&lk0 +(Jyk2yhJ?8<-yWbl}dw&jODImIt~8-5)eGXj;&dLHmPl21RRVg1-CW%g-D|q{bO&@_>rU&g=zh^P(TC}y^;!C9`o;R^_1pDnhAhJz!*_-@AzmTfLzoy +~h%3U>pR2!D7x-5BKI2#DpB`{Npjn_-penFeU~phm;3I)!0!@M0ftv!i1nvsFFQ_Ewsi0?rUJQCU=(V +7?gEj$sfr0<-~r17?Ua`d7g70m}nk4tO`H^JyGXe_ +&ivt$~E(u&2$by;$c?3Nl^eXXVd(fVsi$OmI{T9SDEj4X4_iH+79@YeD44Ozyj3z-dT9c;9)y&WoYSw +B#)|}C(wB59E+63)rZH{)ncD?rD;Mm~A;HQG04?Yw8eQ-^%ldhT0LwB#PgRYD2A)T*Is|%r0AEbL!m! +wP4P1a@V%(@x6d|i?5Y2E9(cXXR{TXZ{hdv%9(U+KQpUDo}iyRKt;mA;!kRG+M$q|er$(O=O2sQ+EBG +ITXOYzQ|zYk0x1*-&b@V5l(sWLO%qBIKQr&qB_ITnrf*njShk^wZF9iKotC&BHvy9t;~AmK0_VTMOPA +85=?3(@Jeno77X)o77v?yVU`HWBiW#pYR_WkQ(rKz>@);f?|RaG#MHfZGiTp;4H$mm)@X%Utg+!*09n +L7BY)+`#MA&wk&L0*r#Dv!kD-~;sY`Q)OxCI&#PZnA5foHJNtI?P4J!M`<(AbzT146-(7ya{QCRN@O# +;BzyFW^zxsCwm=dr(fRpTY3XBPy8Mr1eKd3n9l%_&crO{~nX=iKaY4>W6YENmeXn)gwtlO_UqWea7N_ +Sotr%%x5=wHx(um4%!#PE#L8YlFZVZ^?CZ4`W5=!`d{_ +T;A(I;v^01c+8VqJ9So_4bVIhmY{)ZQG6aPbQ;Bv8Js;X8Y<}39unl290_SYT){!w&{gL{R+UPgL&+5 +0-?-jrGejoYm@VoBk?BCMAtA8K=zW%BHEBwEpR&01cPQd1XhXbPnKMC9y_-){oz~(`1g4zf9QW>WPWd +&J+W(O4p{VV9BpmRZ2gSu*bG)FbpHO^Xht(W!zZEtOm)<7jOP)K{KHcR`MHlIr6U)mMgW7?m!ErVO>@ +6q3{|62c;VX5I0L+21($T+l91=5`&dFm`*<{#mo<-gcJH}EvI9v7)}uV}7P9yc@*REyHIbG19P724Us +-v$@xR_PY&Khn1`6ofn)`f%8&u&H71g&hXniy1SJk*Qv#-lOj4`-bmlz88Jn{T}wqr4}L8f2#jI0fhm +Ypw85Kjnz!ly{Z4+@KDI`km(`g!f>!}9>v}7d(iiY@7KO3d{6s+N3n1Cw({%f7wMPp_b+N!_W3>FALT +#R|1tm9{Ezyd_P;CO{s8ZQlz?dg?*)8K?Q6@x(7=9yMS*!ivx4RZy-TfUQ%!5lcIdqF=|}5R^ywsjGxbIK1xV+RG+#{#ofPUG)+1~{*rc#|Ve7(nhV2Qnf#+u=y}P^GTiru +FKs`xqRxegBSAVEJsy;>(dHHI6BPss^-&I7*8LHnZKcn9`zXHDne(SKSx{|TBxT{?4rS1{flj>1Gpf= +DDXbg-D91u7#FfM2qwYvv`4h0>hp6Dd?MdztEx=j616;WS9ZLzDyo!VnhOvD0%`=*%n&p~R)PJqhyro&M`9SlbW()OXJ2iW#H +#eWs^?7WO7h=Q>#1!^wV;DmrS;bKAgN!fU8ns}yGMIjTdl3pvS8O>_h4;^ +Iy4~E7&;i{?3_6(t^1A{r&#^@u9hQX3o6MoH=vOnKN^X?^q=m1wk;upRNl+oxuNjg +#Z1o7ygD#ST{`gcl!1V>I{MH7u>SwCl!t*S~huHJ +xpOh}b@_wl8b9{nu-_xnW)`K_SmWb;TCJLD;8G_INf!BFl$wlyEGi_M +R_T_Gn@c!gqz_x_FQoHFMb#RFF|5%<6|K#{vO>~bXF%=1QO=q_Cjdz}s%yc)7ZvOhiy+{8Au4fA(E5r4Z9iU`# +QFOft0l8N*JH(c>@qfEo^*>ePr6mQO(ut-UQd9;py?x6(`_&Q2 +#Ssr=lNV;2EzB}(JY{MiEIniLt3vU2;y&|blHHe%LHH|UT2D{oo*V5$SKaFZ;#+FfzmE1vhfsvg>*@j +Px)N+WDk95B=!NbEq59uvPY^j0XqC-JH2{1d&;DZQdV{cc60)?qZ8{Gi3uu97P(aS=bo00{jsM2kLzI +qn#fjqK{l@yssx_cAAwfJ0=K7Sfo0kzBIL#Y +lq0yXjKF<dpCm^{@DljS;#kmI{vf{XAEGAzt9N&ojiOhF;{A81#+?nqu74Z7F>?dDHcT0Ck3#9oA8n>NATOOHwB +9lJd_SH71Se+yQUFIQ|-DqHQ30l$;AX{a!2XahR?{hkUN-x?j2&4muJWIEohJ0#os_5O11XjZ7YYxzt +2kA>aJT=rBJdb3T0riAh6^pA~x2=RMbyz$=O>KRSR$bhW!$b=wo +$u#>({Y3(Y3&q*MIIqT9{U@M!ty3G$jKqkYhmOJMlSTK!EFD=E@3MgJ5gHhYjuj^ICT|(Z_;u6K^why +*4ntumCNelf80K3|eMJxdpv4}=t=~&yX>pCE7$s#s!zhN2XA-d@Aky0bJU-QiOLFTpJ0kCdsIV3dZ7`U>4dBwOoSG +f733@C$c+P9npnG2R_je-?Jh*tPGIG(Zf~T_g8Vl<5V^GVAm_e|QnV2g*)7(#(9~>38pHhR<`hY+^$B +GF`$Zsf<%UZQ!Umj@u2w(!*h@C+wv(+`S>Y>?LfV3v0Q7r!mDNKja^zX(oD`gj;VW)!GUw+QggNwW?B +x#V^^DliIecFqj+$y>G(CVs>h7o*U0IN=h?NByN`|aQWp_*YH<}TM9P)>7#79FBnE67;?5VjLht!kXA +0Um;jkU4Ug5V`P!;76$;{?ADT1s{>R-BEMm-b@jL%q6Q7FL#fa9(-J3KXYD0VYxmtY$Yooyic9Ap;`H +3W7rL>oRqPFo|`bk8*bY8Wf<3am;Pw8L}}$0&!nro(ou>@8WraL-V|Ft~>xd^&lc+yKdVFgSvhq<20S +f*?&}4u*9NVQdUr6QKpEsvSpnGdF&ikPH-e-J@Pd!*a4?SxBUt-YfWTFaR|%&@@tN=Z+mpzuWquG6)X +^flYm){cd`a%9pnw%4e2;;P5??_y-$J^9OOm3%RmaQa4OS)MzWl|5nD4@XU4P4+He+$o%~luf}}PfNt +vA3%g=Bmk3g9=%FA5PgVe#BdU-s~4{@$~zuKz9O7178B6Cv8j=wFF({j(QKt#e=2>V%B)>{L{Xd-6dt +QZLTBl9h3Kwk8qna#Z{8mGcukN6y5iS7fA6#$~i4*)CA3q-OfQp7tj>BD=QNxR5STYc4t?m8ie3*IU2Q=^+a_&m~x^~j<#B3+eMi5gR;hLIM<=rJQ?bA_+aF +jWaD!kk;rBl^^Ux0Z>S(?uz^s^qOdy+H&&s +eP_x}JOFAGkjS0{@_ED4-(Iq3Tky=s-KUYh{oln)pbmkEBxM3`Pg>`5lXG~)tSf{WckSikacS%sBu+c +wW!6xIBs9>hwS?1g>=ZFK8cpl_@yY^S%uJ89IMQe7phl!>FOv%1WhuDHoEE?<8?x1k?g`2WRic{%m!T<16>=}g0-~hwtM4|AQI_q@shVC^U_*ab#TpF +zlrhYwMf^o^K&r3-_IM5?;M^MI#{WIW!gP~t(NrZ(fqkT9^Mgu-kZZ0WvnrFB^D^Vw^Urp1P~_IvT@% +l6W09{Y+Iv6b{{A|a<+`h!Exnc8K9KWfQu0_$pkb*&RvO|v7tG)4aqC3g*Q(J7EJakAnRw(f_HkyWHx +av*!in4BIIN=@l+EN{pZ4iJ^{#qs_uaBG)SeNOv1FB3mHh^RCs8^&eZ|6P;*0dD5_?E4sY~`lT{|d`s +-?yV5aM~Ef9}=I;*ctHuC}r^NGUbaS+sCo{&$xq>qgWeFCXfEgUu4AQ;4I160*)PQd^qdTS>4i~@0Mp +BUQBC@oudLt5{6(2&gf ++*w|BmaUz=m +?$phkssHC9P@4+I>#KS@RDP4IDoS6mSW +OZjEmE8Ied$A3D!5Z7zWH%9O@2UNV`TRSEm&t6HP<{awG}pt_85TzVBr0KBOzdK!;FUbbrsc0e8zI7s +={?u2=)4$<>ZJ;Npw8@(F;i3<2z2`kbG9>KETW&@;=P#e_&rN%fK&om#5277blqXzoH8W_xuBB*&qob +-=iuRPG9tF17eV-O3!X2E~29`x~z~<2xVO5pcJP&m3Zs7f21ea1C5UPl00Ny=bXLB259n^&&Z!%7!#d +TjE8rKVa;Vb6aA6Vc8(vN1}c=EnnmVv^by}?n94cN~FO@j!Qkqv~-zl_LA@XJzd`1<5~v3x)1rpS;wJ +x*&SW_FbWy>K$X6Dbs%^njbDKjB37eVq4w&^1E7TF(%2(9lGslAVlIy^Va>uBbfHwk5F+c_{dyCKMGP +Y-YnY!+)FL9C66wOc1 +e6Ab2ub-g&Z0j6T7FAq=RVj8>x^~dgjy66lS1Rl2tfzr+uCbiT8>`@}ykoVG}tAU+$h3c2JlezYu1`B +`(Gjb~|q$xH5S9*6KVon3TLyqP?VC`-&D$@axerQd!*Q|av!B0%}@&m0U-Cm2OQnAUT$f{*j=4S*`^v +$wfFT0K9$6%t5Bb#Gw(5&kAWyk0#Yoe90I{=m44Y2mUE$|iw(_BYlFGC>raceO-Tui<-K5p?x2h5WC) +r8r^)K&bzkrJufYlhmECwh@WS6n3s?xx@*te@!Eg5vk8Qh=G>l$_evp7I*XBX6p)sIeo7egVyr99AFVi +l60+J}ptpo@ZllM<&@bXGQd_!$u5yzV6`#HYuXnZ+o6C}=(5Yt2wQX#yb<>A(i}oq?5o!;)B8G>o_Y($GF7L ++v*xX0<;h_#Zkx4RGWojpSqGX5S#9Iv8I|L-l|o>g>9Cjp|N4K3_)C^1+JqY(dCu)@F7~c2&8CW?jiT +NqXsweBRxGX-sx__-dq@N6k=-2BP!qsmMDs=&~N<38hm7wbULTsl2oLJ%k1z^NP`gNFJ)Gp#J(%+qbAwXlk~b5DG(G5n(Q9c<>Z@l3Xws1_c}1ko^PrV +}A%EpA28x-kiXX8&9Vf5o+Y%u4 +xN_~Jau*^SrDs@pFq;dr&4eFqEa_F>XP6Lz7D$;4k=v*neplh(zv#q$Q@Lsrjs(}CQ2%c%23v_Z+_i<6Q +1c!dm!T@AkN;>5!!R}$5X|dJ{N&O6;@qBM@>zf!l1XfJnHV|( +h4@QC`4WOjx6uzr3vPH`zh}FNsH@86<14=ATJU{u +!Z*11vaD53w+7n9E3Zb;(!Oq}RP-^#If=ccA(BqHbjoL?X)7LtVyzRPeBSe$gCW+biSy?;juQKozhL+ +4V1xkwL%N-+gt(JXvp)qhFY0; +{j3xLU&hr0moX!<-X7n#q4$GDwpGn`+-x+RMjm6#~>{(i_A2c)o65Elv +6A=3VJS&E7$ME?TG2e3nC?T#hnw4CGupW1ofb*oW)m<~Y8^u7QT-w5Hj$!jn074hL87WU5$M+kZkvX8 +&Z4KvKfr&TrL`ys|t!^w@z#d`yA197u+DL<}HUOiKg8sBs0a4w&Z>&MkzGk!5rU8sEA{+f6J4S3#y8# +BUeo$~~K*1?MMjHGm(`Lf&fMPBVwFgt1Q-DF}eh^)tbidvj+yLb +|(s?$ZWQx-6`vnzxyXB{E0d~QTs-&7y)ELFFQNO^~oHK|KxiX5!>2h*n}7}X3#e1EZ8CZ*e+&(ZEfmX +65G9YDkX_gOwHwx;G6f937ZBSSlYG;iQ8)_G;zvWhNwQuf|k19Wva(9Z=yRfQQrZP)!RjyTIcI84fmZ +6MM`%J-SeUK;gcL8<2Hg%^p_E*fl?r2&JIg+Ql*&~LK>!>?Dv6T#}Lt75fDZxk7g9GZPs--)EDtN=Ee8PJULv>O2Amkh)b2l-+~62uB1!?j!hd76Qw#X;(4@MdK2%7y +`$^^B%?3tVF8Ff*(LP_5qv;xTY<+$6-!Sn85^0eb;NH(w6A7O?L{;h;V28}AJVErDue}XWc8xlJP&8{x<8A!y8rVZYyi#&R`y#2Az6KN;$c?TGgz1E>=!gA6!0id?Zv# +h?SX%w6(#3B)|~PED1M_;NlsNM>lG@yAeUR&t~?jeXOE8ygq6&nrE!S*4;W_lA#yEAxPN$dN +alRy5F69quwSA*TafI&gC})M-M4D5zc_+V|d@U=%s*tJH1B-bA5{^y;<)Z*o0C)@|F~WTRsZ>A@_uUk53AD_!lv5+c}n*|m*I +U%_BSUUVXMV5tV#q#_TO>G^kaJIYkfKG%%~2~LX02Kpi{a<+fI5syO(f%Oac_ib;U$-f76T+k|GKp+D +q1K@kFA622_x~=C8)I_%iQ1k|sXgi|of&hxSf$%Np7j(9o&c<1W$+wWZDcz;V_vrFv=A7YkwKAhMAaU +uSu_qA8-tY}Fct6?Yjd(2X3?)~u_Z!>P-b>4mN2DWa@9?Fmb=fG9RzO(*Ko6AIZ{_cJVJ#2Vs7ZgbCZ}mQF0g&c{+}8-wD{zrbFo4>=bJq6^&NlYArzif5vQQ;b%CA)#ax_P&APy?a{SU5u|5Ya(_dl55Z!T*dNeJm=;XS1 +a5EOS%a6xS+w{X-%!ED@R_ec7yi*;-fk`1AD(|&&{FAQNP^tie?Eel+JVt%>bVAG!5MZL=$srW+=e{W +xDOVo143{({ceD599kmsaC+n`>{!-;LE8%8YVm4B2h5i{88feGY)^|dNVSBLn+F=_*0 +BOCF&ugGFLrhQZ7>ur7ENJEy|TN){lr}GUOxhs(D~K+=KOz>^tBQdzR@ylkehDx4}bO4&j+Rd>w`t)7 +>e_%_0k$e#_ZD$0}wGB3lBb=09u@go4{m$_Uiym@3i<%31?D&d@W06=noWakT~__kh}biBrS**wFqo^w;@-95V!3n+n@vx +%uB-R8SOmQRR|1m#EC6XA(haCrhfPjsSsJwL5fEHHKuOSjAec>_$GXT)N&iSQldbS@A5ey2lhdKeV#u +ze2MBAg`+yiqhoCpiS{XadyepZ{7c8k~3v576ZwXAUIP*EEtC8#%1vCOp`73AKR&=9lL!(t)-1RQ525 +tl9tWSRCuY8>Z+9uiU8ZI@ulC9f*3-M}pJw)hCBNY4jKIz#m0}=CvbvP5M5KrnoR-suM&s^fFTHqJon +yM6d6g5@#-~%!&KgKekd24Mp+jBX^CcBC;U3xrn3OeGkEy?jLIlR7}%}YHv4CJP%tPGV!5rPj|026f; +&vEFauK$q#fo|LV3Jgv5*N4zJuiO6kYLb!3AW^Jqff+!5mz#)GTqJw_A?76lbjo12LhLA4JMCh!#}gQ +*&bH`bqn1Yh{h6-2_Thf^U9To3!+0~|ej7j26YjIfldSai&oCU{21bK!^+g8Gya)Gzi9a7Xl9}GZfM? +4*G?Rx)cqpHT7V*%|;y=h{q)eYX$wrAVvm}!nA? +x@qJsp^N#Qb-Z69~pa##H)dCz>&L(uIAAQM{FBPmH3Hi{{bcXm@ZI-T|4Fu~5n}T*TbHFjcM-KqLW(U +%Qi|IuiZ&VA+_{$wxO~w2tHTt50Dy`Lc%@Xcq#XewPi;!I#lagMM_lRVlOK<)Zt07bVB|a+1A=#>e>i +mzhX#KH6`$(kxW7Y`=dwImUbvrO~aY&=7Xk{y(z{MXtBg+bvX9y^T<{mx7r%Rx_|zZRoapuEo(e=Bwg6AHh)+GkY=G +P7UN2+se)r~zdFyb?T6QkipQKsoRSG%zKHsKseLRWH>|q$t1cKcTdU+EQ-+uLVT$_T{gD3 +>Z=Oaeo59kzF%^aUHnb`iNzttd9La!*|aYpHco;J195ML^oY!i +r>pL?C_Ep4E)3}a?RtJ*uN{212v0?Nh2TW?A5TI*RhGtdd$9BO?zB4X{M +j9~f(sc;P9RJJ0SH9QJEabZFS1+Mg&~oQNsOMrR;a(_#p9>g2lW_&xpjOBFMi(7}Wf1`mz)0dgvD!QR +ky#kA!^avi8j6tCGAmRh;CmlN#-F=c-qkDT!ra+IJG|#E*NWvr_HD0Y({`iAFqwe{r2w9iU@;?j3@}b +x$?Mo3tHZ#Qi{laq5@^snyV$j8*F8J()uE9*>X#T5cY}ZFMaEB%IzWQ}CVC_JnE5!Z%#>;@Wd$x}xZc +3*%#A5kC%*-hmVbpBzsFPaZ>I}a)Ab(is*uNQ66oRzf+E(V+vdE4g+I$k0Sy42kGKH>g9?0{Pih +MKzByCne&kUpVxR=q0GMWd!;P}W<3zzK!3JH!}i^M?}0}tnV&Aq3YA|99Jp}&j=G8cSy)Izs)yvVrKF +Hdtmcad(}2r<)BE5-t^ef+e*yu0$GwRjW^ovU7Wap(z(p>l>FHe>NMjOzm|Hr1HS +`_K=6HFYJsFKVLM*wXc|T2GA~YT#giXcq2tq(KV+}4lih<^G#gtveBoHCRL0P@QR!2j}(W#RLpXyTlp ++Nisb9nnMEePwi>%;#Zwm`Qv +bogS8Wq%)`k@<=$KJ6e~K=?)EFrmKnvI$AP_)v1rW*Od2s?+@I!ts+%G8R2i=C9vnfVF>oC(Z>Vr1i$ +{&Ny%%Qz(SYlss(MYUrWiRbwHOei1ciSVywDKFI(U}I2F}^AS24P1l(4qj}JDbW)LSzrO3e}+7Qtv=; +F})sgsreJd5U#~^I)uV@?Fs7oh8-n&u?QFR?Ox)D7uI-=!rV|;lXrqHV2NYVi7IHP$B(dbgDy&spcdi +KE(+B@I<+Z{LFLf)BRFR0SEXgr%}0_0c=Hi9fIr}Ul85FFv}Gj>TvNGKi~eaKY0Khx1{^N}94~Q%<%D +9e1yD@S19hLww#%hm-O;Clqv`dmYTQp(XWJd9TV4Uf+a2{N+4Qo(Hh%8XyQ2nWO!#q2cho9YhZz+YS= +G-5V6hF)wv!?|q^X@p)s~cSk^MFFu?tS4*L{iYst572Lm5Ud=b?oV3TBcWH0L(P8E{{YZn#wtdW!65$ +rP(2DBFT4I@g-}0Fd1b15`qaoO(;R$Pzm8#27Ex4B20whq{7xo7(Dt7R0Ut0!I(FN$S9Way~n!)&xA* +3DZ^mYyxi1;jWx)%xcimU~CT`fPP9AhcepLPIfR~BU>?Yj9y)=KFZX++18c7R%#5|s11x2pi38klFf7 +)tJ-~93~dHTaSd+HbI+8;gBEAU5Wja&7n&qAV7CXKq~R0j)LsNS;3_6}heybyh70hsLDsQ-_62Z~QKS +-ewUBvI3|$fEx0iFlhL}@OC@v_nDC3w@R1E{mJ_WJCbQ-+^!HO)H)Xhpr364}5OiELc-Jqq3)|3(jqz+WfihX;kfF8J#W +c4)te+bhM!;qV7J;D={{mk#`4nczwBrwf02gKb@vSxzB#3%3vdf8@a(NG2hi?ZGYL%6OnC;z_!a~gy)wH{2%!CS@zV#;S`_i$oDw+vF~&4{hV_jN^tHS3C_Ja&bjB%CYt2j>q +`=xd)ZLVy(GzOZ;o^BC3F>yb8fU9(WfYK?pP(Wvr)#pA1)cnyq67S-h<`gc6^yPy!h^cq1^ilUUu*bd +NJkP`(ohU7Xjcj&b~*`A?!PqCddBQ2b1i34)TI?oP+tEKY1TN3R8bDSxPay#zvrzret5Oiq*&zS9`<| +8g5pnD4A-DBP`ith;6mS0I!_grqN|Lp%yF?3C7BRlE|cV+&`J+l*w&Y(n5RFK<%DoNt|t9tnT;l(ml) +mRPb)haNNQd_vsk;iUkIgX&C6hU3junj$GN^gS(C$aF<+wOJG!w5n$obH-#|+M+ia#&(MOjTUi@0Z;vfMQtSNnQEt1t+%Gnva +3I~2yyJ5>FbW$6jt1?m^XKb!#bP5C30z0A|1`XPBc7(7kr5WIEI#g4cd(!&Zqvb6ANH$b1IOk4n$h>D +!jSPUw1>Z)EC%kudV>;1y!x~9Z=Pxx>@~t!ff(vpJOIS_78NItn^-PSq-|+Vt}pc$NBuoXevULow{bVNV>YQ~T?& +Nf=XnwVKlxayL-o4bn+LqL8VwmM19|DvH7#QG&vEI2?mP`osb*LrkECwVCF3Xl$gKunWMPlD#+#S!t3 +IOKn*e|U3ZMYxCJ>5?Yci7gjGxGQ17zvNECo{KX+!X`A$hLBJUNhO%wQg#p%1cRo@)}r5{MLk>P2ft* +5&MEj&A$ID!%bugMxGEyib7%)hstLr&4#D_{`5tOf&rGA28vKpF`=rSPXW$Qmnobw}C59r-;?hrl4Pk +k}XwUn-NT_4CGl%nz{16JWId7bd#U#FDBpkjZMIoDRU$nhi47mM_Zk=(kDzGD^?>Xl&;yNWY-vFz0t3 +4j%{PBt&hrjOTbMlM*AZ^1Nu0p;vrn^i2$K7oUPEa-bBxUr?5(U|#iz +H5%4$;#Nu6(t$U1aHlxM9C|CB{km5(>1r>y+4?V$w70IF+r6CG}-ss`v68Z0TdLmL73>G>p%q0)AGC9L$s_ho=QI7iC +ezl(aw)?(6xi;t_FoleGMrZ8Hq&muqQ#068g?S7VdA@_X-D+n}q3l!#VBnvv_h*^45*RPK^)+0XG>@$ +8DUY;k%{>FTa*5Tw-vdg4`QU8@77czppe~=*AiDR`FX!0_&xJd3zinWZH&Qg%_V*E6X50cd@u=-0(8Ald4O;#L^m{sBq!eo7j(+jZN2R^l3K27dj +)fy7Egce7XYaf(T&QQ&znXd(x+_kce3LQ?FK(`e?_#?m(qur;Q7FzfIGTmn%yl?$F=d+1Grlfw$n?K#m3N+%e4>J#+TsDUAW~au8qHBBycc5dhj4eAW~Qh(USTl$O2!M%q +FHDn2-U7Mg7d6{Dd@0RlT@0iqCV`_@nz#WTP$n6YHaP8_FDa3c@OuwcG2k7?j~&(&Q%}LCWY}JPM%M= +=1xNy?uj~0rLgY=gw#6hsUyXDEQ$)uv7m@ie*WO%rRsGkL@8dDeRhLYiKjiq#21ceyAO3PV+3ZO9$MkRx^mr>j?zHMS>Ji<_X4&0ekwxFb{7ksq$ox# +cC-4lF$p`l&st&K>22Gr7U)2C%qmNePr!8bVy~~Pb$8MRlB{z{DNMS}b6S_B;g-k%+_Hg!bw$;;C;gi +*dbXmQ=M=xuhp$i$_aJdoQrU@BMGcL!_EN@MD5h$aZF@xGrB1f+8;l<#l^JbF08WPI91&Z@tvHA+eNz +iE=7vL#q>@9VyM}Z^|S!60UepO%>19taTG4c%SLE+LP@z$f=^ktEo{T311T&yip!>S3V89xf!B-Y?)g +(OGj@CH}jJFW7JM(1S=X>i*28{0~3{pg&aHe1{uF0av2Nse|H-M$7w`<__tSEoC5Wf49GlzXIZpI}h# +z=tI`%ulkMy6xr~W-a!~rAI;S_%~!_UKKLgtbP@@I~*yIjh96I#N-4<%tQh7=&JEqblY#9;bO^8kSF= +F^k!Ji@qPw(|MF@d`5HL5ObYL2?VIk_@v!@J_kfa78E{)FV&m!RHToT{q}~ +?Y7JM38LYaxU7_lg`&7nWCS{1jr22{vP+-h$MGBLNsqh+YQ#-JJBEkH_cYurQR$kV);4Y>8@b!TbW3| +wwDq5TWJCQBrJlU&u$EI7}~c$_8sRotkyUHlBHfM`En#WuW9&3quKW)3}1HB>Ju-OK&%w$i(9<7Szlm +Hy$Aq`3-a=FMKRlO6hEUHb58w8p) +#x^I9<+8LAd0UP`BR?Yyw>Gs;={7)jgAz>do3Z;#r&+i@Ne|uTQoB`tfcED=J(dT$9eQ*%)WXBK=nB3 +C4`>yZbr6t*sP3(0Vr>6w3>yem6PPvK{`bR~z^K`h#uB +9dUblIpe(wcjO^^5VON#ApjNGo +?em)VU^>a_WM|1-5_-m*N3TNXJ9o1(NpFJco!U5G=tyuBfTSo^I)*30g0C|d7-IW1D`Vv6Q0z$bT560 +f(Gw?`nqkDSRM9)YX>ks_H45#&3*$~FI9nKSEMw4i6`wMFKm~cX@Y$l=4(+{=f_jZ&n5r9s>7MF3v@! +-W+^OfXjXhGb*3WsH>swUqMS(VQjZIA7)f0L^ZSXm)bCTeX@L@2}l@r3p=DYj@}e+ +z(q*_y5^%H#vSH+i1UZjFcJjNu`&@}EXsJ9_^tHX4|Kh%)ZWw2d=fw^3>R6^G8^|RK$(LWs`A<4p%`}Qu|5zMR-gm}`qd?01urG0eer?AMlS`* +v4&z|8(R#2c=<;YXaCap%TxHcY6gxxI_CP+8>Nh`DC-HeMkku1enj1P~_qZFGR2>UHk#B+*mBlz(=Dw +8#)uzKELp2^{V;X{4YWD!H%sM_VR+EvyFwZR$)2U2?Fs*_ml@`F_cpvcyf_2`8a6q{9iszQ7twW&KZ^nj3<{J&HhJ%q=2Ii3?m$uMmGv +CDyo3Gr(g*-q&&QIVS+dl_$kDQ2s!pIVXa+zHEP2wmWeU>@9r(vE7CQ^Tdmz;e)mocl^D9p*FO`zvPL +BU!mbmT7PB}P}TM`>lUX%{263x#I$Ro`)!xa55SXL*yK?KqyXi(PY&{Ztz;h1+>?L3B@z3CxM?zntd} +K-mk6$uU3amDKxj27L}(Luxkgt>$(mEf7vY>Cbfp$89)_+Y!&2i7<39K!j=qlI~-ET4^hdHEFWmEUs~ +3$_~2sW;UoJ&IW)~Pj$C44wj_1Je30uB^7?tgMUGo^rl(5paC6hb#()p#Of~u#I-{)SGv=KW+aYdEPk +uNw=yjL@N~Qv%p&Qj@jG2K1k%WHNq1+hi4qB!=lv&f$l_EgM)#An$dg>+0>ye +TLN|#KB`DA&%|J_*JJ9AXER>L4USJahDlR`V&uZ((gZ?sVXD?lkizVwz{XuoQhi>x-GDr&5V!OX~M!s +cChJ*m=%IX5C++)UUpLickqZ`&PX?)GejxQeB7|de-mW)v5NU}X#h7B`}B&NEqg06U}KR(T`Ec8HA)^A5fwAEGb4d=W8@0xLN$3o%T%y<8n{d$jX3qOv^5&@^RNDbMMC5KG*F4_(Mi5rqFPFlCYp&Wa#1HQQU +1oJL<-$t;w1IEfrs~b0IXKn+k;^X!;9K@H5xa{Yk}F#(uyX=D@)+InZ+5P3+J2P2oF@ce;lJRj#p3NC +@-~0(NF3L1@hA|#yJOy&8)#LBQ8{wy(tDK>IVO`&ntc>+3-m^QYzVLD@YJj*k;5yxeAU|(OL#@ERBP4 +Jyy5$My({q=;11e-Be(Qkl!iCXLs_A&ptYw-@T36?E%0?HMqkEhvV;5Lp>k3$O=^|!rBb<5Z&f7t%cq +;RpqW$6)amcH44T%aY(di+-pPR84RX~cZ0gX))o?x}l-9`3@ziH5hOJtXpC6SM`G|5~)QHk9Nq|B7u^-4h@? +sF;^7vg>U%K3%3$EjRWi1u7%YN3z{k74epk`r^H#fN;Qjga0)Td$TWy^s5U*t*ZwVrRm|+oVvJGHRuH +pji;Q+a~%Jt*(qnRid{AlAvcEWt6xsHdYeXePdO(n4l>TkG&GteVtX2DrLsuVA%(_aasnvTa`3;9}fv +so`u(?p~>U|y0A5Y=8-zJ$9&uM1z67g+ARXYziHUg1iDv^)9oRhy0#6{ +27$((6I1jS!Aw4`ZL)Ex~Lv7Hi6b(c~AWh4rPPION=XMxxu-BvWD(BL(4DPA}`YcF$D8RFjqdR`OSat +3tUQx$ASuk{|nnDX!H1QHjfmtQg_H72{^bfOdRW3%k9$Q@72jz-`aqYc#V3QH8rH+KZBVb +1+q^-09KM(S&A#SBp&Mb&^c#DZ-TvYkIyTQB!=o2 +Xx=dZMdu-4um(FWJct3Xs*aW4cm_lzo%$d@^cvjYgiO_^~IHT91nI?2Rm`!{glNy4i%wt+gW)}>41CV +=BAxhcGMTPiz1!ZC(ep~^kg9jcL6yi1hOwBb3!5nXmuS6TY7SGwoDJH{P^I(Z)LUzMvvRM5lZe(>g15 +K`|53gtuLw~{u(#$ArQnU~$Osvj^$U??Vmbjy0=y5}Qj}cE$`P^SUVwKcWrbjM?U$YomfTqih#U);HP +zM#)20?g+W*YD==@xweB>Z9Mm4TQBT--2)t1R0R$SItX@E`kS0>v%-tUJBq0K=PDjpx~cQj~E>BllFT +XgRw610k60jd%vI+pzjG49gNA3J@>>3SS*e>`)NjE5<}17I#JyPEo71_&gdr|X8bI{i;`>zm{QLK< +VASYAG<4&J-V%KNgN+n>bCI@GcF@-f`zwqoS!r@Qy4S=ZD81d8I||hEdwx+hpqzxD#wH7*t0FHXMKsD +?U2K!4ALCCw2v8RlCI#(L3;mP11g*e8-Rz&q$o%&$GiJ57Fvbz&~q%8pA1>l^~2%h}&5*V{~KPc_`+5WBP&`Urg@w +58{QP3rum|$BpW9dB&$&I~lqR?^NiHyAw*SbGrn`VBpi{9`t%1~ +iCh_&%Z$0UiM1_aZDVfKn-3}v-oF4tp#B9VoYVhBbK$l?S3Mq2A$tqV`*#9!Sc;pDkHz~R9qfO7y#L% +*i2V=beo`dXW{oIQ`&h5~Sg)cENvu7uOg+isPO`WLhhJ?-@#`(v=2mR;7G;xI+aT7q=C+V1D-!6J&Kr +n3^`k$a-BsVnFKAZID|4p=v+>4enU@p%8dAjCjNE9#mg++fz)u3C6=qVe)Ge3-WEW5@@mPvW=a_mr0> +)i(X-iKnn&QCh@t^VFE;Di3OFf4NJF7c^9a>J;l +{GRS;nsODoRcEd=WdJ5>(Ce)`nxcqh1R_+LQWiEKrn;jhC7VZ?Sd0nXYojr9@FxCZ1ic&5WtPZXY`f6 +=7Ex~jj>P@&-sC!-`RM2>PuUXU +8}P#!W>JUySd>c#847VR{S3b_JN1@9X|5iZ%GFdYO}m$e0J=&;EFf+quST*2!o!0f +vEixE&+0E5pDtZr%Et%BqH^dk@$rcc8J|GBKE!V?;Cz1{slty%;bb&+>9AT?InE5)&kW`b4MwCAsV)^e7qQKM2fgO!birT}D>6NR03NigS3o +8^$1)gI@4z_%3r!VX7~G{-;#aHq8Q|Zd1faI+U0y@_kd~PsY#GwDMA&{-IPZ+`(AI5yJKnmick`@ +>O>F7)zl2c#e(``XA+S*D8xmi@-ql3UXJKVPyCmPhNNxc6rj5hP5cL7lpq#st8hG3s0}md5 +g$1z~`Za$qVTTLNzxfB-ol?fCYY`3Du45k776hPc5jgUA$wrQ7^E?DEnAN46Clis~@QHmf(_bQ-`Xrz +mWV0JBLsFKqlx7Fs2eOg55S-y65WDRa#`TkTrr}6Qn16bJ3=g>5m1%gCfo!3dokr7hyE4HKfwxYh^nD +F}4O_ndYFPsou-jsew1_*rQxU@McXZ^8YibM1d6&NOj(Z=M`ky^LSj +RLL)Fx)5*AWEVCqVH*B1;y1-VwKMX5{NR;=d#~Up4)6lMfOAQWL9d5O-Hqknt@Ju?ZSp#oK>wCIZ`Cd +m*W70CifiheneLEQdM#hnR3Wmow5BS4#b*oqjKp#3*V*+Ly?Blrw+HYXQEXHSJCgm^ckv4iGSU2Gv-CbzS +dhtzwt1h?o<2B<*_QAp2o9#Mt1%?#@>6FF=MB0`};k7{(a4uFy7Y!k&neAH?zna#^Ysb$XRF= +nj)Vth40Gp7TgC4)6+~(hxs)nf4*~ya%p~vL76J9$rsni26x|5TkcLM^XeREP-TY6Z`|$A-4^@~8kUl +84}K^|W}d$mmzhe7#c$li(#Q>_s@SV&oxKo*Hf5X|%T`3aRWYIeXq^d2R2xxu9zL?_OcuPFrfxWd!ZW +kH;WCS64BrK-_Y+p&bZc>00XE0%HU&AO8=%9Xx&eLy?4z?gwz>t0{+0&;u{mDg`TpqVrVVKFy)ojw*y +<-OQodceJpXosa*4QRIH)lOciYl2Fu{M6Bds(_#@&*|fU(8KZSJ;54x?_6KPI@-uhv_Nji35+4+qx+- +l~pb*RZ9^B=x9C8Lb}8Rx;}^k6jDoehlb_##(1bmS6nsx>PoDCNZvo_;Ys$yO1=> +PjV-P08kFh;tPL^698s0SD-uz%lpu8n4SF{0MaL^+jUyK4zqSq>nVKx5oaCQNjILtjml1Uk%?b1u-1V +`)gA1Ds1Ecn0D8HXtv=85dDx<#z@&bF3G;cB_2$N(%+`<(2-^s19c8Y@Ns$V%^+@iS_w4fWF)z-MUusnT(luNWnl? +p#?t2G>l4Xv5FVHEa7}GJpFPw%USS%BF86y43J{>{8AimS}`FKlm?Q*K*NjH3jhSi`NkFQ-vM9eI8(` +^ls7(+w2159mVfR{g=-tFg;l&+JPrKi>%RlKu1$5duy^!yw>TYG096e-(_X2pI7Jt70-beG-jOy;-THr$l5MtnWfc>6kzo +*!5Kl?q&e*4&OZ=+}Kydj>Wb6~_C`+buA$`S$n>3D#|sA&x{VYwjZ#0IvbFNQe#$ku|m0EF&L?1qcgz +h;uJtsxlS%=pV4ahvU9hIq`ZI~l|(2C+j9oBy~03t4tYJpDqRUXo0Inx&T{($jdlJ(>OxOV3ZFAG`w< +!VXBde*+inCj$5`g@NlfYXa^Ad{Y1p#S*s}95(OecDqfu<*czB~ZLz?*7 +n}baZki7xY;8*+f;P~R)PoPmLWkq4r2(%Ppqo$$08q=l*a(5NMqB0h^pb>>iOhb!@Vn&nIm+TY;q>V$ +Wr96?X_8Ehti1{5@ZnO)Cc{M!4*)L;g1l{vSk`3PXM&hte;_lDx8Fr7Kbb +u(QK4t~&Q_=-(vVOf~83<-6H5OS<5!XaDi@33sj@Zbybb_XIqn4s4KYA5ve{G^L~;#nEv* +Qt6|Zr8Wc5ZdOi(-l)_-;)P_;PW0obOziZb$jd{c9}7h?j@7_gfeEPWck%)toerF+O_H=0UC9Mw6a)W +HGibdw()z7hCP> +13|qMB2ZA~K<`FEti{wagr5~mN=>t}L9|#QiSqAo92;2ripNRSJcMB~5OjF0}sOGlIVc(xo{=bBZuP4 +Xx#n+e$?9E^B0-Be6tKu>^3W595&}6hj?=G@?0+H;XqU&PluWSL^O4Y6GTWt&Rh9h^AG8Io-PYRUQ17 +JWwH>MUz?PS|T#She%6dS8s@z9xuUr7RxivR?MApgnWMVR}1%soafZ98k*%=nuqJE}G#zf!q`mb{j1_ +E)RV-E4_8#hhvAMzCWFWDLC1$EMT_6Zr#_Yl3IZn0*4 +DnFpoIlW}*d46%@rWxXzXDyCXxL+h{Mu}{ZOQUimtKMH)FB@BCifgLVJ&-CzsR;*RA*huWv3e%%RgxA +TE^?)5Y+JVaSqpz&5r3YD$M26nUyMJiQ~5To6Pp4pPW^9I4v?vP@8P@4YHz7n{U)-bT>Mr#N%N!YDRMoTfcOh)=M?b+sCeC1nHA^#t{ +LbFg`?btUA?hxCZ^xwyd`#+ebhH+>R&loIC?+<`v~Hsp3Qj{^frY2M>73ng5(|`&Fm^4(Hq5@0K#g)z +N9k?+rC5vvgpnEj9-ix`&{^5NrO3+3w>hkjlJyS%y=VoF=?cZYuMo9hccnO`TXpyv~pH2gwRSS)c62+ +L47PA+6ZyWFixt3nW=8~V1h(Wgmf`{ehN$WqBaqm&yan;_^i>0FF$^wUG4n|KM$?;KEy91S9>4kMpm_ +ViBhWeR*2PU$e?!j@NjdH)%IY%#9n?!BzM0g-q;Te +^*+2FHu4gt;iZ19lePeE0-&Dn47EOK#tp;?c;5-k&sMqTSb)?=X5^{81y7_Ho6wrKRol&0ibx1c0ENY +yi%#Vz+WJD8SUs8<-jwu8cb-_ybTNIa4v9_1yjVY~4pyo1)Q^KjNF}U!1@Wd~QB^vgdw*g|RWo{KfCf +ZI??JW3_m0fGeMtxD(JYu1;r#fazU;4_$L%#hp1ARpT-pu5b-L}H8&RAsuJn?f?2b$j)0PED6K;6Js~ +5CJ6dnPhPH&UQ>8gXM&noA;>I~%=n1p>` +V$~wDCqFp&OV7!aEtT*Ved=eqO8{c&#=e{=-@))KJFwgsAwpfjLg`8khrCl2FM~50>O-8xu8H795F2` ++pVl@xm_!BDX-$bW;A#kYxlEL47 +jP+IytABbFkDyEt}I$HoNA=;U|u~n_e)x#!&7^|E#D2p|VK^YFEHHV~7q9NZ<5Py4Xu?09*d^`5K(fQ +3;v4Lxix|&X07_?VA1Eou?kXXGfi2i%kj~eQH6|4XAds+oECfjBe^M%P)$1i5Fw*64K7>dNLlM5OAC> +FJyUkp{X!9LJ2WgT@M!6I)QyrK{&6Y)guYtD*(mH7B-Rj|oXVVkZz)gdmK!>5Rz +GH!*Msl$hDWza03^mn*VPKIEgh;{L9Xdv#p5lLR6ZKLRax@`dc&%_xL7w6hnhz7Z;v|vQ0y#;lhu=-c +d6`OMo2UKQBgRwG|3`;#kQ#Ep!y=}ogx-in)Ny8RSmFOWy4iWByUGBdbDhI$lh59oDikbmZ2Zy~t=#vs5$0ozZL!yIn-f6%|;KYp(a4koiG-z6SNZgqv`M9*Z*6$0Ipq&_sx(Ds}o2 +yhR7h@Mx!NtCIqe-@)sP5=7uqnmlxC|jMSLTwX%zryN?XvmSV+d1uhX`;USeYv)XvuUm$%YdO95uqF; +g<#1yw0AiGT>&cGXDaRikVU&Yh{p(XtbH=e-Em91s6kX-RXaSTO0ZxYACJ|>obS-mETK)SLJDG&{cj6 +12NsF^0;*JsN8=^axEYKrsLl<{EM|XzSXFa9sSc3(D}jBE){Gh86(5(t1IuVao^*kK7R!}!>Q$%-bw8 +@YUOFJ4)9yO82E=Lwz_7LCj=MGwcV&+K+e +p*YM@3R|N(4!KpTHV&e4TS~2fbMsjO)l$6U=(jWhh^W@tClW2#(!LVu<54;d96I*~2a6Yy*k1VP&6k% +0~2c9G^;=r_M$EO%HSxECQiu1r0-x@=45tjJ;hLjha^EIq0$H0m*SpIkM5p0F2aDKaZX2a4`yV#Q0o= +Ni5kP@N!r;wMpBCjeM1Kt6CLX^XzsnreH745mlij!!U|6O!JX#7P~Tr0G}S8YLjLuec%3~J}0<2?~l+ +@U5nY9fHVeno7nBXwXpRvHpzvn9694>^HdY2wBqzDs>@ve2rIZZQ5(xh%bv4xP1dI?L~c;I6y?Y&H +-Gfih$_69sihvECG?t#n*$?>pvF>La*3^|=vSnHcs3OWs|c8fDhNa|v74nG06;3LGvwazXBaO*7vx6d +lv=Yfr+-PB1kjzejP8tJ^yUkgH6B4a^{W0xsp4~R~P`ImU3eUXs`xJJwNDAXFH%( +z*-IWyL)|$#zIz<GMko{tL9`$$%u3 +_CFj$wK4y +S%;g?iF2Sua#aUVDpqQPjRFOWn3v{(f0OsC6}@>;De)gyt)+fp6{S#_FAnaPrOaOh5nek)&k$+zGZid +g9SlW-DTr9(+sDNHuOlB3J!<7Bat|SSz?@wfxxj-#?% ++DI7h?!V$?m4V +|<0tCLe5?_gc!>KJ@c%!u}vu95}UY~!R)nUMScRH)X$FNZ^4sG?RYH +8RO$8gqs>D|Xpe +t7~RxXx|1?L@mwX-R-@^?M&1(caz`PCSq11U3{egEdbfZQ!`K&SAl)kXI?;4H={!Av+p4eM>lLFLOjj +kskLG@x?0Uf%ey`PZrEs`A!&uPg2^WB5mB^p6=p{%4yrR1p3^N1HAVb1KLp1r5CO#>8y+f;b?ke)xt! +Pw78*VeoHR;CBvrk&HF>c(ka<%f(fz!G0yi(9WO-v{MDIz!X}&hnT6}Ej +34pgQ*OAnfJ-VXDt;14Tsf>2ObzHKaRvjLsc)(ILk8RKxF}SqV@I=Ip2O>Hq<0{8$Tu;JrbJ$s6)K97 +p4zgTYucX6A&AJ4qdqyDd$h7)b!fabx#rXhxFP0Fg)q%yHS<$V4*lEr2BYim-Q<(kyJ_q&Ff`unxTopnM;*SHDkbYDC7v`(@%M(JZoXn&r@Zh8FT43xbJ-o;uo@a$YAL|sskP0;A(DI2Od-3d@a +G1SBJtrA>1Nm%tFO3XiD!q^b3evMQ*a;qMt_}YN2M1&J4&b8t2Y$=hy)!6EZAusqgHj|noC%#?9VH>L +P3jyedKCSalArmO9~MivBPkGYY(iB4E0niJ%_ZFo(Vd&((|^q((}4p=`j@T5GxJS3`O^P$km?lVzuW9 +ZM6r3H!}%4L>-@`7xoA}NiJaYZ)K(^-5jwkDEck +d@{Jt7aeOkLH!9B16Oq~>>pGwFhyt`+CU?3 +H6Ca|ECNVdb}%>t{-(AgDBn!}BrDOca!8IorZ$l%IlSM{~*Ko~g0P1!#F=sS=>4O~C=^&b)Ifw|Rbun +_1Tl|n2??IwpU*~;}J0jOK@rKR{cO1#YUk18v%R8kJEPAx^|nV56lRprl +*rkRHaVAZPJqnKmWYL``%ZsjX9Jl2+^zLQH*aybf(!8VX)Da$ZgicZg)pH^5t0VkLDoQ~xwu=kFtyR` +MG)AJ^X&}P4{t74-aH@ZsP*}PV9)KFAFEWx$&ma^N7C=c&6(n~x_eQ1=FDHg0&cuH2v1uK!D>7SwX*R +CpT&EuprR}F{U`sY@|g7n&p98o94`qkLls!r6_5C{}*&Ek^BiuJ3pwRHjA7qPz6Q}SXF>vY3KtmdY|( +`RYKH2yN~49t;hSVx;)!!kCyhUIC}7O~!o6-{|r@lm;oWfiMfR3hf$uSxzdiqq(to5Mp4MV@HS`MV_f +=8}-g->5p+Tcw#JD($090=LRXs0<@&P1~_1Wf)(J)Jze4VV}BHtO;9Pt5}Aj^h8SVomBp=L>Q%YqM)HYr5NF)~9DhHhNn}`tM~A6 +oIycitb#*PR9yT@%MJ>;rPNNtK)(RH^N$0$c87D#_+NsB0ZW^gP(tujVg|%S=b8;8u^$ElhcFF(>0_x +cwRz%s#)~5K)b5H0EGv!`7^SrhYL}WeceLVP_>Xnfr?M$CjeR7trA&d9kTD#Kubn@Ipl=t9iyyzk!n$ +knr^YlWxwsKm?C!BZY-?rVH><9L>5?&E&ZjTtq|{s9kP(7Qlk2*2}rt +XEdAG2MS}l6)I1j+@~9eOE}c>WEHm9#slJqyNu?qHqC_%;&$82@CW?fiCJL>vxE5Tav0gLM+I;Mz%;8 +gnh8ed;TNK@Cb(BH9#n96`L(U3?dW%^hai6-|tdR3SkxOH}rKoX@)v>qgwI;qta-5=p@vMjz5f3qzmt +ajkXD#bL1Y5owXK@Hzu|x#A8wB*9QAV+ZXxT1&)E0@n;$=5Z!hjttMcFS8-Vwg8gZUt8 +(g>}VwQID8B$I|oz6wBS(L#=a>B@U8^u+|DFRi(^X`Zi53V9SGsK0+{T-{2{snPb0Qbfm7Ugz{$>}N! +p&P`h#79L5bo;oW+p!UJaqHR4P=W9zBGuoM3ykk7bYWaj*a*hj8MkVlDbRVF4CNf`idYp#s1J&0aq>Y +z{d#NiankaSJ&2s#H<@Abu*Mufm{Zr~6;Rd58K6>fE^(n?U*fjwyRq*BZc$60v5v2>7#3SLH0?pR8NR +TuMGspze~3S`hn0-dt2(JPutdWUm#tY?K|-;N4zvuA}k)u#$)#Z5z6SpTH>m0iWr(q9{jajr +bySBaZOv=-bhTQhVG4Q?pv7XPt +~G)nn-9RvQRnTKP)-IjshHm&@D@KXsMiuPztdoXOH8TB0|Og5( +^kxG2RJ`lF|TBDoHIG9ooye +Kb4$UPTQU{R_v~!%T3mxen@QbqpKI!|R~^jlEoSx_n{{$Oj1UKfIF8G^9dRnkfy!KQ?y>sbmfFP@n1| +GhUFzl%opbKOx=r1l3*C3AABYRtZ(7QtO1yN@yu3*5>HZ!I^({+UId5F3?daY^jpxC}?rJ)vu50qeME +IApsQJAUv3;BqVV-U+JYO+4iZtkNmTDJJ$|G6DiG{JGNCzJ7t9{2|&mQi*kHX1gPLGRL!4_gIyihUcp +K#euF3y)1)ZI$i@N9Bt*#a?i;DM`y#Thh1$zJMN^?}o-c`TA1orDJtLVTz3^HbDW*+k*DLpaW6yh-Qy +$vOK|XrJ=z_;_;jz)gA1sh^@1C#O+X$EVhilW3ckW6FdFVp`O+9Sa;~Q}rZ|7Tl2;6%2}n;)O^> +aL`Uc2Y_TSf-;^g^zl~8QW%`*I8&sGbyP_kgntWg}#O)*Jn?95C`u^6{5|f1;t3GxXhrD74IP=(RDu3hf00Qycyzr!VmDB+b5DpLlJI>!}+SUs)n__9$kyIBe$OY+= +>lvGyv@7^l)Y5Y&Tyq-=hysS3>}~&B}s%dXadbEAg}9%->1?A#1UiDeHXqGRETM*6(Pw^*hGl|L&NjW +?lGL!^Y`4y+^re@mEj{&4z8qOvleJJ}*v4pGJ^eZ8+HhhiwG|dN7+2(2LovV+vw*`U2`d-W^kr!onAm +orUYFLL0a*5$+yUL1feE7gYsl{{HaSg%?FlYF<-J%rW8Odl1*%s%1*%Fr=hyeRRJ=S +giYqOud>!7ml@fn+?rTv2Y2pY%wbZa#&MNOW6ur#EfVaZ=kLBR)jEcg0+cJ9}!=@<#Wn;Fd;mc!jG)= +*RS|(IcZOY!TX=hcAVN+ay_|QBp;$U7c@in%yOSV_aKnnZ+n)@x +{SNv1OJ3Idbzfh*^7zX!D}~S7r(hq|4QgLk%Cd@7D^y3y3Xk+cOsB9yjFU*s{qzgJMID#TmxDmm2Hn) +C~WmdVcP2nS9^7=gW`hMlv4osjak#vq;MRomKWDLYh;+`E2CFkq8seRIO2af~k~Abbr%6M)bG$T!JI6{xj&qbW=buaNHad#biOamC%jA5uDSdSsZ#1FU>e2!)cag9H`+8PpUf%qhC_pDHcX)#+L`qw$ +h9)(y32!9fsk&nCLnL!&xoO*d^gSEzQ_=?>s5Z1u!3yX3U5>%cXe*%p0V6wfF{En$ux^LYmjXyh57S! +(1fI=)s)%(u@te&P-{>hF52zG#`U`vNW%O*(%ML4{(l@<_efYrP&E{Pid}(IY^poVfL41Of))~H0xph +H9_(jW~Vd{u5b2!YeN;9stcCL|T?51(9l4e|Q?JSYzX)w>1=0uotq&Xe +t6luohH|I2I&WAZxnhRi#l;#qc!=!ly%)!#U8s<*Yyawg~Xmw;(p9>Ilgn!9(n7jKlFM@Ga$$ySfXJmtx>QP+baHt>x_l&Ea>%7by +6llI`Q)-ty1Y5V)c}#>-O}-?8LpOy98;uY=?qtsM2=IXqiseV-y^5EU7Zz=RsKk8=?r@9R%_`3eBb-n +9hmyqV=cAl9WxS#@Hod$7DsLA6h`VvU$f)AXvYo{KNuN~)7^Nvh4ja2T$qSmay$9{h+SpVbn`tNC(Vx +3e8*W!@oBq{)uA&x61~noDY|@dn_R~eCdVP%C{p;PUf!>^lLzK^!HChRHlfx~fkkhwmM2Raipv+?A+J +1-KKmPKA0D~m$CbtQ53nvihXZQo_O+Io3^Z(->xtR)!is9=ZP*|bQh`HJB5^|UtNVNo9TJ}~I;Vq4;? +Qy5eeBau(VOiHK$sGVo#h^hR^xrO2JkZ}#qkmTb##&g!%W}u2)aKfF@NF0D)1x>e9hMxd+KR)#kBEz +DY4C#~xtPYswDM +Hj4ie6?)BtVv&FyYqHNMHgG2LQJ7a#4w_H$=sF{M`2bF+}TCwi7Mxi>G~Oz|SI$(%gV8H-^#nb(P#Yc +azeOx86b-af~NLT}ndV^kXKrK`bSqSBUd_i#?MPUsEBRC*(;Vf6-FN%$*m^+Q?MNe0~7}S)AMAW!M +BoxK|x=TC`-0Bh!gPVAWWB(~&Nt|Q1IPpKuv)uU*COyT6U9A&i78E$jlge?mD)&f~d#Du5B5|1))%I8vu+)q#mqi +IrQzablrVrIY?snT!;xV@jkLD-NGXNlBJk^-=Vo(Wme8FL`rB-L+OeS4P?XwW9}(3`UeZkLdD`bG=0GS5Ls6gz=GskE +>5c6$sln8aj`O0?NU%JwM{H`P(MY(qIbB>Uh5IRZptHTa1f+05Fi|{2Tz~Pg?U_=~swa71UJ#ad?lBa +16z*5h?nnG`j+m|HK!||7nUZ)z(b~)PFXAGs6Gv3fLMNrI +FaCaEd$VH?#XtVOxSeWh;XxyzP&pEEaGBeB6kfh;>w@z*sD&>J95-Jcx~uK@^z`3Zt(I$ZiHR+A +Ec9^aapM#7%q)j+{CrUCZAPtwAcM?b6gY}dsWi2-GTb&a{_7Rs1#oMr@!?0<$Ym%nP`M}WVtDlaB +MG>l7bY=!c6Yac(d6AYd5@3vh|l)0t%thZCSaGCTI;u#orKF?Qv(1XqriLypHf4&q48j!Si8mbPs^Vy +FEUE8kI6ZkuX7y8~M#>|d{_JMJZ>tZnnO#b0tm+T!!IhPm%jrx4?4OKS2?`}XL!wc}x8Jx^E*tGPHfb +;!=>;$60VRR(KEQh-kKT|>%o2b_k*h5tk+L|v2E_2XQc(I8ByjGZXP +>hKA5k4-+I&asW93(;^Kcj%oPRyOL}V$D=E(=5}8duKg?>RYzh~IGTRVRSaJ#%gfX0{?yHugV#~ZU=eW*P$EuV(Q{C4&`>RHZQnGDn!#wIZp53UISn +-?OwAb)iO_q~b3v2J@&;IlL?|zI1oqz)rj8yP81=AJ0N5SO^u2ryH!A}(YSwVe(ggq4;q2SF5-l1TYf +&~h$P;i}sZ!7qNf*!3TY^`7y1^X&EQo)-QOjOXO;0gs_Q*ft(A1YX_pjT^^kAi&_9HZc!3f`mO0}4K? +;CcnODY#$3lM4Qz;CTg`wUMxsf_)VXSJ15BEefV6I7h){3cjG=Rs}y)uv$UZR>JEP3{@~(!LbTXRB*b +2=?dPX;C%`{tl&BYH!FBZ!BYx;tKdZi{R0&~>iICBzP+iZydN%#VeHo%C5$hU@cje{8$Oc{OZPSX8~1 +PQdG{OKnT#be#%9u+uhX&oZ=_#TcCIBq!xo>Lot&DN$JlI^$C6n#%Vnwb8^BUnCd1ab&@i3I@0fzg^r +PTx3Y*Nvvi>Yw<)zsNv0*HhSzI_wVK=jA7RAOhvvAF2c9z9#EQ4}PWkz~)>4$ucB76(xE9s?F#d5%MldSKTiw+GZjem_%kkSM{22*>XrDGQ*JX3M?YTN)XfTw$!T6#D9$?}{lD7|{UYb?KEeTH398qFOcMgTmrC4^6Mq@QetDAKxYUzdj3H%d8s;MkrU_MYumb9Vdv{Jkh|3Pf{Rm(e@a!XY +h%le(I{Lw1T5mK3Yg)F(JUtgYp6;ezV7^b+%PE-9v!}Mm6Pl&EqwFh`JxJM&%HCetk2$5igR&{E+GMP>Hm!)Uc+20u3Fwrq#s`|wGl3U{pXR7@rqxt>vyH!l|L +)hn5+GY8u`@^vDodWyT+e;{3UKbk8AvCagG1e?EhczTv?{+|J@RxtNUH+Q%?ePbw7`5{MAXofA#l!^y +Al-e(pARziTF0(Outut@PH>-OvU1K-4`2i{f)Eo+p6!r|KZ2#pML)3*WYT+)}A|m;o_ysoasC~y}X-&cE>px&%=%B$v!iEmJA$<6Vh>@di937c7GdU$SZB} +~5op)u<&dScYJ2%f}pEEaq-aWTZpK(V*V$=Tj&R?)_(f>64|I_*Zm-%lR6J@rHy~!FKGcGpn=JD|pCQ +h0><(8?_ZoN(NziI#f75v9~j-Ok7=uCDmH~Yg4>}6!vyV;jFu;1UnzM_GBWdr*I4eSp#uy63FZ-1+S9 +m|N&am(rTcXPMWZv<&T(1G&AOrd;I)UO}I9FhDPT`u#~j|umI!hN7}Asw3B@R$_DV-}+_InRa>m-gID +TG*UM+{ddqBh7UZ!5lRo;~vr^Mjm!CX2%mF#(VQz>BOjUA#;V#5wm-l${r{5&SdJ_*MpjDp+)1`1TL$@)`;@%Y-0?H-Oii{$XQgH5&K4e1Ret0jo0Ml +WCEGIQq{e6G*mGR&(oH7E;wa^$S*c^P^JUB_RH7CdO<^W>07-o;{qO{f+JM=J>!m%*o|$>QOZ-?f{OK +@m_H4$Qc?5V_EEaD(Lqn;3Km=oW{4^guyCF1mYP=7rn?})G=@Ziv>7fB?PCh+)3c-AsUa!ZHUC(^9Hm +zAf!F>gb3n&B6`wH$`Qqb1hn{p^FE~bV$G_)YTpoBsP_X&@mT0rqBllXY-tTqN0loU`bM%kpNr|b1T` +8hdrb8@ao|KHu+{f@dJR$y+X7wa@V2_HKZ?vTL)QZiM;RaZ`vGiIk|+ifN#*GaadOrs??H#^suk!6fc +vS%fyr(*0oQ~76PrluHe*~aXg)GT9aermGamNYX{Yayp(!2|zIhh&BGKA(MAMz*Sn+` +z!skymL``6KtOoZ4{jXAP*8SQyMqff8AJ`MObE7eA9%di=fvr|%y*=bq~nce^~2U*wOSn_kILduwuqZ +DuU>?AS~SCIvg*Jl8gLm!y((o<(9kz-~?mSXf3>7?e)&d5p&|*n@7|qsv|eKNxW1jSiIdEeUVh}j*V)@PjeTHNVO7?|ZapwJ8Z}}%`j5Qnw@~5Cn@)WUI+D +EUc^R{FGE);WRXZ|0e^}V`iK&^XNqMQ$Z<-Q4NqB3m%z&Jfne5sgF^Ael&)TH;vo>LVtj$Eju@>ciIh +*^+x!Ud>hzInpKdjmjGT-55*BQK+A*>lQ4ED=u)ybE2N-?lbVJ%sw+@R{~D%u`vT^=CPLO#EABG`qog +IZi)59T|#S*XrW$NUIkU0Yw)Hq5}<4i2bpS>b=ow_Km&lh`a?*UW=8o9GeWs=Y63zuS+sw-HQf&f16R +S^J5B$F%ehb!Y4hy+5e*TM68J1a4ZG(q5#q)2lzC!nAG1+NS6!UmxV_3itQkjBV{*7f$Ev#e9iQ!Z)X +}bRVbY>G?i&;hVScW-Y?nu@<_vtQqz3TDZbs>T;=n?tVlkZViKpVX&J}i)U5;(Y3d8;ekT;<|NO++-kk +s5Ejbj)i^9ZwFB-{Ej+25i;Nm$gf2$=ZdrVC^QhscuzKCzA-1G=i}o>AgcML$|Wg3u?r)5eSB-G{XqY;eW-WEA0cV_lq%WS)4VTO7!ryX*}PtY~wrRk?=OZKFxCiDYb36Lda8y1_wuj~$V +)eSbgJF=YblI60nm3>(in>SCBIRaq|hAWhZcDUlv65J!rBY3koCiM479uQ*+ko*}&>H6|IgL%3I|4C;El@l8m%MIuyPmwG +SN!x2u*^8(ih_>Me|YM(@vBUFqbeMP%t#BWj0{HUJ!ih3s71HF(rSw>Vg)Q+^D>_a#C1YCwP!t +l?ob_6aow@D<*jpCB?iPxx%Oqgxy@X0yU_s4Oz%=HuE@Iu +C|4Fj9AF1EK=my`{xOW2#Ni*7v&P;Enww^qM=T=ffSe7lgwbBn00)zavyX8~aWEFib8-A4Ryt=?Rv-H +tD0>|$YETAKW}??QZgz^|hDF`shp9Ir&rc#lw|X@!4~o@AI_;&%}7J7{p*oc5u9tZP^b>#Dnr)$c(hE +&DyLE`P5-O#R2hb@JDKm>=sEcDH9QU7BZO=@~m-J-y$aVyw^8Zs~Q?v(}RhtTole*14huPDDDPT3y{u +_0&f7G^GXAHGkAs+4tpAIf^<gbym{+0@3_Lqck7$(%N=Pb8y}{T8dYd0}Zwp&eSdu-$m1M5My-uEcllZfNv7RdY8nT<-BH7jAH&G{#QkXUy-Rh*MLv? +sIQAevq9rgBL-eEeXYwblmZoyhV;1@62$<~xkOApp^uy1Jl{w*wBZLNvNt*E^WU~QsWKHyueuV{A6tK +38J%<9Uw73CYi3@7|@DBjSnsx56t<=19N%iM+^A7fUc`Q +>uPJox~2q>3>jG0I-M=P{ooeNXtR?}Vk4b|G}y3QN;`|m)=;LA=&5j_KCZ;SZkb{~_HtG*7GS7z`;y# +BzGO{4|JjEu;eYlaOZdNKA97cn`*zsC^_Vdr4ip$w$N)*s{1@&O!iDU_s7z8V{=neV>4#vVm@ +;nixTr1+N2?A=prq9ZY~W*we +h6}%2Fvz&aOj%eT^J|eiRMgT|1ULc#vycc8WbSb!di^Bi469l=LF0MHA+c_XPiCLmN90YEp>AC) +QptWsPv><_K>2;6^=C8yO8!ITZ)zVgE=U@hnnvc6Jd9*Q%Xv%z~)BJ*zBYf#U)B10{nC%Q>K*5 +zGG%Jb(E?SpU9#zv-33DILpMFEwS3noJBXumP>!pQ*k&&>{L^HwD9OsN4tzi{_kS084SwK$g)vRA9+| +)lX6gYq#+5j34?u>BWcT}l9@a&2Qim5kOmXGQ-(>(wb^sP%Bk##mo~#wR{~#pP030Z*{4|YlT&lRZ7K +?6&fWz5O?rEHM(3GRXWD1YO3jTY20{dSdrh=u-jYFCCS^{^nwyc8LQ)I2*zD}P>^WoYS;Cg&9D)>Gbg2r=u|SEv8hROQm=5Y@`%nNr=-k`dm4J0vQj4HW +MoBU+X>GfC|!3xpCG9!Jt+ym)+Edx>uualzx56fhssMa*leBl;YS-j+%#B79 +U#20vEKU~YJ(Y46b%1>=%DH|`X6$8@<}InYdBXOA2qR^lv0a`MDNPZX%}3r+o+PR4JaUI8B!$`F51U3 +hYky@OB-x)OS`16poQ&M;EX+|!X`{x%=&e<|$=R;D$i5KuyOH4RC0U!}Q*#A5S;-PH%K9*@;aQVikDk*0Ri?lCV$Jjv6*r+%{L9mUuHbhE<%6BUJ|KZX0V-9}y^Zt*9Fm`x`@kHADT-#R2BCYcKm4^0uyHWz! +?>@*!_q(C$hxhp1Q2%-U^Ze(z+JicWqfoT^`nJ@%#O6>P4cuk!PA^Se& +P1vIF11C$%~Ww%x@+`B3Fp~`Mj_9$hKS8*mP_ely)Rq5ZV^3GK5vl(_qGO@=4d$MyCuFX{V0)_Kp1(z +uQLgini(!rU+ST27`*`HDPtX28FsN6Rx{EjI9kCcCqkK~2MGk3l>EQhN-e|7jj8voy&{vVD1|LcQ;q} +=Tr)c37_75u;c{NDasj|PvYdbId!ew2K8_9ylIgnA0D{Iu!6^k}+ER0H?W3o_q+3I;3KQ$eGGofHgGF +hD`Qf=t2c^Ac7l_`ZVs72K_0xq@32+^paR1=lP1s)FkjT&v(31)orGwSp@YEKtyoHGIxWcv`_v6x^@i8U;%f{O@ +W*60fg6?)cy4|GT^x(s+EW{R#b5mFsU3=BWHa`&~WXzxD}e@{#_=CZGQ{6#uPH)4Ttqf781M|7Y?3E1 +&=0WuU?He_SNi^jGsU9$sQNvX(TT#3l2VbW{E>d@kWL&r7)Y=?d{lY2?BJ0oPIZ9nYP5&e%lyi!VzUs +o-1J7~Z7dMhbuQ+0)N%zB2rKCqE+{fDKwGV;)m_QMrPb +l|H>z>3ajztF_P7gC%@F>aT%|)bp!K_hi(cgBq?4`-00#UuEOGn>E4mKlV^9f0y1vemZuD;1C+*uJP5 +eFoM0?Fm{pLg9$!J?^ZIeBDk5}NPnGxF9(tiL+-B=0t+eDf3!_A9ci@C>=YAeHS$75BAitwgh)6^KOEZaMm@2Sw`@UE;8;0f< +MtapWJ^XIJB#D4=4CTS4pqGk@!t-5rqjQIIBBj%gCHg(9nbQVloF1>`(7zZwf>3;T|&0)dX+u#h5>(8 +BcH>y`PXf;BCE0w`#6q(+Pe^FC#op5}epa;yjt)+w_K!c`HF&Kr)TY(+J*qz2qVG^Ka}+IySjupTt}J +NFO6}c|UQkk)Q=|Uw;`M_fCZjkna5m&QRt<1Ya72Hi62Epyv>(CuH^~I5muPQshgpG)$(mjNk=&^6C%s{02F$)e@~w +nmRyf5c_Z)&7!X@7TKcd%0?k5TU7A|oJ9!@-uz*$BQEp=5yIzanIqPYA9YNn;}lvx;EQD48bU$W +bypVD^oqS0i77Ki#NgmEaAdmHZGK6G^lXPs{{wkCf?8C%7t7rU`gRnE^da(!7G;aeAjyTsDTv$V{?C= +0t+enH4_?o>%6J1Ru7@xT^^+97{4r;R^`vzlr34%z$6tB+JN2&>l_YOXhrn?PFB^BG_RZnaRBq!C|p7 +op6H1ag6;+<`ROZZkF}p6M}pS$#yfs^A^TBPNi}sb0>mhrb^t*SVf&G!yh8}6m^A@Da;yzIFTFf;RM@ +FCq0+kg9xsiF5OoVte7rw13WZ?lSa0}k^@e(sh0OeDDJU +Kw{Y!T$4!51@+0nat?~Yw2A>VE|_@p?XK|IRtMmqA@&~;|b;$NgM!QSLS1I +FQ)M+g#j%18_`QqOxJ6P~8@$(%^=&8JnHK(NgknQvQyZJuQ;lfv{P_{?+E#*+C}fL9Wq8tgPze +Tb~X28)KiN9oyB>2uo*%u!pIB1i^A&j8UW+?-Dz%4YkBr{;v+r%p}=Ma4QZN+DT_IF5cA@>yoKclyT% +oPNWY^S!E%*P0hESG&8;Mg6~-Ab_aZsIeU+Y)@4-XQ1z1bz2XS&-SE;8J?y$-E43Kk1=l229zn`VoTv +q&J7$%L$G@NHii0!N1eH4DJMT-X(g-TtM)qL&RG$ClU-iOf-@?h~Ol8H;{QU!8wN|jrc|Z-x@qY?FQf +v$_$8o`fG_UKM;CYk{-E3eu@4hwz@EwsI9i#p&oV)oujP^7OnZv;pyEtyzbDZm<0iCj)`3+E&BQmQhz(}rz^YC +@2*D}cX~Al8*A5H1sEK?JdO6sl{Oj!t}`Wo^V=%(*qUe)vImPzU%7jL32od)YsX|7g9UmU1tw2lKQ1)KlT#Y1M2MgZ&P@$I(x-7o%ps| +vs<_8*llk4QJFI%y^#V-_b=$LdecMU7hhyswrpYL<>l< +7k3M3TFJESAC{`c>lLZ%QF@JXdp#pzq*f)3XQDHsGf4o@We{t^I`STIrM}FwyQGVzwdG8~;o-997T(Z +xd3%m2^p+kp+T?~u#^zTQ0F-`c-onNj0jw18D%0Bm~z83M*(k@E-B7{G5G%fAuK4rfs{WHn^BJ7m@Me +@f(VHU~sr9Jbk2!H6%(Y?~)tVsWJJ3)$R49S69GfL({~oQ{mj>jc(#yL@zI3I(j|n^`X~5Z&waE4^XoHdvYEY7RK +V@;@G4~lh{4?+*41+SFBjUUViyywqe5tA>$u@_#r!U=8Q|ubFe&2eSXgRO+F}zdvosP8`HM4McaSeo_ +1F@TSP^aww?1u+p7{t67E{`!*2;2$*}0DGq-boA#K5dGgGEa*`5{~_6os-yJGGh&-q&kd|_#y?YB=!V +2k*3+uxdk^tLQV`inUK{_NTHOh_^5eG9vGOe{J&TJUbdgbD1HTW(>u-g+yWF=GZ>m@<~lnl+2vdFP#M_Uzd#H#b+b9}5;NV9(e`vsdm +J#ok;P!3t+t*s{B#*s5$3dptLiy|Z`(`+Gq&du;JcwrO<^+k5{wcI>&kSnxK^`t9Uw&|c0)@8)diLC! +`V;cWV0&Z6GuY}_f%CVb9W9=%h({EJ^JXQ?1?9yU~AT_Vb +4GRyeQxG>({fl-g-;4Wm~syW$*1;&zAhe*<00|?b)-39XN1+9X@=R9Y21Yz5o9E?9{1K?9)#_Wj~%d$ +=>^!voF5*LdZpBWhMLd$8XtJ=Qyjbu4ZS?o)xl!$73M%5AjTVC#YXRI@EfpGqj`%Y~-!kC_aeY&L^;W +{BE|IuVioW*V+60xYnMswiLfR#Sf+UqbPnX#lMx}&!YJGycJtY@t>ghuTlJRihqLQpLUDio8m`O{M#t +Ljp8q-_%BiXofQ8##Xm{$Kco0xQT$4Z|0Bh(af?5&H|cjYmd&9t-U=GKtY6O9(U+)C+eMY|L@UNm4r2 +V%35=h?lcoHH&7v)oqLq% +3*xMeT?7z1mi2;VEpy{j358pExwWB52N_86n`eg&!_myDgIiD|0c!XM)CJie9Cj>Clvn-#jke7??)+& +qZBeIg}+e>&r=G!DTOa6h3ZzE{XB@XUng)@b2n#aS8{glbpHTcNxA=O+fk2Aik>Yow_`NB9KZ<`N#h*s;@22?6DE=rLL +kgrZFb7Fvs={?$xt<_ueUq;mJ+u_e(d12k(PS{26GE;>fSYbID* +u?cC`-&}O5PG>8a>98&<_E6_3GYD`A5e^nqo{*<|v8}yax0O3Ar($4#}9f80{I`F{oX_fB`avp540{d +)$QhlzvQ1^yrv`&TZNUkv|0pRsnh^Q2fy*M2?C{=-8%Bd+9H5?AhH&NJhKTPY7(=rp>rfB0z`;(9MYW +QD*p>;NP}Q=WzT9iHWn +sb*&eG{QLA3>5qvs$5`Ubabvr52vh;!e|>QOSSHht5?N?mOBjg&ihm;gK@oAp;y6o8oFGEvpz)vZPcR +RP1PU>fMu)Lu+q7vz0bKqG!T4zy4PH3nZi9^h59+2rz17(Otdc{81^m6b3Aig7WcNs#LNO*ae;9n#!W- +#VH+qsEXdhlNE&)%hnRj4_RmXzAlUjEqqUNIlwImw!SOf{c%7;o%br|ESRg^KWD&85XuWH;QdoVqxnaTgY +zMPdWv)bJmYIyX8x%GvpI|_~D1yRWoQ~bYC{3j{?8x;Ql#joq<{-dY-M^E{`s;6k@I(O*MK`e#07Y9Fg2m?sKeNRO_+rao7X{5Osar2x6@M~)n*XbMv4U<*C?@JINEvPQ?;x_9s1JqUtVEw3?d(CxS1K6)5EWbX +LUM<3l!<7mEp`*!}#H{WpTPx*%*euxPw{`u#ha~gkh_!AAB`q@vNPG=?2`o)P8C!X4|W5=Q~W5x_&vY +hbAKszS4^aB@^tFL-t);?jtrvjZ3cJ}PqLuzYl&oeZG*N%UC;`dRigJDSHh8u3^4g3f%f&amS2lf9uA3b`M|Lb4>5_nS +i2;5<=sHor{fBdnqgC^}Ioku{DxnF8Dzfy9<=2^Zfbq{O6y4{^f%YKG^crS6_Wjd7VQzqVqwjZ$k +-(<%s)7@h5!>dAVNTuf3o_dr>CZ3;Z=YG_&?Lq(yrPXV*(*?t0zb@%|b7ckSA>jLNY)$wU!o*tv73z# +sB)>eMMw248&fg|Guh)CsD?0>1a&d*VgiKzRV7+)#HA=iPVT75JkJss3}6!{y7`E+hGn{Q|jPgg@2c! +G8q*nwlC;-H?#~@bK{7kYl{S|M20%{GE5+;Z)|FbY@Y9!GDy;fddD`3*7hb-!JOQ$&)9A88n~`fV`oe +pp1aq#veFOJ;nLxBb%^KA@cQi3d4<`3&d3)zrL4b*0nqV(y0jwr$&1_UzenDCzLasl7y +b2pWJdcn-dT9+U-ehZ$x6*=L`L7iRDr{06>|1JDAz!GDzTv)^%U{*d#?6P!mJ<@|<2oDbPgH0#}n(#k+_AF$1*^nVax|1vvfd(pvD`){OkR#yO7#-j{c#blH+(7=(?$Ve|AT*xvANR4OV +a)rS-$=NQAR2~}+~k~;_-DMwdC#qC|J^m>Pkjd0+JDGD^+z0U!!pt29DGGtK&~Jg8Xc(PkTb|V>V*bT +FYrwIg7ce+h8U9nu^&kqMjhjP_+d#yDAk32J2?;D{>SmBws>W)UcH7=IV?v#L)+3A9gy{=MLNu)Zo?pxJ6TOc$h5xy8=Q#B<^oG9tRr!rRp=u%t)<1ACUDKZBp-TvOf3UD(f`0xQ$(wD)6UrUKSP>)}7k(BH +#}>X-Eg;9&+7~4viMbI^^i{LmT*ub4T*$?4$Toc{d6g@XV;>{8mLn{O6p<5>D2Cxz%UTpz8Agv`N&a_ +M$ea8`02pvus=GS=<=@-Me>p$v^e+=;yB}57b}u2U=O6KESTg0Q{-lT}@K@%Id64bKw|&)6jXc|UTVSVc5AIiGq))@QUyF(22}XV9S4XV9S4XS7Md?}%j1HpC +zG4E+n~S*{l}Xm3M08ml83EqFF98qVLCKZ3t@PXvD{pJ%hPoiNn(Xe3w(Li+p^%*ogt7v#s(Xa +wE+&PB-EuCmcGxLQh7C{3Zv`Hh}bc~^U8kc{x8R)~HN8nwzZXJK+l~*|QBJFiAldIK}OP4P3V^1aV9f +ddWt&52Usta!t4gXN}8Ew)t_8a+=xi|9FIivZitVn);rinX_wiR>eO1tNEp%wKAg=THn|x={4ZNIac!y{Z^_gfuo21p}HPj|Okvp0{k`u`vBpQ|z4NHlJ +Vv?i9sb+yF+9Z>kj`3zyJfh+1G>cGN<3k41C^7V +UV0*E@*aE#U1^U?0tTsj8obD65o4W6s&KfoVlZ?#%c4*aE;UJ|+&beYo9Qa)$S92X5&qvL92f(LEVhK +1KqpNWP>+L@-F_TbZs6)Sd7+sXU%>BAEe68Q7aKhM!G=jG*bo6W|TEn6n)^{1bHD%u_BLXFV^ywNwHt +%5EDeH7yXJgCn{U$FCw=V`q0+#FYZ)^va8$-@0|Hfpne88vgzJ_aBy)mX?*0l2S$Os3?bL +pM92(A3vT?nly=*m6h>_AAXpxTD3~xgYiA^1r6v6&`)S|UX@37ZeomTW +-09_vq1sUw{4eoOEk}3-CbQaDPFA_BNyiFJwwf8*S_1Cuj1l#gWuMOC1CK^D7IY_@)PE@sHo#$ZLN4? +L8{*Yo32ty?Qk-Dk}PA<;s@SVn$LY6=S>ILWoZlI$fEtrEqKMc7?AC0<#`3Q_7 +;RYQEWd~Xsd5HXTpMghzbp8jCsqU`H$;tWr-h1!83_Pb!ohn|`X^n=yef#pcbLWb3K%b$_?PzoWU*NC +J`C@DUi28s!g8I;~zN61}AA4Z@%>Ll~8|oJ1pJeHo#fulek9ryt6T|1vpD)S*GywlGW5)1l)20b`lmT +eaUeKV8dodP+ehs+?o`8@c(B>{%(5Vof+L8x)_Ut)q!-fs_V+`?U@P};Tg)Cvd8E(J}bIx|VUDV&Gs3 +;y88Oa9>7$C|4{)p3%j>cq5s~Z}G9HBjcT%kQi*=h3|gcFwAu66xF;7@cf8#ZiMcj93Y>hnMU`ACCo_)yt$(k-y7Skwn9Z%*c&x?I<`dD5f~RQz-+1E<{@QD=i9YZ +j|M-W92VN7OoYc0>pgwXw;l7jH{>J3G$F;8C2>lKE588jKkIP|4eFFq8C~wqRl2f5e%$_}4w5?RvMgN +Aj2J)@RA?g9@CCUVHf-*px?5+>NjC4^(C=c}KL@&NrM!V^Kjkvq;cb8Rn8FrU#;0C%NL#PXX``h0*wO +OK{c7K4I_97128MH-sAU_xr;RWuX>*=ST#vJ1s4-bz&in|McP5&o;7l8(?U2KdF@EdIq_1$8e0GUEx+ +sK^0z#nC!=@3}gf!sruz;o20)!5Ac$N63le|Pyu8_}?jZAc3s=GdoCpUxk7^*Q{A1;)5=P2W`L?vW2!2v}m}Ke)__nl=my}2QE~;e~7g?%lgrw7 +cK|>MP_O_@f?>Jg)rC#9iuUYS +l1w$|7zR?{*c|P$$3-q?%o!`Uz@i8pFtyJo#f~;=?G3LEA*=!{$kwm;P}Mr{>?A)z`lpS +xpOZvAAWiC+_@EujjooEOn))-R8XfN`-`BiLHcg_7ARQ$SKz-$K`xe(7r~|D +3-Hws{i3j_8eAMgBuA(bqzK`Am^wu;OFT#!$m4@?yO+Cmfh;-jj>hoh#Q&T7WzxK{GHj3+t<3kb(s#M +iqD)~byulxxK5tdS^DD_hz!B#6|fpAR;4U4nbYy4iYY>JJG+hQI9rzI`OJnWsodS`a2p$RyT@AT1nK~`@1vO9&a!PRHWM5SDZ`_6cm!%CiCCza!p03xL==!-E^Z!R +4x24VPmv-|tItDWZZv^K8U!f*WE%x0pA^L9J6V{uCo!-8Edtm?m{e|#A>_q;6f5fiii?G$ivcxHT$9v +kEp-H?Dj0e1vnl|_jHF+?$ndp-P$Q-m%<_l#yzbDUyE^#z6(K!!sledAFefu8{-Un9p^5~sP7gO5JBz +;iyy=xzm*E}E-{MX3euZn0(p{irD8Wf)lR(jk>f~)5nj?e7~}>v9ZjH +ck6hTS7PfEO;4#>BK2JAh+g_&ui(euO47$17o!2|17kuT=l{a751Kylj~6RV#^2$E*6rdGW}Q=y9lJR +!zW3o&9?-|aBz??wG1JAaJ|^LGioVQ~0tXKsEcEgLZS)JtJl~{IL+Vl9$ZiJ6I +cY0=&~ppSYr-p`miywryoz>=hoUn;;7s^>whOgp2oqGf@vkAHkTwHd0 +AH>@~E>JiD_33W6zW$PDPJlD*c5$+8E)O)NkCN`Q@_6sxQ|G_V&zOhA{9c^Ji`^lonJ}aNH-Dxu7O=Y +SOCFkBtkKgxWB;JPd-v|Zkt0V6!G?&(;X~)udfgy=APejf-_gKtPi&c-6L-=_kFMR({u5(w-MY1M$Br +Ep$YI~Ueah}(ckzALe{=zPpo`Gtsf6Ij{Z=;KqUb5PSo#^hIWE>6_ald&*8Hj +KruUMLWw*Ds5kf4efNkDDg-vAtD(w@ZOK(@0kl3w8lDlSUaS@$Tz^l9Y2u%(tgOX3IXMm7M^jT%)%x}8-}3wYV&le*st&w&?_O2A +(76vX=N0+uwT;Ll*(cNJQ=WH8>egN3zXb~xtdjFy<$?Hma2c>A8E1(#Yu2dyp03uMJT}^o>$R1J+JS6 +_2mGb{p)KQ&VX#E%#`*dAs{RTOH8nL#?$`s3k!T&zHDs+1(ocL^US3`zbvZ0!Bp&Q0=btI3N<&ss_HC +u5rN0K_p+>)I)hfYQfUilvJb@P=cddtdjfj4gzUpHs&+p2`Oe#Bd(jn5m`d8b5sy+aYgix#%FZbZ +`ykhZjd+46qAa2QSD1yN%6+&vWO_?KAETqfqmI&z?Pj&d$z4opUqJ@K91xBIeJZFP1M~u6WaRKaCG@9 +(tqg1?v(|ojTQNIJv^TG-dy=KP@dSW%Nf)9-oiR0b5wRcCEsgnHQW(Lk7CWOS}xGLfkIz;n021o}iyx +!}8W7@JF?^waPZIR#n#(882kbePfgR`}>dICv8O^I?~oC`+p}sbPRm*Pw+7tJGFEvo?47QJP?(XhJ|3;)Nb{bCo52`oHgayTaKBY+4VlVJ8_-i9Lf8y+{bgfzG?ZC{xEI2@1#CHb@b@bmm`tLzod=2aqQT!A0 +0n_e2U$P$Ky9;A61rRssGD!9y3idzoVn$Y$B0R|;>s-x%|d+!%d5A +#;$Ge{|MCWy|=w{hI3PjJ}?8(P?5h9na`Fg)MvTeJ5ukKD{Kvny72+L3kF7<9Qe$w +&$!`__RAG)!od==x|mN{7an9~Q +jIJpgzvzTE$z$d&GLgn#8 +)~8}UOsRUhOWd6EytZ}sZc3g^a#A&0?>o#J$JrphOY-HF@D8_1m+gUb|+m46YUOUk9ay +@;Kf=Qktb)b?d+{paEOZ-}>Fi*o%d`uekH&#G8WugAe|6LT>h*i$bryvLV&^`Gp7p;Ywa<^?{};dJFU%j&-AH%);{N+=~KI`%`q|p;c&2GeR+ +egzM{M`oSDA4w(`kvacQt35MEFbDz2>xS8dp|pt!2y$w0W`iMmDUzKTF)XhSfpe_=2)ebE#C^sFy@-s +j8MRJ%E>ev9xPdt2;WC$9_#i#OMXHZ{1P<$r2}HJc@s;PVBwp}J6cup}6s_|p6J)AjOFe)#a4!Mb3%u +bjV`>49*5WnI%+&1EK< +0?py@9XS~3`jYRM+|eWnPR4zK69SwHW}b=kO3iAs +-fT8o%{Fto=;dL1*#7_Rzfem91QY-O00;m!mS#y`)S#&iB>(`+m;eAA0001RX>c!Jc4cm4Z*nhWX>)X +JX<{#TXk}$=E^vA6J^gpvHj=;VuVCxVBNa=`M{~V>e(UZziPQQvvHfhP-Cf6JC<(F|OC%pjSy6WPf4} +(vK!5}#*=_gs-Ys7nOB65|41mFWVX)&39}m58Hc8U!J#SG>hrh=+y`A2U_bSU*MRI*pdBLl`_x$OzZ- +(&Cx89FQ8n3+b_*0UHQ0#3o7HKIaUX^*(jqpxa)lHUq=h?Jc#)a_SWQ%kXR|&j>52Em5XfLgbWVEO<_ +;y_gF&Altu+D|>-X6U=JU%}RtIw4erxWkh$??V6(aZN2CuisQ63X?aMK<@MXu7Btg@__Andezi0sI8I +BBEJRi6Wkry`KDG6qn-L7wQ|98JFrC;3leMF7)@LtQJ)=D?|L3n-cRlnW +1zQC +e2w}Af=*`jF!{dW@hq4CJK$Q*4iMT%Y0$jH{{$VDtu_pRe+j9{41kW`2KSD-xD*a4Yk627FSc~K?n +l}on0o?P2hiu?_zh|Pb)`VZy$ac&l2BNBcawx;reY1zx94RJd4iXzu{MU8iq6^^f9`Ni@-O!mS&Tz^7 +}}DG^@NCz#b7RFXHQYya&I*G=VzQu+@tHsC-oV-XrRTNwCYk=U2Vczd&Ik)XMjEjha2co_{jBVHM~do +W1%1ez$oF^+gdY=!b=XFJlq-Lmx&h@{Kp4d;^eP9<8Ov`3aO@B4APEobcBg#&J%pd8mexL1HQ0o-Q(= +(dZjPH4#%Uf;E-gi6|Z=fdqn2j%@&_ORO_62ymr~@D%C5{d5(*K79H9d*6Vm;f8UZi*yqB6F_Gxa6cV +g{1Bb~<=w&Cwfrp)`#XMzIq>r2{17HCAq`*8k4}z%J +><7(`TU2&mj}n+w;CN4{)h7M&R3T|e<(hrSC3(!RMFS4^&Gu*)%ZD}I>FbMKYx9-`}N;HobUGgAIjYz +eBA$?0pav77eAaFL-mor^A)cqzwzTw)~`#SSa(*2rO1hOK9P*G$|8~paDRyBqe<*#dtPQNNp}Igni=E +(0RlC8<5^sm-a8P-U^@)5(I+vk`o`J@j+azX6qI5%H5Lti4PkFXNelKHXdRmS+du5zL7tGWHN1E-Ay5 +MkH)Y(+1|EnFAS(iQE!Q@1scKvS%(_my$#9XQ_!by&YXk~02X^1U!DzRxgp9R?M3`rJpsVRxz_Y#Efp +_O6sR6-e1TdVp_`Ak)uO)Th`qn>R-d@#cPm^>K&9lj3rf{DwW;3QAqO*@;fYA+TOchwuW+BSOtdbqAN +uZ}vs~on{|<2^WmbQNI5AYx?_&3IJ(Gi)1z-u_R%oz$59Is-hAhN-s +D)JoR2Y|IdD?LC^WCRH_My&`G0)t*Yne2X{4$MBp$6G7@6cc-G2jWB76qm$# +livjJd0NfzJ_uNiZhDFh?e4%O2r8uEsZks@z&O^Y%(XEdT(`!|Ni0%_bScn)CauVrDl +_W|$HC%a=I?&sa)^2*^BPU +C})Ogz9wiPnNa?>6k94|x2T{~7ZGOX=6#ta{3^G#Dn;2)*5PCY^n*t_qn-SPMen?3JQLEFMQ>?ASV__ +fy-5h)&(_&1Qhbd07sM9$G641U#_+c^V&@qANUi_3wIeHH4xtpi==WfE|*O$BCfTq7>*8dT-Kl<~)q! +__Dg%{fE$AL^;NRs%iL2MYK +=6US*5bU#F+0n%pRaaTJgkoXMTr)*9iT;9flugRu)r^R$z{Zkc_5{r<6(uqM8U$@#vnU)7%$;tH1o-< +eo2VWI|&uunFg>VAsQt-vi?N*6^b<(7qM7v>q)z~Wov5SHYwz)kO$*3x)K24A2)G%k8A?E<+hyXTM3( +=l8B#SE4Rv>lZWq~#zEX$q-6q^dNM}w|`E*4|f(vpxC_Mldj{lf3#I{7lS3Cg0dHl54GfyOHPm*C6PW +`)Z;C~TLx^hx+0N|Ut76k9q464H>st3?jzUM6W3Bz>9)G*^~)S1p;!s`&>gyE`TmNq@@nZ|}-(S%Ye{ +T?J;5s#vw_sqUMbsCK>ZOj4r_a!lIZQE14%OhcHiY0!d3!#0|_*THg%qrlT67){%-@zGkP@`#WS1lra +9vQa~jT;u&otVomXQg(lgXA2>9T_yj}Q~>@b#_y4V+UMgK +Dv<-La8|LKRr!?(?4dcQHJvF>C5tc@{>8u?cS&fH=VZzL21bhg`c;|eJ(-qed)maTIwlfyY7 +D)N${R6?(`z}4u(r`DR3U1kuhbx@j45O_GzLM&gL#NXdwWP^Tii?(Pb*QV_R*(U5OF1g64L0r1xwuk +qNQH9tmcyB63#aIHPECabGU~xtyEUZpno}hcC`h@y1MTgIh=BKmv*U!RaR}JvdXSwwAV=2<3dh_5N(I +S$p26@l#to9St9jYlmRe*@SdVV3ZK4%I_<6kK6C0S)Zc~bmw-_6~v-S_P@fquVP#gUmrtsPz=rl)}_Cn%D`h_mm5*n}w?M;9TdDmr}hk-~vo^ +ne*s5sm~I5y@k(}WQvK#;w7cAXW#YUj$_;Al_tR>qRK9Wd}~QC5MY7)Qc{i(*#BQxT26eIZiZqyjF{4 ++{*`$YGl9`v8aHJpw;2$4S!GwKP717QbF%&_z^0{X)5c_)Doi$XE?T$QVLd2t8Urpg?}@11p`!w}N7a +@)b#(B~U6c)@F`!sdR`1YELV~jO;1xCi~4MmE$%*j~ObLzM~8_8ZLixJBY4(2Br$uvYUsHF9p)UtT%| +1(zs>$k~9lkm_du=QqLeE+udTr!t6b&Pbb7nUsR@I1YoY8c*I+6E{=|m=w=nJg*rnk0h8g+?(OIS5B0 +4@CM(J6=pZ{8kU9KLo6h1*UMd^k)BxY1~F9r!;LSw$L4m66_(vNGcn@#4I#RDF@e4&?84*NtvtY*&0; +O8=1Mc4}@l4l5v6V7nhXv`}oz#W%I8;F9h~Z24vET2TE<^M^N{IV)p@zSDa2dlFl}pDX2DZq>wFPoEy9Wid +$GTSP8dU*MaXw4a;I{n!}9>@WQN7n>FPe;a!0y!X*!|f%yZ~capOW^&P%CHTSL5d^gwQolgI@Iz06L;5Ivm2@jH9*RPn3=C>eEsIwRZ9*k@-{W>#L#h+bF?7HNXt-s7R?FKe72T-n$J2}sG}_NmWB +zXEf%duak)K;YQyCwjP-Y%EnBOvx$*{HR^52ZP~v`YR=%A&90fp28A7~zpE{(3G_jvFO#-gSUn?{;J0m)Pgx3iOhd}oHLeI!jH|3zfg%pV +6{yk!TAWingyQ!sU>mvI4!Ug7VCQ9v%1g!P$}1O1MUi4Nfx`;>^;l0ImkCDG9XMf4T_7)1#LWZ#0)aa +y?A#sjX(=0;+qQ}pYt>@KZQJ$S{IM{V2PP4$XgwC8cTkovCFv~CNO)72>7Z7IB1Cji!o+PHmb^%_#q~ +|Sewl>(Mk%d7*-B;ScpCVcmnR?j%+wzid;=B~L}QN +yR@`@6It+1|W8@6jZDG$BdMj-Nx*3F)8a+rI4p_rDh@AFbJ=!3D-D10l_mM0S-kn1jQka(K#0!k(-kM +eDlol{KJEpRjf&qj0*;_o?ITFXC%#YgkL3Ef0N7@^xyu)8|v~e$LHLZFFdqWq>x8{rjr%5{Y|h@%YHC +HLhTHK?#=^Kxq7aN&+#E7xq?AKk0u0&61`!#MN_y>L%((WNs^ADALjhWo#KP${=XlkNRDfs3x{3z^v- +vP~1Jg!1hNc*z}0~5=T`XBSQv`F4IQSuBpn^mI4{GYTF8sM9{~_k8hXgRp^Wx<#1PJACSi+8-{_hoxI~|TrF#J9y#xECQOoXTq*kkBd +3`J8XAC6m+BNJ$|ky)2BnX_k)TEcHy{%P&9MaId|-Nv3z5g^c%_QTT1FVu1-3N?ac_hHwY+~Mu$8cx1 +jzwtlEH_K=lE7A%eeu^pdrk_2n8^rqIUsW{eT2A!ay1_o=5|Q+<%~-hSDidE)I0prOpSFjYWTUN6^o; +0HWEm2@JO-Ts4(Q!=BM;p(flNdgz&6dlXW=_tAND@}m)VoC3=A^!WHOlf-a!oNQz`H^z84vvM^2@gs` +JA3xewrCO9OR#CA)Ns=agD8JXdl4dOY%u9i-3jEUGs0y`4IrSR$We&jZ{W`1vU&=0_g9bLm9<)MQj2+ +3^TQ)*!?P$_Jv9X>uSl2CY5z@5LKHL@4WX4uFy2#NLONZKNhto8pW0>mOMO6^AySmsvCpIdus(!Wa63 +mFd@JezJfZhk~Y6AF4%xtc_XCsBK!P&N{{tZq(r| +Yhz2wsKo#*2-*RgieS +majWBo$_yJqd7{W>vr#<0rPBiPoV*ERG=_?}J>#LX3FzAqOShv{MH(Q(dz~%tfLJQ7L0-BOAgsO3?!; +{Ml?^NdPAC=G%PXpgQ;C@=?f>YmZqS50*+g}s9+Y^ZB2lEh&h&BPv&@QHUP&tXLpZ;k;OB-d5a=K(uY +!G6pt;0lciKTZNvl5|*o#U&;jI5NVVMOT+{>eCn?pm4`fv%5yl!L*&?c2lAoMqyW?v* +py=?7W>B&D?2w#^XU$?vmO`rr=$`r&4i->~=chXWo^6saN4yEu7%z%Kq!mbT{C$$4D9&0V@!Q6#HmIl +ZH;jx=q?Y<=*>azlPp2IWALP{gn#<}|+zgqlxXa7uS8Qvoil83)h+O)(3v-cfe7XX7D5_wdloSL<)A3 +%Xi}3MTNY&lwG}a=H&(`3`Q8_H$@5|CkhS_h+Fy>?JvB)xv@8uP?lr~@Rgl{ +DCqP(u4nQfWQjOs?~mmZ3)iiNdTT)2w?l&(n3~@Px8&NXu!b1Q;%AYeo_d{(j7;`whIOO%V5TIcL=>( +f)&YXibf9{%am=;Jbz=oBCW1T!0w)?-B!^K^J8S{6&6^z*QT7%(TDXDLYw{3nB%X##c@u^3*_w5$2UZ +j)0>6NZn;q7GzS@^G+l(ngW`>1<5a@n|1pidENZgIe6=aEz$qO!AM{-AtJ +Q((PNb6EY(!5z%_RaL*H@Ck(R!pdV~L9j1z&XF9!X@#FQ}7$4NgTn1OE +skxoZy7I5gq!lt90s%e~G +J?nB9FCT5jZ9YeBoQ@Kk_WFG*^iKt+A=#OaDcB$a_bkD~fPkNAr@|L)V5VX^RJb-AU$XD1{h{-Yy6HX +~a?NTzmDmEN+31PSftn88ja{J_1BVQKr2`>=gb*RogcEExSJN9PcIv%gs=8hiC470q*WlyYRVsa+8fT +j`ZARs;s^D!r)qC^D^6LgmZWdqpv{Ac0QjuSrIz4x$b%HCOV{>=x|k*zT?iWD}QD2KOIiHTV|CJ;Uwc +O;8*h`ih6-^NjjE@p~Ow=ckajDcy`nVXLl{t3*q%w_`Zqt}aM(>{#PEqjL|9WM9?p=~1-Q3f&Y-geTE +>eHo_K$8-0aIQN2D$cn5QMUg5HLgo@Ott~Q<&lEOE* +I>6`!tJaNKT^&I$yz8_8k=~4F6-+sqz%1r$k%lrHgC8x!DeG5LeRqJTkS*IUgbG4+%A0?FVZ}AVU_ea`MC +@lEpI@9n?#uViv~52k(5sVzItFamW|>W-_M|5;towWA~?^uvU;0Rpayz)DZVxH;=3%Fa7-y|=&AQS{Jck|1sTY&^Zen|m8Qw@LzLB`3GE7Pp~E&KXV*+FVucI?Te5c34Pi=ut%kcO*Ve$?!>%n +*r>48=OP|gGRm!6Ra~o{6GhNih}Ru)uP_xcw+|nqIo*S_ZFO~VQm8**Y%P8OsPjC~WjE+Me17l?` +41^onWE!*Qv$iUyHE)pQ(O;z-2#Q0x(3wm>dvkkPg!?8)uD5;oa)@b+cbCak$KwHsUM!oG+g&g1c+i{ +a}#N%>`BUq?|@21v$a`oU(3`KWS3XRS`toh%eCd96Fg_INXcLhJ07excg_llkE4AHxjE*Yj~|E|pBe> +885pw$=D;dY`s3+fg7Z`42 +2oHh9at#KdUqUBCn?SgSpBKrWzL=SU1ckw~^sRc3Ty)KKiUR%HAYSI9W{%$c>jEo;!&J#VL^2QqXXf|dp +lgqlXracB+XcJh(cq?#v20Uc+B^Gk@^=R@P7yk+>%fHWk{rlY4KjGZhj(2hL`a~a{rTL$*J?#JWQKhs4F^UZcv$2?;eK018bADi$bAln{H6y(oQFb4eB~<(Su>nx6ZEDQtkvT-ER +#=eNGkE3fRKib6PuEXXNJOyr!mP#pNzd_yb5W}s>bADJq^stA|Vq6aQY-p;4ntA#6_LJe2=u|Td}fpC +di~3L*_uzwL>?)L1~U5;=CiHGMgjZ7qZQaYT;2Puxka0a&A`OB~PRlvz5MpPdoo4q +S9uDbql9|`hIwH{N{wRHpymOAlHJE9Z?0^`77;y>nl#M!aiAjm15SAg*jb`%5H!qZNl@2YuZ~S8)R3L +W7~tpcT}=*t9#JWA2pf0eT68e{C8f+<*G&7i|)R~Sg;m7ggS+HK0Wbfc6kV6>u@y5{Dfs=0E|o@XeaqQb) +}%LFqu3YlY7-aJr?=Pdxz$`V-u(LL!Pv21`M4I^m2ghkUNe8+0v@eU>v46c^juYDsZ^bT!Ico8=DyW< +ReL+*2Sx80i^?=`3_6JcnYnugwW=4uQr3sUQGN1mx?I-#@ClFmkwo|2OE@cEa0pYA2SclaPa99Of?D| +*NT7(NUX8XVRxZCKOeSyqZ*>M*!;^I&Iqk0Re1?%&1#jsaL)XLnX?Oha@6tOvnP`6?@Q$_wggUL`==q +gpE}cBoygD=D_-h-(%ZS8JzKZIyInVzn4`XNpq`K%E*@(rRP1tyh5z{lp`^HA*F$}- +j!1~;8e2JOlo9NV>$G$Is`RGoA{s16DjO*(NirTsIa#C<|ItvfzcE^H9}zWM#PbmLAwcKJ3WAWg?<+&qZe2@U>y{{6Snw=cGY`^`GQ +01yD(7bF(kjO_Lx(PTTj2T1tDRcexON498dktVo~<7Ruy8}x|r_tee +dhWkPL!fj7h(2#y;mpiP7f}QUcNnyE)Kpw=M$y2P=d0`togdf5{w;$DZLQ-emO}LodHW*OJqTcLoqMi +Bh_S|-*cfp4^~WfZg@%Mqr1+s%jlhy{2r=7_XTnCa=1pP^&q#eX|Qi-NGOy`-^M3zGNXmgYnxx=7q$A +0xA4t1psslL`c@b_j`@E8P)h>@6aWAK2mm&gW=SLOXZ*te000sJ001cf003}la4%nWWo~3|axY|Qb98 +KJVlQ7}VPk7>Z*p`mUtei%X>?y-E^v7zkHJm@F$_fS`HE4_5CpyP2R$J12Pm6(yN0Y&#SYc}Jubb?j6 +9>~7~@B;vyr0oD^tZf`i{@Twk|k9ElbU#qVY2FVA3b7eSpPiNN$))=+cf9!dWW+a-E)*mQ{Vz%UGur< +1X$7d3k!qg8G)emRx?WeOTIAO9IZmDwS%OnlA)aSVwNRd?W +Om6nf@}gG#1N7yaiYac~8Wy_KJIwl^N+HG={s2%*0|XQR000O8HkM{duZk~a&H(@b%L4!aB>(^baA|N +aUv_0~WN&gWWNCABY-wUIUt(cnYjAIJbT4gbb7L-Wd3{sCZrd;nz3VH81cjX~F}9wD0y(Tf1_T(=p-E +4}AjmSEXj3FZqPO_(C)rW!rr2~5P4YcGKFL#9yjy^@l`@ArXsKR&iWxR#Q&`!ibLwy;$X7GC{qXS?_D +6(o9UZNKovrDQa0p*)Ybrs?nj(O9i12l@T5osjg3biORIqy3?jJYzPy2_*T}*~PHknNBh5Xf6M;>bHK +$%MYR#huBNG-fa-(&06$jI%BfM86WA_A;Wk?%ZXoC~cvhb4T^q>xACwX-MgZR;dva|lVTMXCF^_GrSu +nEhakk?ZalgcSi0IN`$khKAu;VneX$>ucw%8;}*&Z@crRD5i?eu<_bJ1OggvXgd>&xe9~%-gPm#4Rf3IX88W#oe~#2%q$sb9Ct+k?pFiVgugt +ty9AsHvq_3pxGm%qeOL%2s>dWJ-CdeP1uIlm0sbLOfN9ad=Bc-Y7#c%yD7EkW~9K}Uhcx}Z2DW*e6c< +S@v-^pjQ(K#Nk*o5*3`>q*A&L?|O+c8j?+FqTviP56kr4{`aeAKW2uK)(LQkKG-CuySl2 +n-d#PX=J7X=&8k}G<@TBB+Rfwtz+X;IPfpE?YJaHn?R9IC7c+DAS!e37l!+X>FUTt5+5mxiPR%1 +;5s2XWI<0&kT_C=WGSw0JD>me7CRa)>MstY7YKmo3$sKy4u0xbf2}?Mjm9#2EXdKO}We3mHWD?io!C2 +`jf5evSLuF0%@}vi9I=K>%+4X1Ap>h`Q?nhE`I;lv&H+5Z{NOo_u=LD=G=U!J9}b3uk5}xuW9Vdx~}S +H_3@3Nx(T5QTT%;@a+3Lox5de-J^`-_(^oHRx`XQhu-6XCnu{SY +Z^oJCojuSd0mw|Tk?+1cuV&%LI?JFd29}7+`BAq?AqL3+YG{##DP-lbJDzO}D8U +iWyAGSD=Fp!73|I&~A@{2Jm2TW*SC=Y>3Rw3`iY3-{*TfBZU{zbbB9&Y6e*Bc4(GXRadNO^`$iyz;v* +F0QsHG*1rmJDb~-LRaOez8h}JFaX0IOz$GOE{v1QKmf-;>Z*#C-XdRuUrKv~|3j}V2%*(+5Z?e2-2m` +P6Kf?Z0w+$hon*IZDH_-ENh|~48-IzeflTA~v=4P{Q+PNugxoxk{pMLwz(O$Wqr?11eW1;#}rtsxYQAzrJI?{?)ea>QY@&I$YO{mOXm& +KG>li6mb%a=<}iwXSpx37EMO;%&e~M>V_OPu4HgcR4JxHpeP9`7?Ry8YpnZ0JS8GGo0;?T2#0%TAvLp +EEJ1z#!e+mSg+)Xo5QO}W{UI_?eZ<^Nt{yd4q!|1G0u0m}BA(omd1O3{8S@U=vnfqpnhSk&dB+wuEr= +lyi|#Dhln>jnQ-k)^>?)Xz5?=t#6{spoto;m%8;vIO?7+e%_km$B_2YGh!A#Y)vhSe{&m8g!b_{t4y9heS>ZUS@qh)TuQS2$r?A;|Z6)8TRW!j#d)5&U +mowE$2`W6f{QIo(M8lw+#sMdnVciX8DmpG;PJ5($)tS;`8EY1!H~ZC-M`vC9q^$7DW>lYxPbsI|`<7? +i{od94ygBmP$9qSN}z65Iva3U(|fp-%T4;ZU1B)o1sT-BTAN{qesV^|3i%>U%MN@{NA-jCdtkHn=~aA +7WD^slzZ6MO<0oWE6R?p-trzq=rka;Nh6DAJ+32+uP)`@b`KkTf+H##pvY!G{FeRa9a|JN-x-OwnW7{N +xGYbQ!J|SK-iMhIIU``IZA}?>6a|+nzg4#I-*mD}c(4xpW3HCfzcv)thm0JL_UBuvmJOa|0x`A8-f(r +`4vtAkIh`{?nyAEU*4OmuSh<)JDgrmjR8?k^eB?0GBtzfk|WoM{ALb~?mc19(hmanu7Ig)x_xSjTN}TW==q{^pi%V^IJ8q>r^SD{8c9|xvC{ZQpi_MIo2cA68{`qfpcK7(Dtm?FjKox()wRbz~Jl!sGooCTzSvzzEzQG=Ybz3$ey#KuKUraEtQBOMWW^0Ov(HSY+9D* +A_MxOC%^gj@vzO%{7*0TybdW^lD_sBa?Y#;~AM?Gu+Mv*`@WaNT +(WK`02Xu59n5MZzDzpWN#M~@9EVr{PZ6Yr%;@q{$SAG+bytV@>8t1$tJhc8;$Vm +=N8KBb>CwAmTs1+hO<@!SrFE27tZTufOQn)}5Lk0|E!d7*eOM^p$lAM%u&PHlv6>gafBwZ6IVOhRY&Y +R^Y=raVCyxu$W?asURK#kP?c0mxBQWDo2x>r9iE02SOWEH@!%3$#f01s9K#IG +qY#(WO*n3y5C#-!u5SbiocE1%&>swbv_2WV0RJizai6^-XKYYU2Rk7YHlH!)mfE_kE4x*QDE#gBaFZO +NQWdFc&>&f*L~0s=7K*RVeYSCeV5WI5{eO@gY#i5n9MqOica1D<^0K{q}pgX%ooelQsEZ<$Qf*u!nibW +STu>?2K5r_b|Co%HM%G1PFmRx$E!aa4A;yCiahk>_<5jgE)Bv`s)!#RwV_mj(Ou?{u|bN_fC*f7TXXv +K+i(AKxV##MWb%Sf3sJsAH{=vF%ws2GMkT0@3bir*bCJJzXJdQLEf->tEhI;Q7MSa*y3u&PR}hIpOo` +wkZjOYX#LkcocxI0h;#A`}5qE@)o31FvLONezx+A8O0yrYUM>_&+rZw=sml+ZgfO!&1m^)?p{`I?L<_+uIpDymFkx66{6>@2n0rD@6|z{F#{-t0c5E3CcT;)dcxsZrrtdDC>Z; +i6r>gUA6x5MFv)R80fVkY7DV4_q%6dz9birI;!w*&dc6L?sURkE;Tr0jF} +a1v@5loqpd_oS%La|Zo-}#t|gNEgiSN5Gt?wkuTro=4Q3mWe+c>!0Pb(S1j54*0Jb~b0{}4?0U#c0O^ +4xG-7<)PQtWZu=IbP=gpg~JO0a=vbFRJPm%8fq6oREeO5j>cC7d@dw(E!Yf(5j9dG+oFSF#YuyTex}mpT`!0_y5TjYQqINT0+W`plw`m +6iFW`;KP^-pfu-`?U#H%nHz8}%c`;GPe6_8!=mm=_&6{tpog~*Jj!t@$(ejEs_oYHD+(__m#K=7?7@f +SOFAs&h3$HVjolndQI!kRGk+Y|m21mYf~jIX74J7y7*h^bz)3L`CSkWt#{sjsnJnSgvk4{qh?veN8m8 +par$oavI{bbY52fu+2ut`r(w8*`?~rB!Pi>OfFwroa0x0w3r|qOvz +V^kcdh4^4&xTEsoUSF`7Llgg>gW#WB9)4v}*te+5YX!!TO63_PP0airX`N2HgHKowG=r>GT&Gu0t1qLo^offFY_Cao2v(Ulgx)F{M49UIHlics6wd +!*!xjDGif6g!+)=)`celn6|Amh$iVM%W`yv*$5rJxszmnKBibJkU{m)J-}Zfxel@Gm-zmY6`eK!F0(Z +xTkxH5^qN2$7NX33>;!%?qQ>$!@#X7h=I1BBOj4egC@AgQ)CPRX_?^sw$W2k=Q1(I^QZR!K$Q(9%7J& +h64gxv&MzK=3$jt5h$k|5#CXQ{{3XR)N{Nv{-CAgCnS|`-kM|fc%gc*V)$IcdU(8%V_+@i@MN)9|_z- +)|99)M?vRbN=g9frNGKpKTc?vxQz*IVo_=o_GGEruvybAm~{!~Q8n +>T^oJp?w>)*XS}Y2gV;?mI^r6v@wE1CgEQdb22{R@hMbuqXC^F*<%UFfjW0@{aNr%t^ELI`RINo1o4^ +&inb`Yd|(eV5}hZvwFrWp~0xVNb9@lJ$;^4nO=I=a+B7!w2d)MZL6tEh-MfJV@?k=Z{&4D2Qw$v%~Wf- +;5&&kDvV<3-9pKr>~OV2a;KZ@{%i20?MubA9`Q|1l~LKc*}%bRO(AnmP%Fm*ze1gsi^SgeETj`34;kX +kpIkUK#F=rqEvCqB=XB+%X9nSkCA~$$!PIWE4jR)2YF`(-gSb^vN^Wd-^@T&&|8j*}T^R>1r~Tr#fOstoZEYL3 +@jef3A#4|C;Zy_alixPHyj5-Twsv#JL0b`t9QTm#_Zx9P*g}Bm9$74L;`(t!U;h-=dydki6ThxN(~?Q +UnZ7@7&z+o*=4odQHTOW>h1KYpseB>E^HnN*L;km}JIB&UkxVmOFwB+n-+@0e_$P^#3Ap3WR4ewiaSD +7InqGYVrKti$A>n%ge>9H}C%Z{KI?9Te-Bb{esERGm}I$n7O$~!d#7W+}Y)v3l~!?I%M@@@)5JSR6QO +Bi4$1@#UICDF(h*jEb^Y0bo1F)XWS2!9H_#?@CpNAJhG3MkCrTJdX8{-Lw8Y4 +H;ld;08w$}!IUObw#%fF6+F9^Hu5=Ol2)eHDgL|Q`JRga)wB$2)-+pOw*?_1T>z3SrUz!M&-cbG5EE@ +w{T{mRk_Pmrh?HLrYV-P>CI8Z$3yd(( +7mtvV@hadq-!MRN(Ea-Py^{Sv>Apk4m)VNi??lK|%?3>?ES>&w6i~Z_(xoKvd#t`9BXKV&`pOI>jBK6 +D>W2t|(~*osL{2{ZTa=b?fBY~d`S`=z=P&;F4`n0^dI67ePzw1;NW)n06T}8M9WRk&^q#iHr8pA7m%> +{R2BrN}T3s>Ff&Hkl5H9y^bSyRLdqCVgK(}@UFEIst60q>-q7nMVscpo)W9*8o5UxP?`FJ;a*G`7(UB +E}wOBTogh%^S|L6<-r`S!*PAoqHIxl(?&hC-s7~PwGDmu3kd~XVH!77(dOue<5$DcsQizWpX9SCl1uj?9xWPBSNpC*i)y7^*w@4QX=$az@&#wdU3T%HQ{!Ye(=_2(tT>{S~aSm +0}KSz|E)ztW*sD3@2k@T*9o{*eaj65DiD1%Bw+S6R>Z(D!P{M-!ycKvILo@%b95^ +Irgp}V^f1*(9}Hr9le*!Ow)9#*UHAOcFXkMV^7hvA<* +&MEIMHejfFI0Jl0>af8(WYaj$WsYNe&+&{LUtUmGXG;CL@Dcupe6F`sa^!dP1k;^5GO*(i9(djeVDNJQ=GfUIO}yjiv +FCTglgA702R?%9y&1;w1IGn6MD>D*o}c*oM9=46qv;-2ZnRh1*(Nt_?D`Pr*W?p|@BWHG{BrDZos~j7 +)7mSIPrF#w{^X{@@VNu9$(6FpJh=o5MD +R0M2)MbWjJhG)BOI>B3xOZ&ASY6GS_*fF-B`h7JcsZ#L`YYKKv&tEdWOafLVowf%4_Z +Ib88oHZ=fI%j=EU9^%yO@(@_kE|#QhTK#|}#`*q=Gn+DIiOr}11Ca0ctqW(`D>d^r7L9Ga*A{-`Z^?M +YTepeu%?ze!PRwEF0Psd6!d1;y<}`E*bXsZ8lFIshN5#CX#mD|P|rLaqvoMm0Gp_QpeB6MkX*#d4Kbh +Pwl`YPbp+`x6}6ufa7zk&jW;+~8o%8E#7UC9+n=u90E5H5@@%`<(2xtiu;@EW;t^EfizIb9Kk<3qUUzi +t*sS-!jj7_rneGAMp&y~0$+Uhh@4JL|NmpB+3X0XM&!(!b}wL=YLbxERXU6bGz +RLTS0><+YsxHy$e5bY`{NyqQ`a)sB!Y|)i(WMb6j@x$Be>KLT|Xa4p?$>ZF-A~8?lQHu3{GgIiRMY9J +|=PD%XwtAI*0}llT&*PX76SlY8D|?glF#8Mn`-9j5Hj{ufY70|XQR000O8HkM{dHV;zP=pFz7OKAWAD +gXcgaA|NaUv_0~WN&gWWNCABY-wUIUt(cnYjAIJbT4yxb7OCAW@%?GaCzN5{de0olE3?}z)Hy@l}L2r +xW1fQx6iSi*4HHVv)nX$wpXDj$YM;9T7vY)_IiK&%?tn%AVJ&NcJGJPdu=2V7z}{r-IXyZV<3nh-*6a0lqlgQ^icEp@1R#>me67guw$~VZD$s}kG!r~u1wp|Ja|txYCjl1wIShn-O`?~)f2*=Dks%;SWo;gWm9*30WKcRv;8<7Ifo5r`8K&aL@-f{jG; +sr?`c3tV#R8STyFn&$%c!F(g41z&O-EX}@}B|N==m6-84n}~4ECwkp|{NF&XX0-+Q$$3%cDYM(rTeTT +SV`C$X9<-Z4A#>dOfZy_{EW&BRWy8tw$zd42Zcf-Qg|rktlNT7>B(pAjc0-id{RRi*?3SOBJx$NU<;1B)RdY?Wu1dAMYVpmP!pq+ +w35E78r&2ZV7U-~sk!J3FkG7Cl0sw~D4^oXmQ_TsFY7(d+GtAjxic?ho9n)*g@+@kkK_LcUUs5%e!hy%&#zr5y?pVf*zz8d#Xi@ZrO#Mo-C`@{Tnp@;NY4lj2swCmy$fy@3$fF3P``>zn=b +d^kMSmm&14aumr6MK$B>GiHkCW*Qysu3Z9BG=ha(1*UKcE0$Wti*VKH{tf(K>D3bUOf}D%2%t6s;sXd +R=8OUedY#K&a_#A{`bQNB5+$|DmlSz<^RT3Az7kESVasW(S^_oa1&{%%)n_vcYQ$P(D8Uf430siBAAV +;K}44{QqcL)XOkD}@~WOhpsgs{cJtJ>ehpx<=sAQTf(z)CFr0qP`S@7ZL$_tU}qgK>asHDCE+U{Z#)X +Ld&mgyznI$=o6<=QqDMb|4rl(ko)iJhw9njkuXqWnQ%a8 +e&JCu4F&&wJpeG)K4@wqngs$>AmNFryMvSP#?32Eh~j(_W_{*c&lYm!x* +si6NMG+x_pG&uHRbXM85~IS>a$)0KkSlQc^;L%~sfJ$gabrB$`rv?XLE+$UeRraj0N8=&d!PdMKw@G$ +AM~qlvBT2620FrdcVo6S|%W7efIY7)B6K91G^W!i{y^MW}*G3tYNm`IY^i5ECm#<^#)n5AV7rVCfz(c0N*;VV*n6NYTF#TI19*mS4}ZjMLL +vMiOZnR5m+`@gHk{~*b|A{BD98;WuV5&7jvgqI03Y#C@*Ai?IW>ybYPl7bKC_!hijAb>P;fdG7YsO)>f1B`#=8Uz~qwMTL9 +gPdz{ZH=kZc&lGGc$Oyy5ZFkbUdMTsI)T)$8$ddl-gw!`qSEuLG-|Wie!kM_&h8V9eUA3YCErLZ)yztBy&_(ZN(!AP(vgu)0%IhZ +kzfh-fBz(Kip(Ay)|MW7AE*xZm<#(7^U!g($zp&kD?wNOeAeZo(K-zQKFe=z)8Z`se14xby=RQ>{eN8 +Hw#eC;WR4?=4E1oFNt{b7#u6%u^$}Eh%tbA)Q(x~9v|=Tp6>PrsJMIo+cU{UPu@u?`lTUoJ6cu?fz81 +sm*zuH%}m9+bl{E}Y%;qA%p`-5MPPJZrL6km00S>^7@-8Vt^BwZ7Qb%c +4oi>G;*-(l!MV*yW}&Vr}29(&pX()=_ntF!Hmi+au4=)2Ii(RHJ#LoAvLWB^nLXMG)Xi*@@bt!09VJvln#1E_qvPQy`07y$1ToVHhGCT$u$U6yzG +?+L*pJDK_M7tGjS{JL2rO@q5dU6&j#ns{u|Ezzjbu~-Qe5D=ydQrc>OEQiuwUPA-h$kLxOC@Q-j`kDziE}9%X +ev+;I$?i=Cb*;mc)Ma4w>7#d{Pen%5{K;JG3WbBYqtFW)d6@Bx{Y_`ofYxp3gnLD|`Ejh-BWyFU7qZJz)CwI`F&Hgr1kMf*E(6w+%6aF>I +{0MkE9J$1>j3nn6a|~**$Txl_)P%fhU!c_c+A73)#VYpeBbW&DO|o{VpZmG26GTAu%)9c6yO6+y}_^v2Bx5==vDELIE|qrh7A2?W+pDc9*+MZ_j^f|CFpsEs} +;~XkY^#IlE+8m!%sLRq_m)pDr`+6i1Yer +Co|k)S+<-d>7XRUJ^xeUbc-YFZ9vbQ_+Kc)FYXUr0E0Wd|1VSX)Oo@xJJ`Z#F3s`g?OyAmcsAw&H +lmol+bI7Go#^~!w>GZ7*=<*Km4%w?w9?8O<*N=j}Ha>mV4IZ(bc`tYb`nc9irEd4a-t>PdobDmoFGaf348(^8v%)^LeU_ +0r0K(ybWOe?AZnD(@QrHc)xyLWq)L#2E!G0^cI7+t15cy+gZ%4pfjOLM)<4wuxbdloWuXQE%JCPuFYgIBNt9;XPCpi#sSX9 +Mf5X+QnHI6ACK}LM^J2?Vmr(pPxUYur#bmU0^`50hHw^a6p+~$1^@7$$S$hiM1c@>IABrEb|=0o;ts6 +OY81hS~<;@yVhNHzt!M=jni3nBk0`6`!HfhV<1)!6N1Y!S}?K1eps_xC=_VYt{Edc<6Oza5i-#u;~TP$Fv+qj+|F_($u +5j)I90{4brPts}Ok~6V@hj&P(i +}0F%Yk-1T%|k5MlWt6yb5*Aa9m3pzPxjg}6SU!UY$L4-GbJcI;ZhcHA~ux25I84u<|%0@4QVP$?PzGs +Lbf*QSi4}~RVU&ahWdjYCSn1q$8Fy~+&Rr=S*x?NXx9x2i(4MCB*<-b(?_gFeeOa-Zx{^tX_D!_}$>QlsJSu6RqLC?2vKuK{aQ0G_SR4wfd0wXSL;@xHNaB=KxzjwK3eAnaQtQOUNc +RuSiJ1lS-^1iKg01G%tTnH2CqlBy3a$0`GU_SPF|+c8ich@M`qj*^{N4i^c(8@Ib}bJW=u(KoqakGHHqoY5RErH8dZSl-Z1<)-OK1 +^CVe1%GS=l~wvH6rz3B{s`Is_aSz#Qcgw5;PdS^0>Ci9ma9Kex-?pL&7Y%8wOjZ~b9+)01pl2uFWfTR +K>b=)UlyF!4aVLZZd6g;9D2bgLI!UIFs8b?jHL93T)&~QOz6>ArtG+}h|UHfbay|V>Gvoh9`m9Y)sbH +($NCtATu*roK>L5WI|S^F|GhuvQmCgTm(f-dwg|`|fGZvqSV$+aB@ +%K`duo;}ReS6r=nqGy2iuaYWno>2g0aZK%ZOlur*~|3wW8WY&>5eQq`z^B_daq3IWo{ipwbN!m2;u9q +G5VjhL?CsG#1K`ol*MC0g0SPV0iS4L3Fm!Mnh=#WbY?QOOL7WA|YW_Xc+)H27ORU^=;xBc1iSv`mTk41_sTQ#|x;R8KuG3@;ZyN8cVYz-EOPf2k1|yGrvXOR10Sw +OI7K-M0BSGtVpXXMlPYcGJZ1iO}S_kFbS{2yHes%LZptG>(n?fK0#~V3g!_C6s16It!DL +PyV3z&&5b;V@~2$cFm>u)io6+M5zk|FP@yA=e_G31bSvXDq3AK%MF6Rc#iHsl5_q6u9!HJPMoel*8e# +6XMQvxHKN7&OcdIy(!4sLFlt_Y^Rb94)s!%&)S}j^ur;oSmlwc3WQY3q|+vp9X*a#Cmm~pvKE_fIf=9 +PAOY?um1x)fR)9*w_c{4yYlK0Hw&*Vg#4z#V{&L@D{H|p$aXGzRC +K?DtbNCyajtrmBX^LplhQls9vki#SAy6g>_t9r19Ji+ai^i)K@DdmHgRZJ%-ER8%LlU*Okz%SNi6Us? +i+V?Xb~H=iz5_3f22BF2KD(Z^+^rFy`1Am!QPY@ko=xVEapTXPb$P>;_9hWa2rI@+va&oLytN|Mzr8! +m0bZ=Gxq)zf@sSwARtm(It!-mJ*ZTF=GdP_UY3n^VEA&e*C~boFb_ajU&umWW=EXK<7XOd%yMi3Y#1s +?-3IO52FqScHR=@sOGS~92EO?R^}uxFo{b&G9k0)i%b+l?d}e>C>mD2ff=9EW9gW>A;fWP+TV!4sIZo +|?%{omIf!C_t9ttwfseqaS!P&S&fbjo*N?^^A4%@#VJgr&QdRNHM_%Y1BWPSAjNgleDx;BeAQUOmLL~PHbiroUQp%HYjjKuyr5deTuz&%|>u*x&cI> +2N{BLhJE>h)HG2wJozNr{b*cTXh2{LmyA)_W>OvOL$<8?O-1r5NqmfHug4F`Ia<$prJC-$RRUdfNua_ +1U;gfgHZU-eaj&*oMWF)rR$y+UYfTmcZkCym&z3i=o|m+yMylR~5aUZERnd`8YZ`r;msNnN|62Iq*nz +8|giUot3_FT^eDn#HL&cRDIS|ne@s_u#2W#zTevH{iV6=j#XC}I9C0Y94oX^F&3bp0juKGZlGHdXmod +JUr|wSgnDI+m`rlsIAZUeozH@c=Y}^by-;kbs`@M(6uB&$B3W;*b}qXyZe6O;H@2A+beXeNnS+q#0+V +MR?0hIwEo2Z=x`yK4m3f89G6PCg*x<1hv{+$5+BIcoh_~MF?j4OkP4*9t-yQw+{lSOR$?5LNj|U{h1u +qOhMHWcQ8WT0j{?0H>5>MkKF7AK~DV0MSdx?1j5mJUY3NgxJ=Y^}7j9{0UDne5GKmro$*U?v%Da#vuP ++NBH!nqb6(fm@?*0%hQdT+z%nhqSQ#xf|;1>3WeKz4PkL~A#>3GW0Z!qKcP^a&(M4eBtEPI;>N4;vur +b2x@1X9G*<_;l#4QlU8C?2`Y2Lu2evZ~zzrg#X*S0Bk-JDIU?)73C1JSFE2=o6%L`^%M0G@b)&K- +ER!*Ud6n!jBB)?PjmoCaYYvO}#e&iTh0*VaN@RH|`DD$18PQ;@j-ujpZURT$N; +4F{2%dk8MLbQoT8Hn}@%6cQ=Dv`@{s1uPg@5k{&wdzux2}F+6ef^0l8$rlK%?M?bYz}_D9HqO97BCv^ +v)u2FYsgYcLq9g<_EJ3N?*7qp|DwE;~nTJIwr%)Ec49cQ6&k5m*ColqdqI_slj-%& +^OQ}?y1(eV~jdNCL{hC?S4WT{jwmQxd^rsl=f`a>p;LILjuL9?Fjab87TDd>lmu?wV(raS^FUi +p$d9xkH#HQ)j1R}Vu6r~vIN;hNt3Bhmi)acZJ>jMa4!fIOR6pQG`+bVzTXF1fwJYmN1w>grP!`w=@&b +29ho$FNDDG~Wtc+)kWuM-dC=$K(w>vOO}o8RurD4CRAGBTY5aCaod8+8Ch;OW|`o_Jw!m)VJkS^-Ybq +sRIyp*xEFKxtI^b9Lw-l;BiHe-y6@Kz1nzi+tmKvvsjdVqJYBj9wl<{>!gY;xJaYVj$=@Sp)}lSt#rN +o@$p_qsIKmef22k34~v?2^!<^!N}~P>^0fP^MY4R%4u91M7Z|w->ra*F424eEv}&#OjeTGs73yl)xWL +NCSy+U|A6URk`@wef>l;%CxMw^CLpjH*2$b-~Zu))%Qx&6UgdmVBUfAnEWBcAyvCZggKOtaPXzKlW@l +;R{LiDJafk}1n9p}MC^-b$U;N0ii9$10AuT@7caeFj!zdFWWJc%w^WH>{3(D +j#H?-&O}!YADVVG$t5z6`!$#-m(0fHpbzWhk8_3g?a7^bMbG3=syWTf^9-;J((!srdEFK{{T=+0|XQR +000O8HkM{dL_!}!Vp#wH)M)_#C;$KeaA|NaUv_0~WN&gWWNCABY-wUIUt(cnYjAIJbT4#aa%O34WiD` +e-MxK#+cvT|`oBK~S3WtG5?O0GFHL>x-s2=r>ZgvK$96X9rnxF5(K0tOsY6n6+}-`|cisTvjg*|U=ic ++vZexiA1_NL)m>CRaHn+e1v#}XfadDZ>lfmM4WAl%J_&i_S7U}G&in`Bx(eBR9Zgd;=F +tyx`2Alq^?NW)euR1l^La$|%BV=nr1+dn2OFF4;!RRqr)8PuSrnyZ6kR1nGQN#wMVwX1v>!#6MUq5Oe +i==!;$oJ-lPZs*IJ=D&Nm1q*z{tl{oMve@i{dDn0ESpRs;&TDnO{~nagkt+X%v@bK1pK$98L4d@;b?? +xJn5IjuSNBt*)SK=Ul3FdeUArP2xFVm?2y!ajxM;H)(a1FDrlnJ*$dzf)M*yb~0a15i3S5>pnio--%;yXv#m?|37})lC7_h +koj(Zi!AeP+Ao2&d9YXFS8gE%Xf%OV2=VBDzO6#gr7fCf1HBbikEl$yHC=kxpqdQEs_(-eDK?$KOdK! +JFie@>{EOh!?bSI`T_3ulZmV~UV>YF7p +AMt*)0Y?T4$cmvqx0y^+3DYoUL3xNItS+wJm~bJcSjdLoxZ(@pvc+5$;B_x>C5QgY&eP%h +H)n_E=h5j|boBbo@zLRnespy5{P^vQqmx%r^bG2roL)r7N3V}A0P@9YM9m7kqr-E60WhQ2hiA`!f+q* +hj*gEmet|K4d314tkl`Buj}D^f&B58l(et;*2kG>hNIC%juPEJpbPF|itqld2#Pc8<4|49 +T-qv-H&@H;yH>EQU7+l~(2LZ{9EGQfR)`sSCjqgOv&0F0kbk6#?(^Jj;E@WHd=LvEWo{QUUf=ygAOaq +#-!)gjkC1!#Z@7GXz|q?Bk;q*(<| +Gg`YF8=X$)EQzNP6-UavDbgxIA_tBNBwk#{RTLMKtMqeH4zT#f#%S~zmJ(D4u=`QxKhBcRDgOKqcqeZ +n{J^`N!S{om4%CR3z!wUrfKN3a{dKvslRQFR+Vyy8535aqgJC7A_8%|c*B-Fq;c$CrcYF77H2iMw(eB +>PFnX{93_9w*EYf}i&tE2ED%Oks1EEYlm+6$iAe5u&p0Qm-PoF-1`oseIn1TL1x`vK#!=S)wnkU!eWi +b+pMM`tN=^=WjG-vA%WrUMwPO>@6Fq6sR^hcaj7ZK=NI`WrM_s +qaZqWV!lLrPoPas8~*PF=R#Rdy#BxRK@My29B*fn-vRSz&F#4nze}@eep4cu0iOaYdNSCFia0HSah>E9K!kxzaK9t48&Y+|Eh6FUN8N);I6sx?hbs1 +J^dGIZn83V4=($C%{LO0+>3W0~|NH%I8zs1sKqI^1MiZ#?EiA$2sgc$AH?KBK- +`MGE1;e{EbTcm_Gp2O;q|lHIOIqbz%(T0ybwHI$Co=iE0k+<64=|iL^d+F5==PyaXsu#Vi~CAnL>pRJ0GJTqKDQ*k4EEVIKR0Cj3OWb8)mBy1QDK?%RpFaQj{OIq8Q1$U} +H&AJwWV7lDciu&jPZHS4K?EAl^U0@jDddZUW2+1oW`qNB$K?DmK(25-i~1JIeJdWB3~(@$iR6 +MIMOVgM6+y3V}lYBh##;?9=&%f{`zGHJ{_~#A}`Y~X2p%;!;@DRKaEZfUL%&nogJ@>*YTJ1dUaA%8Q{HfV3 +rTigH!zY*snlPhskxWqZo5H?3Nq|mk6 +dwhv5=pw%UL4geJ`Pr!ra+igUfgcHJbHPm3qSD-qf&91yDgwJq-%W_ss)R?N@vS_S@LM(3cwnp|GOGwBjypd$RiVLFRn9@&Jm)sfI~HQ9O1S{BBoXA^|MWt4=Sy(JXeADY+aQb +#qvT5k`#fwuS0G>kKY9P^SXZB|u0EURV;D=Re13Y2(&Na);eE%fe4Yc*0{?ZJ-FSO`ad0*QDfjik1=M +pFsnPE6`=?K%F0qfE$bQ6=blqVHYc*C<;myJOx`NL&-EMXl@fY3Li^G=(Z;vnP`gQByzLn56`-f~NAi +pE5>UIHgM0EucvI1W&7bL~)ZJfV-^9FQ)!xtl*uXB`Zg!A;H1N}|dOMk;3r$|@`C?vd6`;l6P!QyJQ^ +&{aW{YW@Nu(-R@`jNYkTC4HW>1_nYLWy1#$x>*F0H$v;)dBKs)bZMe#&5jt;2KDvJ`ZcRQhSC?qyr*r +-TIx!B8UL&My2Rc(DWBse~eBJB3XeOL>!4A7sX1-9q^JlIy`E%NqFMaK)FG!0utf#<$Vcw7~tQOe)3>N2Nv)9(TiNx-FYcqZuREaJIZ2gT&e=D@P +8qRq);pYn0v_gv5eNDM-D2{p|3pM(dw6DxH{yXfL{)=W)d&)tLmIT?d}wIPL+a>i5j~P18URHvavM9O +)TokZ1}c`wo)mbv{kFWcj3u=Ywx)>U?zc@|gC;oqV{9Qen-CZ6O3p!usQqJ9bG+D#C)mT +&UpA6T2V_8zKT=L1158@R41x7B8?AFfA_SU|5Si21ww8TzF^~Mk!=tXgngjR7?vkzsX>azIglY?C9c9Az+ncgN#x +1@crR)-LzGd5lsGCCTOuS>b$BEfmsM5GAr`s0!r41?CdrmqKejtz&xx#MCzOxi0nKHj|egVC}|+Fvl~ +W46*Umq8LmKt>wMeNO|ukjuj%h%QvZ5bps?rV0C^>@^=>Dtka=VNJ(WVrWroLUF^*oDt$EwgWP8Rxss>)^>9Gn5cPr6<+RHR6%WsybYhdoB;WAq^EipIH(D0a(U +4;1&4x5tb;NRNp8I!L!6%3a}Z*+?%4>B}^mc1cHNJb_jg(O>qX?ctu@{;7K(_7)$lo(!f*Lw^PTwA+9 +!Zp6F?F?NgF>IzRM=!K0W9de-9fIIX}j@E@T9fK66S}jr7a-jBspDJrx3N+9IL2;hn3{(e8G*>|%Cs# +$6SYfa3tG4*5589((C+^C8bmDT7rX(!U*;J>8XC<8-c=EKTD~d_(Z@9r4HaYbndtr2x!3La8eSX3ZWhS3wxj9vM%CmmUNkrfTD&yw;MnFupd2jo;}zH?5ExGLki?L{AiJC#`A~+nBhs;3 +`B|jr+pD__iZgIG||?yswGv=k~`6)u%UhDp;8iyJ#Y%r67S*uP>C}^m$;U@RQ|E!gVxGXWO8dry7eQS)i;S2eSiMPT`(M-QC +Ae++M2%vl9XB00l))qx<(GDdP}XNm|9do%?wwx@VT@M_I3@n4>J89*`SyI-k0sH8~IZi>a97BFmy5LD +zr$q#1{LZPhEU+d;Jm#P1tiB_;u)%3?H&{oAo&ZAS0kzmML5)SO;}_$oB8RRR@W#h=rBS9;0_EC=rGOkKgc#%3zr-;>o9O=NOoaJmLrQ4h<@>u?=hdkrLvfh;O^SCI-A4=%CE>VW5@X)b)zRc*D^CWqH(W4RIehNkmKb>XJ7NV~~Fp|o&F-<{NE@0`(!IEr)q% +tdY4h9s;5JUw8A77<2kVBzYs9S?{72PBT8n}_F;f5`3nF%g{vhEB$v01b#C$kyxVtjz}(sd|y_~_{~p +i#i?!ybJ9i0j=c^6>E!Rb=@1$=>7P?#CX}&s|y>uWn@=Zbhin=~UltT}U`z+@jD65>>Y>Ca@Wnl@crW +@rcsg{T8?CAc6TZ*+Qgt1htWj)K7q;7yr?vs+X2@?%8M88=Ov{fwUmAVg+CASxI%h{e6>vasQkm0=g~ +*6bHi8MX^k5ZU6&@e5jZVP-E&2pWGkr>^`#D0rJcokMAz+x>O&keX^cnUrDDTCg7q;zn{H*DMwjDVDb +^RNYDAOs}E(bW7sW$-uGc~e7?@7T_xK~RfdZUU|h32u5Pe9r*l@_db|iv*c0S+P=Y&^Ee5t+v;mTJ7G +T2Sns#byr}y1*ZYqB%2I1Fc4*Dn`K@c6oZ;?TX2#&k$f!>Ioz3iitpm5a=DmYdNR}zCj2rRmTHNiZzU@bG`f;2;VPJ5n3Gt1C^MvKfU-SLKP8G(gRPmi +0lzhS_NYmbmYWCu@On|*nqZCZP5nr)j(`pV1^FRE6?S?@z?G`k2K?~!$zi?g>U&+B^s{ +(udAG^MtyxWp6LZjP43)6uh|lY_HgI*ukz=>2P-VRDgL<%V7jF3~kIXYaUf-9uEupFDZes|RB;&&z~H +!e|02*3SW!QJ&;Y9ymOM?77+m*41U8suZgMum~v->^AFHTv6{&BW9@{eLbhQWJRO1u96IXpjc1i1)AE +%Np+JXnc|>;>c(gGQYjca_du1(O06c)Ll};9lB!CkCk>nRN-SDvZyw#B`^ZEsI=&P(qGMGr +rvn!E`I82Hh(i%g>4w~+j|*6nBtO{!#4?}}H6Q{7|U4gKNK +dsF0JZoBf>?n{lPs)h%8>S@<7h*GcV$PhpKG_!Ql;YZ`-a1os*r`@IlML_Wdv)q5X +F>th!)SX%1cj)NAmzbUcdj14h~2W7!M7OnFI3B(d_rG56IVU0@aD}a{bn+8UMcf6>|f%{_ +v>*n0J_&wMTQxh9Q&Cy)u()Jk|vS2G9P!`yx?H2C%yG=v$zkhXC<7c?$+R>@rQi9drGQKoa1)vQ!-wj +~^O*b0eB2bJ>TC{l$>Ec!%mR#7>WPaE&TI-D^OgYlt`wQ9A9xMs=k8Hh8-h(U*<>Bnudvzh#Hx;n&M{ +pr>;DkM8$<29- +El-Od2my?aci_r?AC`-i>lhqau)8J)d+KK%aiZdAs%B_6$8FUtxgs_5wabo=Sk$KP)c^(oa$@<2CE#J +xV5nDHTMTIK=<9TAFTF^|!khYwZP5XXVo-jREg*w#vQw#9-*m@3s6weN?vU1{}%3G~`T%k^qrUuVxcpUj1r0?4B6_r<_#+V39K|V)|SPGl +uC5X2-aWO4d5MY2;o5x6IS-rE~bco@vMNsC1D8jm&FUzZLZ_O6GGqINGX`BytqhD_U;)kz>XY7+eLLa +Wkl+3CTM0O72@VMm^u0?p0^N>1~1l2)J_PU5msmlMcV&!C?N0O7ru0bZT&<8 +;TW`EmZG<{8)VZPc0P`6umB;W?p`YbLD?T8_wwu_l3h@<@ZMA>n;Af;0#X6CnLLPeGM0KGFF-kYC1LW +d&c|kACC5=r@t*$p6XFz!+9aV_>yOXyIXg{v|2>_CrMBZG3ug{xjP7aw(r)gMhylFyyuh*h~2I96y+q +;#*L33#wQmw>iR-QV3ScPTGWM3r+x7wZ6XmG)+tiDkT0mJBA@{8(Vu7e@Zf@4#a8j3jQJU6FYSv4aM_ +H+4?m};XCxicA$SnzMy|g}3gDpz43bX>sIRS-H`2&7MZbOV4vzv1X<=!3Sa0Wdg1v +zS7Tp!93UO$XG>V*f~fb({>E@r#1LbIibsYMNn;Bf*J +wUUr4QG(eaT*!A`B^kuWeDGm5`XaBiGGNDeajrARr7f_N4cQI(r6B~ky +@DXXIfb=Pa7XQWZOTKs!XN!&a>Avd9K}{aq2cB>#Wx~`sD*F_x$(#8X5Qk +-$`xKGZQ*WE1S;JRO{Z6T6FFlqDAC_7Ht*(y1&(1eYC00)AsBks88RT4zPmLs$;dRb^5M%^boAzR&1> +o^N7#4kE`+njL1;2<tiGkZlMFHW~ +$1JD&H6AE;Di#u=LR$o_hd;FtMy#HvMbjVn&f0oh85`DDqI#9ec&<@LX-yStH_(;~yW3nH|ViAK(mhL +mdeMKysyB4>2>3Z0NU3`2O*q7HrG|W6#VNwif=r%N<;O@@A1PX*fG;Spa=GE!eVkP`3ta`LbfS`V!o& +iuk5ww^Ec7+^?YOTGs_Y0?~U5_0bf107%22!A^!%Z5xBy-|&qg`hD{bcV|)9)@W@$jBtL?AOlk^WNkg +8QMc9175aLk!e*X@&_L}q_LIjkKnyZddYYLwaC}c6WkMq6Y|@6tC9I{_uR&YKi;BdUKAI+7( +*f-|Ua%#X#}MY>_oT>WGjz^pq3j5)D_?vMBLrhv2Y?7FcWZ&QJLhM{xahYi5tyS+5`pTB=W`*0`lD*7 +!Eyw6DGNcDT%Y=?LOsParGd3$)g?xSY%uObUocgi!Gz +P7hpXUz|-&`F$54*%N1_<*06m#fRrRVv?<2P$Ph=iJX}mJZ3+v7<((|DlVw3Vl2}LYV2DjQc&|A~_1= +{l7fA%pITVn94r;N=Eme-k6>8F5+kUg_*b!s4Sk(G?bAzoWJ;i-AC)#!fLlq1NV_fw*&ALoujX*pB#F +X+_=%Q*rx`yU9>mqg^FNwo0fPeCZUX}ZLWqh!?)<+KrjtxS<+y3^%{6H}8Vu@VgTvqc=;0MECIlb@KY +}OD};c37;-q420b@8Jv%$m~${qtwa!3Rfqg(n-W63xZB_AqYq_y$gIO?LxJqGnVb3tw<-1q4Q+y)QlV +DRg^3_{zfafmg<~yry+I8xo7eIMG=TiaA +tiKa+ja8GR(V@%;q#q?I&KqCnnA89~#_z|tuyVN5Jy;B7WDC!8_qD`wZ6xP%#AbL1xxb|~>me0=8);k +$!6H~_%z!Kc7H)4D>j@T8y5ADU~E@|m3Erkv5?zU}y-OYB*tthUd>%6RjM;b&s&cT&Avl6TYPjWd109 +&EwbKc;VS(VQ5yh=RG@D}%1I7@jUQjY$5YB*}a|7Fg_*`Q^^GVFer?hW+Ty|xBt)DQDki%`tB&5Y23> +T333;AREW^KE5M8hQ7sL$+Wg5gC*@!F8;0xOBV8fhExk;Fd?H??k;^mK14-f&fg1`a%;^5j}&kAiJ_f +_wzJMOxoWb1}GnW`6N~amTw_@p>uOc*dIIFR<2+5Ij-`;B*jdvE>jPt(V=aeEu!fCHBMOnMO(x?sTia +G$+cprc1%?|)>=lcxQ<*G^z*&*tD<@BMuMImy+G*2S_4* +^>v=SbbyNr;JhH31)Oad41Y4Av<^_IUA7q13d%aOGKj^OyL2nzT%MxO(r4(}Tp*I)YPx-FYEL_BjSD_ +L2XQ;IxBaIsOvCOxrS&K>uMCQ_t{*{_Y2#7BaLVSKX}&?dMwrPgC9uh(4UPtuD29PV%zT^re2l1-BRy +d0b#9{xN!KfL&M)%(xs7eHlXap4;H28=a^WQgnMI{wn7&hGRK?b+NzgRq~!J@cdvHWUTehSx5%>8!0t +a9Bgo2=yWeZT;RHp1fEwQh>2;hnSMrhJ}5Tzn3+);sByf0z0nI5fs3DwKrtuSnu9|89^XOthOTJI2Di +5Dk=QCUlg9CA}N3za?zmrIVp65TV)%Q`-2#ozb|_X?v?`7VQHmZo0@d+ID!r$#Alc8$tS^Rxpf2>3t5I8CZJotKzrZi!>5Ft_#fXa?Ui4zr0-T2#7T9E4zGy&v+q9sJsB^s`9d=gZF46q5m3hw2wyRJeQPPU3I|RLA{v5&RgN{+hgS;R1P7BWzh3N1 ++iC9ognrh0Mq32b^MRKz*6`<&G37mAR892m|eK7&!E$^@x)DFnu;!J9hFXj~?mLEDq>|iKSf +y2q1D&n{1*!RYd93E;$R8r0C>cQL&)dq0KLq71+TUY0WOY$+;~tf-G(jl$Xt_qr)if7;63O=PP^2dDX6s!l(FFOmB(L4K6@0us9wp6)3${w_Vj{UjsAw +8N5_@wjrgni(Uw0 +N!8gQWH0tXS?5AugFi%MV7fSZmu2~6-2U6C#XE<_CH04yj7zsP9knkzJ6PAhSYtNovCpHsp&_)r7!?% +-v2Op;_=U%DH!f&U<%qcPRN=SYdUBb7|>$ESC$+?{}A|LEU7N>R!k?3HwMG*#zeHydKG#8M +}RV%FF^~v{bTZ^WH!)5?JoNI79Et#w0nc=nae%(CTIHd1GLTiHmx!8wiGO&wPEAs7c!+zpKx6HY^?nwX? +=y+u;s44grY$)kY}9ZIr^OC&N9a$1Cdra>;N8N)}69bn|qTr~oEi$c*n&*|>AW8|q@@mj!u7NJGS88t +f}`}QJLw`eGFDCiz@P$=+~4L)o+8_A4Vvu@IVh|t{WG-&giCliCin^PHaAjnCR4bGWUott&Vk=vc;*g +S3;8U4nYHAl|`7)VgpG@4&S6ziiDLWeWxwV+cQ#L=6qkyvUTwhpNn94166U%TGvPErM;b4KSXmiDU?c +wlHgyh?Br-}dqR49($^>&}T0s)^2o!}rsd3rTTpO8a-`H>!-SQn*^i00Y>Y+tg-sk(8C%{4OO~Am~|= +iG;6Se3>NFSIJYS^YRulKn6I>y={z7nnefa&ySAugw#F5Rye}n75`BY@iU2MZhmUpkE9$lh`85}x|Si +w$V_M~zn*Vo>DD$M_2uC%ftxwDAbbwAAw>G4lmEp?pJY{%yNhqL6iXjcorY_S#u$8{fk7Ir8(g!WCexyN$g-F;?% +t$J=Vr2*b?6*#|3tc!0gcL&^AyJu!t6tw!i3UFhNxWfydZgZ#d7(SY0da9Hq0SYp;$8Urz=!nMt=b5M +F$jWMWy5MNwFSE&ttE724S$8CtfV^l)nfI1~M4ofTv|j3413=7fSVcR0HmXCIKisfsV0K;0Cwd8)G`3 +(`M4ZyRD2-=H}Ws^5#`!W1pH~X!dlX_A8@$KavE`>q*FgI4EmwuC^pruYDb{j3NFP*&)~uCA8yml4=E +dGKUTry;*D1#gVphU9TmcNjIUz^+%TTZ}%ya;#133?g_X-BNm?KVi8POhHDPRAxSKT$mNUTvIqTm25o4NTEjb@#8jA)kjxNw<50Ho0e#7*H``fxQ9xD7F=t_H2{ +4`=Vr_Mu&t}_eWZkcc7t?pb^GCyN0d*tb8qKK{_765$}mEC7YXXa$KSOC*=Xl=i})7gqiI+Ew#9-%eL +;#@$@TbB9lA!FQ^C=AbUdKiGMX3Drjy_H++Z5Veq=;k(Bxv~;PS59D7+u+M|HRc5E<*BN|LVE8AYkrB +HA=rJ4mu&@tp(buepJ^b`jheUDHj_CZN=X@X#8&bz^R0$>Zr7s{i?K$BdwDeVxHy2Y>yqW9aoUa4*-| +pzQzlIWxZ_9{o`~IBC{REOUHofTN(DWpp(yNPbSLeNL=GsiHwNFY*Zvaks~LctE`l8_32f$z$$a7_8(Bf~ +_kL(kcOt?&y?3qX|{le4Dh0Kfqj~5%&VA(_7o$xkxbQY3bXY8H($q{$|OM`0CMB{s8=ZoXpZJGm^ORp +x6cg)h7C!cXo&VRQ;M63g}l3xKx3T$v1nPJvY8kf4R?M9xD>E#jw6vq|ncpgU&gLm$B!+5uRJ2IJ758 +GMy(Sg_$nVzRMwXuj)MKyl#LTCs)Si>cir(*te;uW>5ZkrA<&lKi42kOTSg0xv*y$U1Wp!lPcnmht%6 +G_}_zQYoGr8HQTa4&@Euk{?m5T0c*^qCA7vY0{1H^zw_+T +F&@F+gu`x55H^p3LapduI-Q%-HpyX2er3nvZhh$#RqfOL8=%`N+&kwc3JF-w?$IHfuweSM8*=7v3Ky? +wgI;A=N(8L{TQI(Uq!ZDfWm@qvu~H*VDdE7aPXweC#wevMb2(4T-dXZW&8h->zarnq2`3F;$4~NSG9#@}WmQUg +)bP>Mz2W00A1xH56#JJnWh%GP2qX>cjN_@+?M)>3_ApR_;UA99@=CC-SjF4f1I7Jgo1Tf4#9vkSX9uf +2{b(0r57oL1^m+KiDKoRn44>=`cON-r#3@x5+I_S)eCPsF-l)3N!zY}E+bUJ7wpW&`DZUd=)3Idd9zO +o=qxIf!l~aQSW%hQV+^XSPI`wv+Jl@;=es#T>Tkret_8#tjzp|d;fvUy>s_i{|_}xdppg5iCf)AmMM~ +{tywSiX9fY*DE8>qzKnx`Oi{p~yQHWGuN7DL#g2pkOLm0LE7OSVN*OxBUiV+^pE&MEl?u(>PiD59Rb{ +pdjX38UbxsJqQW%b0j^^0E%jaQ}i{pd*F&wMtL&$z-`mfdf*Ib=m5c+0w|q$G)(WL|uN8dn=TSm23-- +6inv1%fh_=<*5JdZPaI1WIowB +HTwy0V^rOJhRAZhi?X9e+4R01wAf9Nr`_Y$_@Ph}JwAom-sD@OvIEMO&I#OHO?;>nT=XLlV6*8#2KAweTFflVEssz3Rt-uOWf8xil-om0hI$0FrfQ7zCk&N4!n +oaYtRh@4raAsmsl2VzckjuQ;UK~c1m2|%v0&>fn>T2S;;VG{nw1weiSz{&FF`U|;TSL&98|_a*u +rMC%S|d`5$b7fkX8tf?uiGU&6#R#S=&W|GM3bNjf6WfD&h4$*Mrlr(68R +b}q0G9f1I*p^2jBjiv>XHnX$1J$>f(EY{t8gy;r;o!vLm5N=PWlQ9m^%_$}$yeF9G}XTA`+!A=SOpim +p;>9411)(D(O$*zGM!hLHNavq^~|gHEmQx7XBsvkDJ)E(;FMIKviwFK(ULb +2LW0HRU&-xFQ*>PwSkOF+ZgXo5PrV!M5 +kAFk;HNhsxA9zm3$1Hb>B*H4RDNjkX**TPFL3g5W!q0|29ve=*EWQ3%r7{FV+U=t_b@#6Fc+xhJ}t8^ +U&pOs&B+h>S#k=Ci~`@iw#gW-H;x9Os;6BD%BKcFD9wKnTx|C5pXF)C3S)R+mA@rH0WqIhrTVQzaG8# +SoSJ1ir>fY%g~a*qV90+D8J-`4)_?Sq})xT@SK#ti^K;Wm+a%yI%O3#J!11*zb +kDvj(_YxQ +yr-PI?XfDw*azW`5W8BnJ&ByE*260d(80n@vE;_$XADB)F-4FlIui3{3y!Q*e@ro$iM?L=PVA1q&U#t3%Jmk5|E(AFm=u%_T0E +YGp2~!uyzn5)KOsZbYb=MB3Lu~uw?d)>2rmpCP$BYNdou*{bFgF0xp^*<&ppuX$rq(J$6RjUW26*+e? +QIPqQi*oLf1|pcKMzP`=rvIG20;fWo_As@?|*+;(JMbKv>V92Hmfgi@#f1ATzdSA>ZXS)RqSDb9*`ia +F3!QIzQ-U;)#)ZW3jEx +zz!tm~m3GVqxQoe|ML-s4CcYV8h~z5X96RK%TdltjXTMDfkZ2DlmR*p%@qrSIx(2tqez#c2=~+QV_J8 +#DR86IYwjHg2mL0!Hl*_dq%7=xACb-j%6a|_GC|?mD<&uKsy5R-=Iw0q`BfJ)n1y&f-$H9D#)XkM~BB +R&i!SgsJHdi5wPw9*=kJO$S3WOKyGIpH1WO*`9*bx973zLINfyN;%?^mwYoN3t82qx*X)A7i;mTJYeYBWRtraVmal`Aj#jc7Xkh`?FZa>U6Oj`;g>v;Uo4FpyoF|;) +WOUDSdN(nVqJ=fnS=~^qIj-LiMp$u&(w%RJDVQDjrhF^z|0?>+)DzqL-H1*1KhZjz|zo!c^7nYX2uz7 +ZeO|$#$6FY1;eN-5Kz}|h~Yb9SCzVN}_JwFcUc6hhb@AN*d8UlXuVQ+8uV_(|)FvMSNLosY2^fe9<)) +|vw6S0dSh+|g9Zb?zz_=lVClr9l)`kd$oRpEZL>jlK%v^;aOt +^{4}1L;YX>C9xSchbps=>abNE+%xuVyTH}l{&371%ea*`B=yXfkQ{Y$&-Go8bsY26f0Xu1;NFrmr!=D!X2sQ3rm$Pmf>~j&94Y_JW667H!rxk7bWdWl8j48e-40Mqoc;~)dyPrh% +UA`yp7WOE*Iznh1Yqg2%6FB%jKx#sTie|CG#hP*+8}M^x-4W^M0i4c6YuMPpz)J4euO*voDR6sZoUt; +8*tzM^!x_tPHe7QC7;~+2O0VpcJxRU{ohVNK1XuHjEnRExoG2I=HM+vAn%rr{ei9ubqnX?9)0Gk57Jf +Do(D}LiPDiE~?}CS}i_1c3Zqm{n*W+nlF!Dp1Q+RJDW6AR(7KL$jh9Tb5lLrRUL ++$7!%@1J7>Jag(nT5Z{XleJk-)gJ=*{D!W<*rfw$kwS6)cE_&XdmxUK<{|6#^wsI+zZK!&KNwQPptOhmk4{wSn28dW(YW)9o=Hxu~cJ^(kFF?n)8!x_D?FSMc2_-a2tAMadIDl5qv +23W%-F1av{^V=iON6{g;6SAFQO8YR|4(8RZIWxnx%ST6&Rnlh4bCQZCRx!=KPK+>W-mzdx5!=eD`ofI +?Ht~@apkv!6Y!hL8>0mCi*NVf$vszB;R6391t3Ys4hN_Rc`TXe~S)Xhj;b})*XusEX=v~ok0CMx7%mfXlYASF!SDx|KP%klV`k +u~874bY4O=9aM%R`G8#r_@18M%2ec#}qwWlBtz!7{01@u@4e_*MukcO{PhOnP4(>SFA_RxP=0;n{Kxx +`m)fnaKc@Y^H*^;H@!Kba|Jzbz0!@qG05F8qVObBZB^|Q@r|QT`0?(jf(pC>qsMc}v(s^0(&U~o{;^+ +-n(_aj|kY?r7LM33iHHp&+gm#A;la||~0Jo!@9RqZ%3{sE{Cy~>$qX>6|IlGHzygI +bbg1ja^OkCmy%^?WDi84nnR=?eg}Mni$L=%k^KR>&Eh#3S0*6C96AN}R%>995S|aItNL$=uA#E#J(e% +cBe)-&wvAp{3|;Nn{Kc%VcDr@}^`0o-Oc163*bc@P6^&meI7^Ichv!Iq=1&u%mND9)8KQ{i +Ma2b_h#``d*@kJ6Fq$FKw&tKY`9r&9qh&b-D*n?>M8fjns>xxsz!pGp_-cuE#Q>V3Z~em~W!#}cchx! +VMN49K$&yEQbq!L*>ryY{(m7;x5}u7P>Pg)K1G${XGwdtrHUj7hFV2sXB;(A{77+W~w884!^x4#zTHV +B^O1`n8qB5yx`83fft^|w`Omz}Zu9RDxl+FDl$37-@%EMA$ivV>knbtGs8LYf5t_WIHX>f{C@*BFxBr +WBbqXNh6_Pq0GcW(`CpRe(9x@a>JRmB+K(9!caxl}=~*qMq|L??NP`n1JvGP>j@5@osxlSr%4x8}emL +$5U?o7=n +>eQ?uP_0f8)WC};{}VfZwpX_HMDTKL^KkoeT3&h5Pvb&oL^v~UKuEMx-I}j +y>i(=t{?C$menUnMGHujh8dPG~SOTigDT69mu_e9)Zuf?DYEvsX1cfjAlZdP@->bZz~ummiB^^X4o^m}4=;X_YxJu7c*z1;t9z;1JQ2B}R^yPD$&T(J_-k3Hn67_Tp0qGqscB5BRAsDlR=2J(lU14W|C4^^%`)7yG +PtRU(K;--PKi$N|tPEK-EGveg!1uNKj#IXfcmXPOfw@*0ug$3$HEDjbZHI-@wG~sa*8V0j+`!L*uhQX@t4}(39|GKYdGH3EEF(AP;NlUT1RC +))>_?JT&6bGRuf-rbv_8e%=@Wl3bG{AFUIAat$gR%~gn>D*-jK5QV-HtRvSi2h`5FInkiEQfn%3GrqE +0AI$=Sx?>SrH2-d!7=hy2K|tz-3&6%VzX4MOhp#Xwc4kUp7zN-VCOOeZV*78ni`lEP;Jjr)(IrNON~z +KDmVH0=Z)*E(XNittuZBu)y`<^io^J8uefGp_mgRzW=jAD{K_^6P?W6`k{S}J=3+Ze)M1Rf_8|5t#g2%}v#Xp{)mk2K^ry5!OO6KQB$Yvyvu`sFuhR2kID#rHK%h{;ohH3}s~i7O +wBJRZs4s8R3P1;5o5%%NsrKL#;_hA02u4Afpzqdn +lMJs{=WOB$iLjyr~S5*f-k`uP7c5C4xqlnD_ml*ezlF&w=s^caE?A6x`g=a%GKkqX{JV4#SZEtUP>+n-yq@wJan4bw`{*Yiwy?dNl?XLEsbxmwyzDl7c4pVL>TU +vooc;@-q3`N~rh-5KdCIU=%g$3*jzE|S=85dG-q{{23Oc4wC`w9gW&)#dPmBf;V +xhqR&bLX(OOR`G7}((>oB3@{oa{=9MnvE3y&Jh5`LalC8j6x76>%3Vopo)U4URF^7Rk7~l6nwEISBT7 +Tl?S;vn59#;t`6j-(NunD}M}Ri!F@}q)G541R)rM_NKAWch4}~aVPZ071a_n=V&t_C2bz`?~uJU=HbL +I^ZX~&u*iY)Z)Qv@$k&VmWkb40UYuaD5gP-RAtL!lW&(+kg!bmxO|YtW*vrfun~3F@QOV=3vownN8^U +#6_?Y?I0hJHUj*D_o!B2@A^WN9M3d#oEQW%V*?yIk?2+u^0~t83=*mSd)tigtS5QOTI+DW^;{cdU4KL8`;Y{rR=P^NogA&}$owJ4UjzQLWjfcP;i#;PyKELsJ%*a`1V!?x&S64{ALwF8#k& +HGqFKNU2zf9r^ZByksFGY&mJkIone$xGORKvwe_{5oUUH^d{c2i#?i=rvt1%h0rvdG=`?=XsYKhf|*P9eHF?$OeC-#k2Y=K|r_ +`PrE@PIL>5G$ji#6~M`uklt{8I@NtN9hOcA)kLXHS<+=7sCfVhn=KD7<792z}0n!4%y1%svwU~)d5F> +z)$#a#;O{q8So%BYY?wf$}~xiS#Elu8R5UpbLFzSrkHOG3fdi6ZuB^?@M>^AIyyf)eAUI`ZrFj0k6yY +440zTzVNR3J!N`c7e>pi`*Yz@rgpYO;eBozCtlL*xmUz)(akVJ^vTwfnKz}|410hj#Ku&&14fCBMajp +$i5T?XdwEx>HAcsxng;wiBKYqt*9%WFrNoFsO&O&77?pf6kY1C*^B_5_Rt3d;keL2n}%*t?PUT25=RFWx&&9BD8C +c;FS9xrJs%A=J|30=W>bGhPBj1^us~SmA8_@pCHf`2CVRlqNgHNB%y@Q)Z>CRqqU%!%G>+ypj2U(MaH@U}mqZ%}w)V#bzG?LpMgr(%h%L#Z^c-sIDclvoyWH#>Dc&yUYbg6v(3A=4G@!-`Ylto~6kxtHqLvE +{c4*oHQM(*!BheIH19L6E3|9P*K5wxY$*qYci@HUZ$SzZ$(>yL=aT1bFcjCy^`W)+v~2z2-jM3Bv_9q +W^Q#{8ZCI#hN%I^^XQqCIZ{V}fXyxpcen?gd(-~CX{SNjaz93w)hg(Fq}^*nJuKYVn32uQZqY(Ckc|HM+9KLle#@_p|_vE9|@`m56wf{YcQ2(;$hLULVebP>+*95GMQY~;8ET( +;4w}0&Py{%CC+Yjc1YL6)YaLFu}Mti4&y$~@w^Co3s_Z?LD8(EmyRr{n9)rlP$pnq|mQZi+!y%?vCapLkvG +;9LPS!_F@yLVAyPu6X$@NxIkxZ`=m`h9N?F3XIZMtl{i!Nh^JXufx6QW-TVcn`ks)Q@Q&g2-2=cH&!% +V!5@dZm>+bgH5E|)dPxXB&&Z)k61wZbIr(`=sWh%c;#`zQ$JFOs8@x>NzPUXN)wxj0Bx+ESB8?e7$R| +y>J`F%p<7A;+JyHkT1$_by9iKof7t_Zf(cxPDmErx6pZtF3ags-C7H5&5ognh3o|#PnbOzeIM%LBq39eRlt5?@jGGcTzgOoL0uOdP +$J<&TN845kN5%ardSebbv(nOEbd#Skr +l@E>bPg7F@_Auz=teIHy4Q*9?`O2ly%`EOFymv@}lL?&_~wOIBI4!_MVLn;_k%3Cdq98I(cA30f5v6h +^(XSu{`Fd92I%4rt8OS36nQ&skUP{V87S?o|&%lf(r*{j?rFk8i#V@09x6QxCwa{ew!Nu?z&?DL&>@S +2O@g>Sy~ZBH$JbPQ=W{p6UG(ugk7w*#4|pHA@qRky~QZi*Yc`Q=6vN_R_Icy@m+Y-{PfHdnVaVIxd7zywSjDH^m;+MVmr6=;codP$yM9pX*T7)zyAy0E(5=4X}Vi +u4KhOaivln98iLn+~mb4=cHO|Hxl=zit?KbV}H|Wcsh{`b*WrETwo|Nau6+@)aX-FHMs&P35UecLQRkv=*{ka+u_=-W;xOW`(jC{c2IbSFjzu1^F$tXVx6V_LFNSGa=aPa1;(5^5ciJ%U4V;^ +uj#wjW0*{51JQT(9n&*Ng^$d>x3j4zXh_+m!sm2pH`xmrVEWzyftzuU1RPj5yqayjg)Mrc$mO=SA$$A +aEJsAx@dNpZC-$O8nnfXrWZLKwAx!s#G2_RLvq +Ih77b7t{^f!nz;&l9|UU0^A_w)A?c@2q8EY#iD#%GmS)FK{Rf7Xy-Scz8_9)EZaF*v0S)kgdmA;D>^M +L*b=qFk4l4a%HgjhQcb84NrGlEE%Pu8KJCxjD`*ObiI2O)K;SrvO$+&b8q5vaADuPz!e+snB?gj<~1K +zPA_XR@tSv9f-8$x74HML;axzm=PhFpk^8mbc-7_QV}hfVB-aN>Ud3%-nawd*$ZvYs>w}Cnq`bm0)1)QZJK}7Tbk)R`mF +ws4>(Syv%75BCIqIrh)=q(zEL0dAwzkH_ED?9z_)|hB&b +9}6stN76xCnNRx(ciqQ7>C*Cw8%3wP&KiOAgc(7jy{_Rvj{X}4fG0VG!oQ9)Wk^!c+Hk>kNgqLNvsat +8f@Rdv*(XoJCj|P!LB=McV()EW-N>8j{KASY>E9TzU1&Ri{GtaX{bo6+GM#dk{JbR!fJgxAt*lD=Bo> +=pHoaEmPG@Q_&6c1tC_HB2s+4;X@LKN5$T#Qa|34~k8}C-F`kj{gNLdzCHD^d=YOG|_T{Z#}S#Yinn*+ca-nAXSi4L> +Wn_2NjaKA_EQY{Z4(8s0V*o2V_gKPp1Q?nDz|XCIyL^5Y&ziqVk&jKbIf_%rH$ah)Qum_f*sg+axX}# +2X$4(8&)9(*bCP8X8AkK(j|Xu;wP)re!_GHMWhUt7Dtl&_W@Ld`(TVr&3wDM#2e;H7XV&22*paxlLY! +2Q`2#t3DD0N{!4x>~{e?4JvTi^k9UU`Ai8zE0Aq#$}&-9Ia{gXvdkwbQK`OI5Ez38)&&il +00bCb<*Z2_BBo<--LU8A2*Iy@EHTAsNF@>~ptn%(~oES7`_uuM2qbwFD>AqC@Nn#eM{Yu^`=>Lzc5Xg +Hg#T39w +TajB>IME03Xgo>sR;<{h%P%wKo-F +))~(&y)&gd=H*gDmi0X&RxN;~;qbg)#wT`QY&I{n7bFlcH}8c*Ph71gsP*N8Mt>%5obVKfCV1cEUEHxu?Us6Nx;Jy +AMQ3U0tJdp}9i}*2Z)tfKAwFSk_re1)8zr%vYZ?|Y9>S%Z1!_mI@hx6GsFLfB(`l8das58mN#= +4mJ;^MExh{02los{5~feRb^Rv*Vvz=E +^Jn{HL=T5t{joWfsjTDVB{-=t{+?CC}D-0rr%WKzX-0?*=Ze^_wKoCPUJBlGHMtZy*AE91S>h^wi+NM}B?=mS&Z9nR(S|Nx*i~Vy;@_WJ-O4Y>}le8S|0O%h}@ +i(J*sZKXkeuuuk0RT&+glIqNguhR4)E$*tbPYnt5+{+y|4r0P`{3qx#tnW=;x5?z3~4lMa}s%2M%zM6#2rSJDuOX7jhaqmakw^xsf*|z5DAyM3NQ2hFZWX{$WVY1~O +ABN_hhVR;umP{e;Paj4zqBV{p8<6fWioW0HHw>dIHE$6*?obwX${cTGVN|spOpmI4J<}Lvx~=&&Hjs7 +4*B+kEpJa){$)jv~t)a!RgbuA22rqWw+rLRWc(vGn3;vwu5*P{B&H{bzH1s+t4 +CrojRLfqp9V(HUjC=Rsj!GAc3Kr>s{M^q4BgHQ746<=CUQA +iuiR4rkbOf)g8UUx;n+4wLmqcKsah0sQw8nEdMY*8$79E(4aA6?t`6W$kP_^=!yr8H)Vz$DjNhr&R@v +>MEJz(YSKhGCUtb;bry4E4T79^e>)cf<5xLwKp!xC589jtrWIs0pnZnXzm^7RfSG%=>M>=6pkZn^yS( +byD}|HHmp*Z%nGw7f_$<76}f8iia5;5Wg(tG;S|C=7j=F6c83)o)7(go(TZd`s+0+Kmv5qA$m4+2v<_ +X>&C9nBdy2~N0@D{wWNyZLnGYM96OIr|)pwZfn=5rJM!DWF6%RSrm!Y|}8vjvK!~8mMLm{l-*wBp1UM +vkRvTxQ1@B)zt3~xT7cnUTf62M4UDDvg(N@7@7X<;XWCZ%tl=byAh<$8vx=?hY5qtIZ>2a<2u>9avhV +V7h(hi@bAp)p{YO&oA@3BTb4bj2drupv&C72fJWp|Y>SG*+B@wIJbntMsmG(k+>Ck!Mpn@fBcF@GByp +6N8rs{TQc*j-II?ZuH#i5gjm(M(_Ge^Q*})1CxjeWNrKSu~V)a+p=ZOr%jn)n7 +cB0B3dM_HLlem%{At3NORwE+{95wX$4$(6kw`v*oPbk5zC-^py!ntTKX!Ucu2)VKwVQJYdy4-_%)z1t +7_(wL}h_jp(G-@E@yTR-r+4{C_G-yW)!oQW17_g){>%VNfm=PD}LBlaZv$?jUES2f<`$oztN&@g=PUL_gw8be}OPO&@d0PLgpv`DB3BVfPxtfw(ygLJRXCi}VSJiuFGopf#GV`H~3 ++1vP=C7O4Xz#rtt+vXR3(y7-O3sJ8RVZN1)$pclSaMEVYH7J;)oqG=aisd(!h+T`$5F#d1*-`R@z=x7A;(?-EDa(eUxQ^0tr0kDI?45cQQPel3Zjt8A@wMo>OC4 +nksPjfo6h*L;Bh@S5#(05_q9aN_jT^gatyq&pS65X`BQsZ)%ZiQ2bQ{L>0F677V>Z08q1^pcj-*46boyj9`WAyLK(E +P9Jj#FxerC>C3-SF;7aPb?_xK=U>mJX^pq2-bzMPgk2Z3I6=Y`{rd4DU22F9BvDod-*{)McZhw|awWhwkegxeY#I3Usn +#_svZqKbfrahOxt>t&ZS<~xh-C?P2GWN5Y?7u6>r6PneP8yEt+*JZkCHd^nAHFIT`!(LYLn2e +zjP=kxiXaf8MNDn}M%}jaFaqfq%Zi(a1Z8IB(ir!*WI-3t<}#|u($Vk?u7p4>N_ya13Ec6M)HLN|FFz^Klp4SM)CVUo_2_1sXY9K9-E>j_ +-o6S%n^D{wJ-5Ez_;kYqwD6Ov5g89fa41bJX&@|ZY@ISm;&6sstex+x}wabUU +=hG~*%;iS;Q1ZK*tUj$}q!AuFvG_y8mG(=`?&S;2C&uN+!V?nJ-=*bAN%&x(V5X(HHIU~d}i&#d8Wxh +c*Bg8U`SmsB>(W7U+b}$Puxmjo?Hw$S{8)F&alO?I;V0mUX#xh2OGP5yej1fogY#Gaq@Yvn#Eg9`>S! +yOFOB3SQK~w6LnLQ!PV&a&2&k4gE7@iOZy>g3T?!naDVwe+#xkW6e7|Vee>4^~GxrHSsSaQ4ca)Kqdu +;c_wZlfiqXvuACrP2WKshf*GfH2d +7bQhh>6`PS4A8v{%v_WSbx-EHdlHzYn3@vPBoC<*6m%Sx3kw(>%d)%4&$u%sVTM(xj4=GP(D`S)As?p_-MpY +I=;>1Rn8R3kY^t{Vr363|{!hQ}fWT6~6fvXF-F6gGvm=Olh6NXxkK1OA!LQ~}FrpVWYP#0odFs4QY^( +u{DF?kyMT2HLIGi^_r=t8FTq~u^)89i9<@+Z-HvQ!IaIht~VMwyL;N`p{oze;3`UdeQjcqL6-X|fC13 +!KU`Q(1Wlar9Q{RdbRFtV}>ML18!{$%J}ND+MnVGMcX{EQ~M!uVULhq3&5=I5?o?Pp%barM4#r&Q)%O +a}qYWmRC_gR)udlBvWL@uaaa++p8kYmDOBPuWB@7?#;)XR+iKnls}ni8aK2#<=FB^CtW^07x*sIJHPL +y#HsYo@6)>Qy}7n0%`rPgEVlynfN`>D#rjRp?{60kJ#$E*fTo#M=@{9*eAdvT&S{J}qyEkMu3o5T7xm +P_8~G@-_2}Z$1BP!mJD+w>-|n74f&(nr$~YP2psCrrLptO_dt8O|U=U`7PGPf3H|5k_2ed2&CM!j+DA +Y|+tar2sb18q!@emaSar7#ZsU{_(rP75aE!^yI@zJyz<@$(__62TjM_ +Qx^1~DQ*2}U>+6HASRB@0%=lGv+`wzNxfp5JCdiV@ibMQQuhoPrsm|3MH(WvNiF%6=4ObDCM7eIl9@@ +#Xi~DkW`SgL7TDa8Y|etMV7ELWx~s^^mDqZqUeb>XjQbvYfI~GX~(9Sa=Jvxv(}DWO +G6As!|y1)XFod73Dp?Npnk@rZTYkil?)#jD+n5Qql%eW@f#Yc|wVcafi+=`NKvtDxXeYS%`Ik=|ZUsI +`}Jk;;j-hJ5>@9$K+TQJ@!{@+-YSgHcgZyr6$Izj1*?E7S6`hVNThS{LzPsTY6^4PHD%k$P0O5uyI#s +DfaMo@n$h>zj5;EZIXQ|jA+}ABFmxY*2un9U=cn4MrOZcC2>lVh^8cyMwUY|sg=n{CbN1n+GR5yk54(3xHuPLq8g%F^qb*{aim&hSFc}k_TpR)a=%!LX+L@KIK8}Te +@xG+>mP#C;HTMSHcEcQS8v3=_|@e>hqD9D)wNV2LtJ!DBNcr;^wOPg)}Jpn!&EUgvkSP?=utLun9Ic= +?#?$-_I^5Zx^?d;hO<~fY;(T3UoM6z{F_~)d;d;#qw>Bysl71Bb?b*!`vo7GTiK`L%Z=D->ZOlw#N)l +{JnhF>-2!2Du`>gAqZ;aTj_OnmKHCvnbfe^ADLeUo9XO&cA!QMwiK&r|L*e4yPi3(UpwC6STvrJP}Wo7GiQDvw*%HU{ew7=sC&WxX1H>2<)H1hJ2 +c;HL_fej@=RHGvLmvE!n$us47SbeOt04c9bYbJ)ghMpcVn{{9{QD(8iVdovKb3ofv2ic>t@{#qO}4?q +e-<`pGJR_z@Qi+y!~vlp-Rz{&qa8gn@CeW3@{`T=#Q8+#8 ++3T8t%U$HyRt0Y$m2-^MI9HmVLM89hTY)&8~bhUMYG_`+%ALH&XiJs?-lv2BA+SpQjy;)@`EBjO^)UP +^f$RwBG-!isK`{28RZo=l+`4v$vm*Z!cMlTeG!H8UfeHvLjf}D39US7#8@9gx|#n~UOt}f56uD<{8tE(T*t{&@1{!3J$yLxQntH& +2|euf_(v_mCuL7Ad)r)U$Pp=lKDJXAV#=_0Bq;kkU~P(Oj{Gv^GInk(91n0bSimMWd9_yH97Au17C{3 +HaeL0d)nTv2rQ+ZaME1BFlvp%%@;Q?!G{f$M^*<{(5lL^+v*LQ{~aenAtW(nO$)Djc+>3dBT%ihvsOJ +^++K$5kct)i7ZQ)nS-`QcHvu8Z>06z^@P(g|$$$0l)Dfmi}HNlPr +{GGhoR#uOHeD>GQ_fx;J7LrYB~*BH50@H4`PVagay8N-yZhAeB*(k4_v&lW=pvQI#Bhp6MO2kKKL0Ij +K_`fv|sa!;Ab=gLg(ql*t&KL&-B9QbfwS;+&^7(}3qDjXD6as&xSVDb=4kOMd#!#@t-IDq3x0}6ux7z +bb+fbkkKgcJu-9N=)E!U+|Qb;1R?0|x;OYstAbj6f5rsIgjdu7z_gIVXUln5%X{yPLr7CUCR}+D`@6g-CqRkXR8Y1Er2wF(SeEf< +YKzA~?G902KW=>=J-baP;FC5F50pNe8x00XRhygHi)_Q_;e>&Wl0EifZZRR6!VYegv9;jtvUDE&z*m? +k-j~b~q2a1Se02)2d_W4o5nU;kz2LHCUK=Pi}3BHW4ZfDqW0GWEhcAyIRbWGOECO-cSW%wTnu +PVbs|tDeP{@JAp2Ox(ImDkry3o!Wrnbz)LWQ3BW3-MWChgU>as!Qb8581k@6sC7>3d)d86<%FIup>ANbFB#l55uvCuXyFSqftN;}jqM~A0(wZs_Xom`iSXYCBg;4e7__7jUPFTm4PF|}@8*_y~C +;zTLojJ}6XSM!2KiNu~@qX|5+<8B5{@10;IuDMo{@=4j1-s&h^4S(PMS_xB47QiU +HlSk;OKB^B_|-Y;PNqpJ;hD)ae_e8UBwvgntMkR5ohd@JKFkh(eJa?1jtSpkj`vSV=sqqX+ex)PDz7@ +sm_C#qZD%~YNsb2^Y^OTWKRd~R4K>+-kl4?7C`&>9v6ZF#JI(lan(?7D-=)D9&rwP9zL3r +VOy|}wyiryJ+@t+=K#_;EddeP$U>PW6Ix%~d>QJVDV7V=-p&;B<(`>T7#uFkGLoz7mKp1-a33s%tyd?|d`xe%QQU47bzCqmsFp?A<@>|KW753e$r7mJ?@n*4dlnMtLCa3%V>1p=@d3 +=eljNQ78k;YDs29Gp#FNlr9>MCe*I}G<1uU@@>|Ni{Ff4=VDyqdeN`wFJK`UTFYD+_g%AQjk=ewj}PH +%#O8g>rLPkI!0DHOOp#s>>yIxUGrazW4ihJ!8O+dRpnjkpOvejqQPld*I30*+gNabRAy$?*VKU@(6FU +UJYD!=IvXF>S~Z$Hn-w~Ap@VJfZ9pqkGUsOwy0YtN8dYbc?LnTYRBL{+Yg10uvYd~o^n|E(KfzR-^EP +!CrdRQOpe(}o}Zs5H=tdQ)TP^vGPqaQ)l&e_tRK|Hwmg0F$?U@jd?Ox*{ki(~rCd+>hul9pJs9>>!C{ +48IDeAMtCuOo>P)RMdqw{-kYV3Ej+UzaiS7f*j-79A^lju}%5vTE)zx(2I=U +%D$@aAAL7IoFBX7r7a$&2Bd37yhi=RU4GUQuQ5s&s3J*;C8=;9OFNz?Mb@!*ufLWTw6`ai7J3`tQZb2 +Kt@9s{uYHTAuStnsNF(Qp(WTv4|l}Hg4<&d2}z`{+vyf^@laO?JHrMybIfQhi`a83>Y+L2L=t%;$WMtxKVyN2nJ+j+ADb^ooY-Cn%g+Wzq{{;GBQBorU +NUdJHbNB-rWDjV8QSx12m8+Q&9^F_vfwz;3C9N@4mjBkOip9!5K{pkx8W#Jxl`hy|c#k!}y>UehTZht +bQB5T`J`+T?)T>EF>_`xi4VLe4k<+%GithOx2cY;T!%i6ppesmUgv6+1Pi5q^Wz64U=A?_mc1n%~E1Y +ms(jyq0RtJG&(he;*AT3XRJj7mandid68cJhBvO9KQH0000805+CpNgfPsHCrD502F@!03-ka0B~t=F +JE?LZe(wAFKBdaY&C3YVlQ85Zg6#Ub98cLVQnsOdF?%GbK6LA-}NhIsoD~`Cb^RQR#{G2ubeAhTV>0+ +OUVig1cww>Ab`a~l=gD}J>5MI%nKClT~|`cvF^O$V5VoLr{CQJ&dYqsCX;znHzl7;Sh6hgvS!h=%G0L +i6Y+h>X31?*C3!YvO_s#@j8D>}=4F&tTU&F4Q6$B9a?7(>UXH8eP64X`Vt&6Ugo +#FQUkB+x|qai!ZVn?DbqBWZf(hDIDcHJZzcDaprEYylxNUA$rfs%<2cW%I?8H2)#-<`A*+fg=Ev7j8O +5-#YRIB0PLg-LHoko>3SP!h#k(MVNv@hd)g`R&?T4+cy1YNwV(@W#9 +NpKvf)1Pjv$xcGT9$b!y36P6(15kg-sjm!o))`>UBH4Wmd{zc>^WensW?kAR$p^glzc=RD7PGR&;$S; +*7ZBjDqi<5;rN$hLN4$32tB<40mKIg(E)Ka*fLT2EfCG|3Y4!)pW?M8EAUdi%F)xdErqM8G|-sP8OcXxMhME`j~{~po5r_{7}hW|c4qc1Pv%h} +1v?g;;LieJvoPU+vXFP{+#eOG^pwtd~UuiGB$w#T~diEewM+n(ySr@HN#ZhNNNp6j;fy6uH-d!gH2>b +94NPZ&tHGGbND3uLM!nOjI}QQ{+h|Bn}Fd-8?jYI&|&UTnU)7i!E)1?8n`d81n1Y`(f9HReb`IaV#ls +^w(!)t#s@rwYocYB^IaXPd81h@zqT>kQQfX`@NeWO3a@C*59MwS+2xh}pvbF))(nqEdq4hI!65ek}M?Gi2ztZ6TIudWU(N<~1A4q3{xK8+u2IZy2Id+mNo4$eb{-P)yAoZm>S +LA$YDscaDDD+zNlm4roxRll8B>>sv=pjBgHZFhAId_jvg_nKS{*ef~Q-lYUNIt-1mdM3E%z3xLx)cIV +syN2_h$z4xzFUG#Xz96;S&S)=8B2gd&;YcnMaCBFm0-(Nol&EK&{R~h~JEF)v!N4$7^n<}SE=_61&Vg +s()(A172Dhwc6M;kJ3R1J|U*d|K$UnlVka9L5dYwI~VJvTGqxX>s +`O1RibC$o5hc@z+OY^{8`STmcZP7Y@%3H-HCX`DHwQIINaO8+}Y@s +F!IsOg(_U|k7DvClMeiTE_AeK|ynCA!O|4{4-jp#PvY&psSw-bSvF4s05d3#?J5SYdDK(vtZ +l%=vW^Jjj}snahg}WB6}y!vrM>&V+jLeWd}e14CAVCK`_R7x%fE&!-x}{Es21B0%i}!eqydyWCYsAf4 +R6g|H!K%&niA(d8s$L&EBL{4u%DfZ%FJ$vsseO0Yu7HB_IxsEpxOU8Jbdr^FYjszGDD3jc`UwWqAX~^ +J2|%O|6xH4J-WPLv|LWayg_sucIoe>r$_!hZyd4jP;iw&tupIHU|>6$)amvSYy@6=n*Xt9k@j1yd$jN +p{5fAgoEzJK(7_X75cr2>fSS075Zo>4!K83#n}a{fx?LW-f@%(`=rKTgBnFa3$VOZxFJE39#XF#%O3l +&1@ChOvVh#wT22Vy&wy}5QRDRhl!MYSqwA=gm-%fn5X~UCmp~8Hu&WYa;>P3FTv*dTs{mM}Rw?R +x=M>hZ}j=)zlhqow{dJpDApQnVsi!_Sii;N<~d5K{kl4+xg|JJ}rTpSFGkm(Aw+&E90rHC%2Nyb@?5l +Vm~*Q7m{2?(I5N$X=Y<3GWwfq?dQ_n+)`J2r$;g9!lETj-EP;BrZ^<4Ck|d){5L?oy!utntxn_C7C{0 +PlD3<|Mi)$}M_Z{tJerr}x0>%k(Js9Nv=S=`9;@HDL-hRQRzNqKhL_(IaNm@G)a=!SgA2oXitG8;UUoD+%`#<4r?@)E7}XOL;} +1d30BgKKz1x>NBn;d0>2{koHIe^T)QGio@w%I3~u8k_v`pJclQWS +&tLLIlKK}G%jeqkk@b=qN*=Fx#Kw|}D%mFVeVr-yF<94N%=8?;1znC$I*x%YIoLuLKM$NaL3{JMKQNtNY;YVmxjc+V90E-S+NFTn +4LmZ;IO`!-IKI3xu_?kPh|fL-%u-pn+at0RRXzZ5C>YDLc&;(OmXI#aXZ+5#|d1tkvUt(1UOmsRQXe%=v4?p1o>J`s$3|EQ4td|7N +Us1C2RdCQ}jm7GHoxP(n?+1zFatc) +h3TU1)lFO6PKq}~Q;euMM#;xxuw|j!pWcLnp=oBTTN3ZbF +$U9S31g%y7J7 +qqi`x$`4*bh}$x)>h33-vIP*!CQ9*j(PO9$N;@gI4^Fc8|}@Fpp&7@ykqGOEFOO|n3h25lJ2X8O*G6z +u^_pTgrjtCOtZTXv(wfaEQjb-XC^rsxlB1`~N&(V?oNvhEKYNpKE_UEiZvAT+FD#Zi`Fl +z^hT6~hkh%B6pwRG*Y+JdYBw%}bd7fD*ZE|0 +o#m2HKL|HCvX>4AQ(ZCOBGS5;K#+>1P$4$fGkcM89lu>Y+fLcofg;*YAG=P#&) +BO-DzMEF>eHRP$@!kDgZ|7*h#V-45nS@Gf~=x1$AWllh2*ht$JuDu}x(|LSb5{m^+Bk$+h!{BQi;C==G$#Q^Y(Pn*SL;u8{8kRYbpDZ;ELa8GIJIM63)0*X18e4g0LU8<#ysh44y4?WA;!__kEK8R(!C0t&M(x@7pzM&*~wu-8 +32l*zBF#f*cXf?3BX)CV$%C>FX62?UGA|%&6FW`suo}c$_!T|2t4C=wG#o|e4}C3e>fCCK?+F-xDW)1Dq5&u^ +$qpMtG%+H|XZsKr9(q+b@Kv6<7qh8Sx8Ej5zBs*_1 +~|t9ld)?)u%y&GRZ{I;=VO&_?b!{K#slH5^4Xej+AiB+31xdN_6d|0ieOnG_$A8CU`^U1347yCH(gDz +qb=2fpyFq9vc?WwJ=J31|_ZHWyZ!+yIk32uMc!+J3zi2<&`SjrR7R?)Qc$lrau6;P67tu{{_ho#KeWjqV6 +6~og@dYfTULgd7U-s@Z~6$sLn(UwIc6?5Y1a)Q9M!f|^uOF+@*n*=5i$@peTwSd2HiUMMB&4#NG_q~8 +Wv4Ri&(sPLiv0&ctY?8BSLNh~saZOcX#Cuo}Wsmm67sjgGHhYLK*YHYV-06zj(u0z? +d#fPmr8ti8~t8vX;E%G|Hk=D0^q{5X%~?`Db~-=H&(QqP8y?y}*x5IE#BU;%~bCV}zAOjOQS5uWsWze8Sp8b3EoVG}A;}E#P!-3loua7FluRQx;fegGw2-C>%|Jq?g&L ++z`vgH4NyRHBYYB)WM>`J1k~@lZU}PSn(aa*2a0J-EaKn|4$yYIq_d@E&Uze9OPf4$es>f-@aAWRZB2kQL*2&0kRYEi>p +mg%!(YAtUX7wa_?C$d~K|2%RQmjd*8HI$0qpx2lTHE+VezFQrHcxIvaP+nR|7}6Y%&Ur6;?O!GOoNbV +RA3!1g63pVfmC`M{1Jbi5P9{1m2nL4(3KibyL|_EjF0XAQnn!dazJtK|vZxRBoq5u7*z!_NV(+E{$u45THmEHtm>XwUZ=x9P +>k^sY;#``7Y1a5)06~-9^uqJb|*}^rwGQLtR{w-_Y8Q8nR%!IFv4KO~o%{ff8nuCH#r_!!Hw1H9{i6S*7;GR5wwcWkL^oQGvo3x9&bPELe2kb(df*GX|$L79O0bg)JRQ>w +M@InETeMeos#zNNy$+)sGa)5INS4t(ufFu>A&MkNc&qZ|a&ai<)4IewZvlV?U~8p#Ub{WJ*f9LST2dv +~FBila8YHQ)X?w0Ya4AM`?m@ecrU!Ei}hGPD1A(R~LY7BEtK3|-@IAA+O +m^;HYz4o3>-kr*xNccNLzr#`6VanG+d%WL5d%Pcj1|5#t4ggI9`-f%lkFN%-odysydSQfBI3{-`4|V@m7l(kEWaY8Ld-Rk +gh9tfL#Titt5qO*R|0d}RQ_K$Ss;0wPkOJ`02KJB&^eKm6Mah;FM{TMw?8 +)`pN}@>C5GFDWr!!U3lt?hcL6H&szhaeW$JG+5;^CQl4r!L8gzCEXYk?~)T$XhNRK%8d3NN<|?vwxIX +QQ6XDqNIfhxT)#|!>dZxB!DJ4N#IQ~(7I)z;;!~P7v3!izu}RQm&foVR*b55pSTebGPgd}dG +S^i8QNB8!Ctwg8O}xh&^|7Ug94Xfyod<5GB(%v)6QPUFLv`JX_7cQyt6e`FlVd +OU&hIk)fcDPZ>99A~0$+nv8!g*v^Sg|nXTu!> +K>@plbw!)1Xf)v&xP|9cNb-1e`Dd +Wye;qog`m%i|n*Zi6ATgc)h?uH{YO4=iFIp!@m5E{da9EQ?*1CE3NEBAhZqW{~%@S$0BMcVJg<;ZK_u +{$>`{26MbZaapTIKJX3ma6=BGDKjE#qsbwTB95V*r4s{!_`dguLXux)lth{Xx? +AK;lT;v-ZmM)g{&rBDGM{JQ`L{W9I10U*^lk~6Fo)EpQfR0HzS2Wf{Gnj7Yww2>Z*({ga)TN82~IU{Vo +X+X?A9>*7#ABL+0E>qJNw%6&c2FJK)je+%iPjeZ0QB`Nq}r9Ib`G&&dFpsVyAMj{xG>;%}S(p*3U&Tj +amwRr1T&%FXHxzP5F0xw52957qPnLeN+wuMV{l7J#cQiqeW(A=N)Ui~l{^<>c)_(ZdmALmOdof~>x5m +9zua)4G^zw#k<)B;5iJ7!f3W+LzzcNym(99`C;x=P3#V_xRQ`I +B=u9{se$*eEXcGSdhf2p_>3qpe!Fh!Ng~HfnxGN!b^R+lW;N%YBAiV(}u6ibMYP +T^iEAMYe$u5!smH4KSjQWmlT8=~$!&n)XJc*XEtRmg2j73mR@3&C)^)nZd4*Pp}e3Tp=Ysqp|Z`UWb@ +su@!;Aiv(1lkN9JYJaMkwgygGvJ5^lXw(B=B$e2+KvEoq)a)OMZ8e|*j8N;}_j;ixAS}Y^))G>7nD>- +#UlzQBKv5OL!#_c}R=z8kbCi31aV!^=y%E|$0_(qL)cmXR8uxIBDuMqO^6VCTbaPkGh(;mKCafG)MZ+ +l_hG4V$u_vA>tUkiD7IbdbpcaXZV +1LTL_)$j>OlN(90Psx+qM?5pTEr=LphZ4CSCQgl@f~SdS~|9cAW=35Z##r!YlbnINFB-|nFj!Dgup*` +SaR;KI50Uv^Tzs~`1!gcR-d&;ZGOU{!u|O2QY^z!Hm>cmCZyw7JJ?xVFYkgWj4>CYj(m=T@7C^^i3(S +{CQ`Eu@oFU+VC`(~n`}&t+NDgrUqNzJiuB7#laR+I2`Q3e!9A(T2@vJb$s)_?l@Uqh0GcC3q0Yf~X3< +t;7@&?YRW9D~%P>c_nkn%+IN)kJK(i&UVyV`~(6=3QxY17c9 +SJ2VP$lKsk08#9*KD}T=L?gol+27=M!hY_V8c$}~Vr9|MH8K1J4&$ejj8*L0l#QuR@ylb*+r*3`u*_H +qrmbs0+`Y#vs#Wrdt^ZEgwwmSWCkDpxU>-D*TP{2lzaFJ#?Q)yU7P3O(&72Tpko?&H +DX54^p0v!Ujwi9H^33S4v>LguM4v#LQ=)0ahpyJL4Ck2uxLSy3+Z}qQuj?ogyE-FBO;enudQ`u-{ +&^n{vc?TwziI^dqpohSlH{hw;STQ9VCXGo_ix`8@i9}Yudjxc}-M{CQ?8=`|P3t?FUIXu +qSKOW3O59pI%DXyjuepKkLt+Z6m?av9>2(^H=f%e)J>{FomA=X<*ha8`lT!{PvENWUqTcY5Nd`e#Le- ++2%UF5AnRe?{)iC9MBSU7s;-nOG|p&cG}kp(zP`94T5zOBKq?stBY-w74Y33kJG~ch-QSXxUf5^y +qeW6k7K@PQJhI!%JZFWqz#1i49knt!Au_`9xCQg61n$~(8FcDSsB~ZjHl!TGE+3V;N(DCNWWIW&OFr< +>i@`XEAN;eFRMDVyo^wPRh4v6r70H}*T{_t*$TW@9o^pw{tymP2Ch$QskYk5<-*a%~S6db5FWVxM?wL +=hp0f45xY=Q{8dJk+CKY2QHGLZJDkY@AfM=!4>?cFQm7uVNGbR(9iLBkHrU(I$=DBlQhLcIc)4!u& +A2QQI%tCAqhUvM9b!wA)Ei)HCx!UId9A)#L!qNo22P)h>@6aWAK2mm&gW=X_GY8Jm7001N_0RSQZ003 +}la4%nWWo~3|axZ9fZEQ7cX<{#5bZ={AZfSaDaxQRr?Ol6w+cviUKc50+W@@>$RHwV!M_OkmiS21-`^ +Yx#-RyNezBCC*tSM3@NIPnq?|#n#2ofa0mqfi{aypGH0SCZ&{LaAv2#f=NMy{{NQ5XgE`kFYixgUhYy +kWi@h4fndeMD^M&S8%49g)a$EZ?Trt`pM0blIavW27;6=A-L7>e+rUV$M5B2un``Vlo2%#6>ONb*U8s +H71MM^!JFyKaVWF*}99Oru)B8?;Q*Dv!q4L<+gzo$W2E!&w +mA(Wrecc<~kv!Bk(N{9X}^)4233dKTma*_O5Rw1Bs7e+UO&MPB~OJ6(QJPKJDP;(|Le0TA~_pk8lH~j +0QXc#zDmbrk>j~+>W;9ul~e>srf9X@*W$Z}1_I6dA?=MNeT{F~oEG>1wgN;q~_~4*%UxL7{{ynG?q%QxgEfW23bH|DnY82{4C5EH +YhC+gM?72;nsFqsf#L;7kH7^=zc-k$Vc%?kK2js8|I-y$e8m0WYy|sB0@maz6$51c65kNGT0PV8$*l= +h1gzjv|aBKs;q38j&*0ENgkCe@8SzDRBTETwWcjS{0grC26Z8@*f-spr2^Mw5HTnHR9fJT{)PnT0I8E +gzlI&BF9AlO(I{g|E}-PMMV(K%<+Iu+GiNPOO+M|ir5Ojqw$Pr5cmPhmcmCc_D>@OEH<7hFnwvfMsqs +DddAfeF;JhOM3Lxd?#~CuhwsaJkn*#v`CKt1=+behDk=JhXhwgGW;ZlAL$F@NAmgy_=)0`ia;+Ul9`~ +g&;~Ak2@HHU6e0qL7NZKDoz_niC?m^Q>AC*;X-Y8hj}# +;kx+3W<-;{GJf{B5f7<3HD*#3V2i${iTo~Qq6Ln373cN(*bFj-h{^LGc#||s2PM{00Igv+xHGaGIgL9 +x4V=DmW1C}MX{B^Va{+YY)Fm{4bDP#qF{hlmIujrq-?Ci?C<*avg5v^7y%*n(GU$?8G5YO+&9Bm993D +c*mL#@^yCD87#POrH}J`Wq)&%OLI&CPpfMB1r!+F5NjwFh3uZukGzF&0KWz+!pbNf=jDdb>OI{|#t}= +C&Rrdsa3izRW3;<0!G2J1C<8usRhGRb%dcfwuv4%X-TNp>pXkoi|&=u(2pGGn)_$&GR{(Y(u)CEos2F +LGCzdAl9-<~L3g+JhHfSyADlU&<_wAeE!_2l>*%N=SNZu}Y{ei;vqu`K63zzt9R2%X2Af>!e|52NNO1 +?*w|j86S~GN2>y&NKgxCgz8BM&xWGYs<0hj*pL@Xk-Upf2ENfNRR(^rmgZsC+@h)m*?6lUzb)nKRwkc +)%od}zDmZVVK(#!L~Jx1T=M?DIKryu=V$T1=lJgv{zW4J;v*{Xnx9KjpUZFl)|S@aWX-=zT7Q?{{G%< +cf5@6&NLpXWZ@z3x>q}YlD@p4s`OVjDX?-ngK9{tf%Wqz^rS(GAd?{(Yl;51TrFAN6o=I9~@|*Lvw9X +T4I+nx)qFv=74WFfWvI3nRb0d^7x7_#RBe?)~7FX~2ftv4D)jOz?9m0&qU2Z`25!{DcwDy~F4cnMZ(#Aq4#3DMY+ae&^FY2n91U +GYqdqR)G%=3yT~>$}5bV$VVp_@IT##OU`QL5Jl=o;gHdpWBIP{89B{TW7P;E?GOXnbZQ{xs3?oV)GIU +Tii2ki`Qo$=X4{^JVc^_EAwA)GF+F+UF3Wrz)Cwjd?HwDyhEmBxEnL*Lo#RBdZ6?CU8xb0goq)wT?Lth5-QcsteBYC4@gezDYp%f10V+Z%1u-?(4E-^A9uk+D +&?!_RUJgto^6VpsZlz7~uHR36nA3VZGop8|CF%ryI4o313{0dMHE9_M+WQf-0*ogkp14P)g1LN(=v6dDLGgR)O@LP?fS}$WZA2T +q{);Y3Lf1_1_zFwjH7F$%m#@$-sOZ{Ev;fn +=;e6XL52xR+v_S7=F>U`)Vw(O5;;08PXlDo$aF3`aGa +px;9VP|m?s#*Vw_dLW46fB+sL0E)7O2j}aO`gNx>-9#(+HiI*tj>a!&-uwPPGFQ#0kVcK73pi%-PHj& +xT9l2Jq%kRIPh#20wWv)(g{V3KygnEOV=S8RhH_KMR)Yzg4r`cO6Mj(vPP-!A7rrc_2YbUc7Xdk8EnaqV&Mv4<~RA2&Gc$RMz}p( +VOB9J}UZ=xfJP(k=c?u2jj69bV`$c|pOZ`HTv+6em!A#PVB+7|*Zb)`2KqyG0{UXyvUNf2dxgcE)ib? +rF5yA*Is-$W9BJjd*$}q4RAm9pK?lz@{o9zebq3?JCdNEWasb?|65n>)2^dUYpo#*bl{lwe3gDgZ!E= +=Mf-vVgCTkwS>Cxogxsp*}2)Qc3Y4_v&Ok&$~%CN$6ds*op=R_-wQt?48nSt!SRfDjJbS7IZ{lxKQSk +TiKLj5=JTU`qXyqkY2vS(+=3J*g|VLi$;_c{NZrL~X^G`SmX@(0XXU2_qhr5d_F<44;1SO_9_I9mr?Y +tc01S-gHkwX$KOkTJp|ep5MI7;%d|az%fj0DX-| +Fz-Y9F6_W1G{A4sRzm>q!L|l$yL57`ZEdg2j9Gy*4@+aMuJt@^u2=Qu{peM_>}jLwbJqkBc7o`A1ie8 +`&uisIHLFDR6Q!?HIyEJ?8n}K`3$8OWxQ*tg)N(OQ2R*Dy27XpQRdszvFRIguxy9a^buyr=pBUi&2%e +5_pfX}5;3;oEU3|K1R8`H1KNSYqvf6X&*7NUOYEP&wNxZLNBhTI1F%y) +bIvu^_F&rJt?ky`>bRWZDpb;E1!QpVEOPjZUIq-h%xp1k+IP_cHj7uh`sb@_}W>X?Zy3d_?G)FaAY02 +*$qD%&T0#YzPwlJ2KePF>`@lg8$faj`&v|A10-)+>*PWyYF~4xY>aBU#jaf#BK61Xu(QvWabuSfjKrJMZdWp48O6G!DX*)`RfosXvSUEQ;QY9+DsVbxx^#6GO*!>Uy|)Q43Y39FWc<6K0rT3|KoKEN3+8Q ++|mY}&}1Zh_ND-#!Fx+c=sX<+lA{ak`0v)s+(eS#@O1?Q&0Sb7SVU$`0m|fi!rPqAcX;O+Vj{-t;>${oPNmi+t)#>XY~zPU0^E&iVjiB|n-!6pZ| +(T%$JtcsN1}IMiO@({=C*-Kz2j+!_TlG-<4+fme>>dSzQmcpD2+n}(+ijcSWZ{2`?8Gviq*Q@EZ8zrM +454zhVamRcUz*z2l7!0D%M-sJ8asoEgJo@6TZ+^rZ>j}Q+AAzHDzb;7a-mv-sX3U0T>r9Hu>4**#D^_ +k4mgI*7M+W@_dtRJmp)%xW5N^4Ro2hO~Lu68|_?nYFyqkU4Sj^7=ogBoGlgGmatRphc2i?ttZ)$D$Rr +9`Q_`cMk>68{9j8CP{YHP?UCR_8}l@%zpX03i;HgCo3bl;5nd0#dBt%abTc$`t*1!qoBuzBVkq-47%y +86tzg?wGO*2QOyTr1tE^6FM?U?v%=hR0h1yu&S(Nao>VW%_1Fpw-^f9uNA8W^N+)1yxPb5l&GD1+On%*cHk4AdAgdmYFMiUfJK +q1)VuM46&TW6uTG8^tF^u@M(AAuW@6Nfm;l<_yfE-RN&Al#tTRZKEQyUG&-<>yGifgK`$QR0EFgtwr#?#)Di@-gga?m8CmB{dk`ZPNJMKxA;M@!jXnJI*!p#=oP5Gy0uz>K{w;4HZ +*3ePpM1jk`OO?mh@y@#N`Uo7wl_%i1TK>k4O94OO@??^wEG7iQ)_d9b{IGKUufavpS-QV?I-2=m>Jr-7b`M&%`v!ow$#}MXSxO2dJdAB|VM^mf@_zaj9(+D2pBgWxc +sU1ilH4%-e_L`e^!ErRS2zKTyx)0;^D40n#|o3WmASP89;VDx*6(Jz=WKNbSdYl7t?oDR2$^|GZ9K1a +1@pkSC}ZME>sMYvZ2)oH!vUz>Fr0j1Ntlhz^=in$X0vwFB8fjheLW)L3i#rgD-F!25CE)ZJ`LiJby^R +!-&@a$L+iwP7+0&Ex1NL5j3?u?cK9;0mPYif)QDEfO$|hjg7bX)5oP41_v@((ENhD|dpO!29C^NgBDQ +HPDubTFXw)r=AB!!DGO1TE7!|I_UwQ0km1W;xqGoyc+NBL*+f!`?u%HWt1Zz1+b#UA8YMa5kM(H&Uy; +d{zyO~QAXth{ctM*ycQ5rU`^4nCBI-9??w2ePnLHn5xZY*N)ou>~;`PVV><#fMr{cm3BACn)&oh{>%&= +3n(iWpg!i!^Sx{FGWQ^gMKYuk@5HY!Q +C2ZlQ(CVppzI98Jn%P^NulF)1M>QKVRSoui&=!ipxx>S!cu81MD;GOV={i_4$Hren4Ij>CO+2z+8@L! +5bVdXSrmfzf~|**d?1wk5%dlNcQMNaLr2!y}+);pdm)bBLcW;Bz(T4GtDq@V}zc96!GnpDBJmJIKGVv +y=q2Qp9anFa|juJvyh%$Zn2PpW;>;XDlnOpd_ch#lLOnSCa#njD{D)6Js9TxQ_M8hDtyB9>s%~7A&N* +^qYo+EI&ZZfm*0CO%&M{gKMe7gQ6W?@}sUEY1-p^(*ndflr#>fy5tD-hmL$us56(Mm9e(vu~Q>{Z8uJ +g$VVr|;sAVR=I!D}L{FW}q*(R +G(HuQsGtm%g8w!s6tH05mFyKJfG=Kfq2lO~$W$7R(%xZqFLa5_M#1FJh$WIvN-HCeJPZmV#-7^jD^6d +JyOUl{62=j?4gOSpx>H_jwBTtv5)GVpaC0ix@k<^}W*#Jq>SefRdgtbKz4#piXe!OAyj+z--!Z~tAWU +Dxk;39Q9>e97HGRjRJ4U+>Pkc4w7**m>mVyX|oTwzDR(J{Pe1SvoBOm`($SeYc@*jA+#xxw~0+x-q>; +yyO&bh(vR$b3P@Y`NH%n-|kxFNWpG~%LmtbxQ*s-y9kfU7`KU#j|*>?ZfAjYSviBruMx!)tJzN^*BW& +NCqHV4n;-VH1NiU(hGN{C@b2$$Kn5DvwK1z}T$|r#7cU>~`kS#albW4al@*^{b-dCpHf>zD*3UGL0>i +j6B+*K;wxk)vQX7Fv)u!SF;C!9+Df`@HOryxV@UE&>k?UVn-4&JIXAdgwXd{i^g|&NV+@{-2#MQvtmW +ry%<8JB@nUZ0Z{#JEvQ4JqB-ZyaR4R;WC-PazJ%2?d|4gDQQB@x%FnA8mp?WJNiN4b1LsQm4meTt$ww +eC`_ZmmmAV%|-g$~Nb`nd3a>xXSiA|K24&6}t}cDen3;BBb?;fg5#=8~pr2e0K5k_eR~WUwj6JgN0v- +iWYu;Y3O$Q;#05tx?wlk;hSYZ`KCpDiW?W>=1Mm&;#2L-U-M14|Dua~KhPWmBp=KwAG5@{x4$b0~J3HWM<%!e^r53_t(y5QY4P@2hSlC;JoRoowZs&2k-9+?!8Y +HL}|*YTSRzzApT(4aK5P!3Ami311f0)y4Ec8%GxEAxo`OJ%H6K=mnBZT+oG6!a%%Wkr{~U&M2B4d=i4 +AvQgGQF{i_8v3*2XD2Fn6CXOd52n@wQyXsW#*68lbE_s$k!7ngzqR18nPUQ5y5oIJZz@>2voAdLSolD +(uu4_yv$0Jb|3=PC?4hKGk{(Jn!mTwxNv#QQHiHu0Q|e{9^W3xF#AiOpez6W_HC?a%9vBDPHv9G=Z*r +JMo9Sj=8Y@kI9|D7#%*T8D>!+1VO)FbL=7U+VF9qaX!@n)T4fLmnn;vf3!%g*)@zz$`3O3NMwzXnQAA +M|RwXIq}^{Z{#`a8SY_K@A}4y1+F;!OIy&<=2`4^&EDZLC9&jV`w}^~d{|BUiw*&yn|7xLa6QrK*jW+ +iE@kCYRfKDCwc3P^*WMU5Aod6Mir$+Fk`eoXCEq1&n<0{X0%br^@{7D0240tBd7wMjO(n3@GRieBxx3 +qwGuMbD3UpA`Xv7GTFwkWZBvN@*bNjBX`JulSmGH;<7q#NM1GK9l_!Qr>Dl!ls;2{mdgcfwCP$X6 +reh=U9^QYowh^wm-dz3}v69{;%r^C;$w1xF=gXw!JiA#oJmz7ihV^JE$=r;(}gleKH&lfI4ZclB8nJ{ +}k2`DIr;{iC_nSp~}4bgfNGLOkAHC=M=gj3>0u1lsgpd>K)T|VK|^yF(?;@*j*9+rLSM_w3@dt~7s$< +;*}gHOvoBgff+;){aU*hFB0g$vbo5lKvJ>YqW^t&q-@J}(q=+YS-iW4$9s8>sg0g +PQPiF53>F2*d8>^BF|oSo92Vg_gG$~>E49j?Q?k?*7L9ahL}R0X6Kt>pLVDjZ%4NlSj){)z2ScBL;Uc&(PovE|%HXDmvm& +8mMLn78b{EgG$`*nn9!zx?OyWqd;}^AGZuQjp)F;Y1Zu)%yD62F}mn41}r78SwKbQ#>={1*B)4BXvJpaSvey`GJU(Eyr>+m7@z)4kleAj1|uYFYA+ +BLE6~b2$r^;qFodx^XXYbD8V1=$X_#X<6G~btZw+;4SO#cI(c;=XeA#?kz{Qf1f_I`xp2Z(SxUOx +;3zn2xQO`L}koGupViQT?fM7LhGajiA;2<0G7NA&s>e@T0bYcKTt;RONd*EL%Pcv#FNbzmtJcQc)zTriqwz` +L?m6^{CKLgOS~hdh9hoMsP)wI~wq&nz7JJV|$I{DTiq!C8B)2#Ti*)ftM4V^v8*F=$p?gmS7_m0EP&? +qZ@lH^6cWS$fv51vArSgTx0=X*z?!x}(gaVK(9-_Uy%Y6Qm_dCNThIVLE`LoH-wDriy&qOG962j@)b{ +1O!UVG3x_J`SoWW4N0FFV9-lJKjE}zp|~=jS^5bTMckL&FkZu*7@D_WghP#ePjk_>G?_*bNG`QX;@@abbP4ImehTNkcIvUzLDluC)>eIBc7 +G-^_&KWlXL-E(IikMGlJ!stB{z(6UhRlsTB1!k$~=Klzg~&e+GA!-!CHOKqg|Cbh4@F2E{(^T_Tc7IM +KVkazy03`f8c8H2g3RxD4vs>;CTw$VsJxrrj@HlMWw}Jv`Wd +f2M6Mc23^AAN>bVO9KQH0000805+CpNywyq{s~9`0J}v203iSX0B~t=FJE?LZe(wAFKBdaY&C3YVlQK +FZgX^DZgg`laCyyrX?q(vlIC~+3XW%IZSPnv9wH?cr+Zgr$+o)XV{EyuuG-pUW|GWOGLy5IqD>uRIq#*3riK=ZUoqom-P&ue7QAa&(+wN!zh +W?ASL@%=&F&VlNC6qGsF^r;5*o__PJMiV*DMse=zy8ZpO>>f;C&jb=@!hjdj}7s`BF!Gol9FT==I +Te@^AaNlQ`xu7P=^b{glz6Wi!?2ZgFIZT`4Fec4hDj#l1P{|Bk^SR#8eyJZIl8irL*dvtGbtIaS*199 +W}S5U-Vw5bpz?5w}|3UX=Gl6Ua+s72h`nDtn?B!oqLP4Oi*LutyOgo5{IVzI$==VTWgY?*BqLPyh0fx +#dnw=M2V^=I8f75&W=FOSgoRkr(~tfn&~eJxAi^A!+3Gv$7!xC+`%IDmItY+_Q?aQi +a^s{KWDh}pq;#`HovYoZH>eh6TS_n`6{AByccWS>b!@N*N{b227R}ZQEzoYiv(>IrIFM2^5=6X133gz +XdS`Ri^>W6vNTU{tCece|6;@MWl9>7ALuES!b>kQ-EXnCi`cBpjC50_;-INFqV#MwJvCaGTGdQblCn? +E~r*43spd)+O4hK|q-epmzAR((|qFvCy&H5wf;NN&=l} +{e|h=ShqEUy)Q+>T7Bb?0?x}^dX1&oP-HvA8PuJ^EZX2l!|J1O4aG-f_X}k638?{&aBMnpqc +QrzL$!Z>a2Jw15lkXI#~KOn9rYS?RGRT@x@_XAj`HolhogU)PbdDP>c +7v4jy#RFtq>FVE6r8RB$3so#KZO^UEUf5Cc&g6WT3TlJ*L6K`>qCtH8LX2{X&Tz%iaHz +nTF=GZL_L(;z{3Xc0kwTqMcq!C-X_Ba|v~KPoOH-k;8raiQDA$p&d06e17EzY#Ag8DH%1 +$@CRiyn&dbUeRNyb-6dg~tYEK8FxE%WUvWOJhjV4MG<1yL)H8K!&(V_Vy(gtNoJFv9CS{g42`+BI5M>3m1=+*RHww^|+ZJ;Ne;RsDF^NRPsVO;y|l_2;{XaG? +)ysx9<3`y&`g)tVP2UffpQyR3`%yu7En9p2Um(`2BJ3w*B$Ozv%=mE4QoX{sZkr4CCL|Fm0-wT^y8-L +_VnO4I6ODG+nsQ*(1A&)D3PMiCpSJl?5YZE1Ua+NO&%JqW!lwvM1WrY#RcwFOMmUPVlHr{cJ6aeMW(r +Te;`xoq2m`{Np`2lUGxFE2@?M32)b4r<=MA~b&oRdas&sFoT6TuEwzYRKPlNlvvr%2e_Ll3NNVDYCZQi75kfv +YZ_UiUXVd`e}@nCqT{fO##zOJ;lP6HiL6 +vn~h6l*c>2Ur1@-vF_a8BHM^LO&$hjIKM?QJSo&X@yPW;4W+O{)|4yr+YS=F3uW0Y#?d;suC@bz)hN1pz+vKW{q)<&$4ZLbcXgF4t +hGf^8(AuV*EVOA|J2=>5OZN5AR9&Q3%Iq1zI-BC&?%#s$ZG8J^%2szYRVz%hD!cl<&py|B(=O}V>?!e +NZ24B{OP)Hy_&SdE%4k17)uLQSS9TbYZA)?Gp;h6P-Nq8K-`mtyrF%yD^)+qF5YhuIb<0k${B$VX%N +1FWF*zs31*Jj9VU-#V6b=o#`&w%%O7v1`rRdY*)4^Z50l}1Omap`B#rodlc$8S|+E5B+os0HI7_LATM +sWHrSU9zp159DsrC@}7e-WVSgnHR-6H15drzie>52B-AD=y`FR-s%`-VjP)PXGw_1us|Ma#KNO&KX&% +ym!_qyxp&x(z@t{nCa1kYXNU|)o3~GbwRjA(6LWke-(!bJo64bm{>1z}EOlc9_g@Lx#|M}>V7HY*&j% +zga@alhy&9~otb9;OH;&${R&6eK`rqk&+cNM-p0`iL04(j7?-YSCXKW{JEGWpHYU0~Sn_rKBDhVV{Jl +dD~vRQQ&78yi2qy{K6+eWfBvzJrwt|IK49r`%6BYR)#=sD-u2(l246tk~1PRkb~ZDF0TA@Ym_`li7iZ3)-A@e5 +_>c2l^O#h{aPp6#Y^>jBVfwWRDJDYEElPe&C^n(Pr*v8Su$<7d@?=W11my!h)!I|#Bc-_zfRm?bX@_h +^oCrz3x#sqpe>pMK2MPGvvEel3|VbDdGRhbT_{t2+03H=PcO?55bGb83@N>@({Rvi-hNfN)P^e!5406 +~Qt~%gsKj_1fDf!eAdhER>78M+JjuPmhA=W)H!h9tV5WC0x(LJv~`OVI1W9X38R3mf0S4TBPaTG1NAG +4~5=2J%D5{%d5d2{BRF`vF%{>jbW7?JdKea>1KyXT7; +A3loc0)?J@_Jg&U-sJh_jB~2ym4$vfm>5WObscvQIvW4egJy+YuUR0Rdk=i*3v*(X@@v1r6)1CF6)vG +#R*+Y^?YAbTLn<(D1qF0{%9*Qcz?;qe3D_NKOD2hExVdCvER!RB*bCaa??A=GzY%>3DPk-N?e`$|Zljdo_Pb$)UR(aqevI&Y?Wx&~>>$}=P +Rl*&cDv7`x?8(7a?9qc@}qU(bESgItlGeR(C;xk)T!=l0sr6Z0IPn~yj&`c_y_dn|Fhk9)j==#z08YG +-@iUFk0T%^W$q{Higd`v0N#1H@oa$gc3lD9BnqLpJfsiRftIgJ}AKF3eZy35x&~EwLCY#PZf~)ZmG3(vWYc}X@h97D3w7>6Xh-Fh_C +^@Y(WiW7%aoK7y57Rg&LeNOT1WZDAO`igV$!|RKyMPV~hOQBAe1mR*E7EtNzzN6s^P>`P4s!be8e`W| +f5tjjsOwsQzwonHNN=<3;8rdF3~M3*e;zTGXbs79iTYQr!t-rJY%Hr-|y{Z|mQJM%NRE$x@kBL#L~{s +9}cozIy#7uZiwI)IWgDH~KlA7X7LD1$+^$4feA7yTR3M*AqtL>)$8!@0KQ7N7_MBDiC`5!f{2|0F@Gi +Cl#=v*3WZ<*(%g`w=`k>`%V2@&=?ukKZOKq&}|gdf~kN0Q2jI%`BkH{R8fBQvW8i;OGy2C-~4LudiG(A^e;I&o62EMY-Sp;i=PH1RIY(_G_HZ$)yn!ReejA(+3FuB#g8`jp0PjK*e{Iz*Ef2_c!M5RABA^O!qM9CbWgwHnfF@cN;aaB<)!XG +qlQ~3-l8+X;9PY-*4;REsZ{@P8W;nV72-AzW!+_f*`z!Dkq>O2~N##LlYJLs!%IdUX$pbm(|afqRbY0 +O;)Q{WgeQ}pQ_(2&3#^k>sXnPQg0u>Z6Oyeq@k-k;_C5$sGTsndP9&_3U>FhhJ9*b4eh;y_I?ZPmo(K8w2fDdi~e +efC_G&-^Tn?eY!q0p*(|n+jKu2bAnK`_MM?mCk_Wk`?3uC2JR36sXT(ok*c9vYn-&XPNs ++>MZZQ|cnDeWM089f2HO!a$DnfkDk3e|w!r79cxRKKnGy#3uNpkT7dx9w5wQ&YqU#Z^|%g)-T$&_U#@ +EzHxWN&dVSr^*~Xd)~X&6+P2=81oUCY?@p3vlEpADk)kQvUHv5W{ElE@4qPm}(?`WeYc=jlWmQmp(tTE3Xt-`z0twajh(h;-6s+Z81Gz +*^kN?EFZUsU~j`s~@W?K+{=$#355bo5e7^PhWfl#J^K;hOQ%7wwyS_Nt{&xet$4H4P2v(|S-=gLZgUL +-W_j{B>yl8k@f+j~}Uabz0Fb4XMpWyEm-QZQ707O_kkU?aQzsK(a&?&}>^XOV`}|rQ^VDRaMy1xV1Xs +*Y37;WXiN}QbOtwaqB$@77G0+M6IH}e&oU3yC;X<)(Iv7SMXKtbR6FA*&zm3B{<-~ix8Ag +W)*<`$R}+`T&pHB&-%ULg)ALlVN1k)-Rkn}#c^s*IuXcx&-)Agk9afZdIUevS7tSZ!)s=advis}HME1JQ2nA#qa=_?Sv-(eUF1Kt +0k58Ojl%qg`a$CAJz{+gwKn0uH8%XWDpAfnqO$UC!s`! +W9!(CP_w)f@|L(ZoQ~w?IPhR$VXP-a5?|nLd{jQ>#jK`zV^M-1Gh3fOW)3aCS@6Jx^x`u;eQ`fMrYjD +z2)x3Lsan`$d|HHww_wS$IU!Gi^zkkmAFn%UcWy3*piG5$x%ZxFsu;e(V&n19#{PxzEqXIeSdoX>Rk1*>Fmq%k1s#JeRXm6WAEhU%d>Zv +O*@BReOk9OQmlMXCElK2sHV)Yjm9L{lUlHoek<6QCm+srN1N6@)uMfQ^6~w!{;aETr`r^6bUZ-aXLa32r(62>v)w<@#;a{@Fx9 +lbL-i-EtfqrT57p3WA+-W?s^Q?s6l-UU67k3L*Kc;08yX#$j+$~Wo8}sYa~B(!V(n}>ZJXO!4!vtb?&r01|tsJ20W`Yb9XJ_w}=6`zA(wNCQZDzbYQ6}UXVIIR`r`0yBY)w5urS +-Sjqa(Y&A&eLFoI@@V5aM~BgBp5@|?IeIrt0ecJSuh0)?JO8sEbN#A(;ahw1lG=hGiT>IGhlQy>6x;x +nzF}R=Fd-c>C^L*vyW%mE-K$sZJp1W#l>=$<6@?r!#pzWty<|CN5vB*62l7lx~10|}jV!1GM)QEG76AN0-6=){jQzoC}ESr>ZWR&Y4z8|Wgdp`X +=Gd=QNLW`lLI%+!kB)Y6yGSqH2m*P=N5=-W*~Is+%B +0F=Xshf`z<}PSHr$Q{aMpq5zL3S?)CVe$mZtjQ7@QSR9JE3jN$9KtF6*Rw1v_Ne%m#j^_I-KmO=O`lew_*2i3^KK +Qy(bx(pukJt%UH{OAi^MO734@lXI-$FQ8cO)ZL{=~Uw0MoF0iJCWEAF(bzkSsn5Mi$-=KyUOnHqgS6fSUr|(IF7YGAlzGD_E_UauA0LLO6Rg#B?w-P7Mzh3I)#6p!88G) +`02=G0gUh%~-ORS(+Qkd&FMHgo3YQpIG=B)g-l>y +7&xaGXjl&>t5WY4J!T)k#FR>Ep3Vb42r*Hy>J~8REti~{$c9xVmP_4D{jtNHQr%xQD#hL!p09N%rP`d +A1=h{Njxm&FB3u*}MZZh&QRkIdWQSd{%P@2)V~tnVrqkHb;@C~qZSZK}bxB=hQ% +UAxedr(|-iNjrKX0rG1~%Ry=&_{vKFlh8RDKc$l4$Jm(@_UUMW=%<+U9a0Y8T$li0qca8Hs;i9gUktS +RrdFB_*3Cv}q*4U>>*$xHsbo)3oDZx3uUGSxxzaEfk`yBPJ5VerRE&JUvm++cvE_D-hV$_sy=1RmS>v +_U^TT9vU@2yL?m6YRpIlnss2jkDE&9tOJ${!vKxZK28E>T`0M`W^m8gyTfkb%w8tsodunB!1XZ +_Rw-b_25&F~d{f+i()R>EDI=SiQ64Ymf<(^z)3@bfeK{*cr|lHtPWOJI(NU`>40co6>h6v1pnGUa``cdG^ZI4x +^~A^hfyu=lJ=OX6pbNg?-f-r~s(!Bqryl4@8+o%4BEoWk<%kyb=;O;Mc+hG?ICJsbPP{&zbz~t=BXpB +LNQ#0)E458H*Vh1N@qHY6>wN0>OK=0cv7z5DoK89vX?fw#UlI_w^EvwHd(I9ifBI>K(aEIzN-K3w;s7 +%^wDHi{w=q$5t&z7D@AunF!v{A`mSc*~LG_UQ$?d*6xR#wU}wI?UjJqrahPG)SHu!?4A#eeBXF}XqJs +3w%~8Px|;uK0Aidm&EC+48Qc9gQ9M@~{z+%f01bA;J}v+_i@xY@8O9e8wv}VdoHslwsyU3pSoYzQSLT4TD+Es&C9-&hTuAdCf?$2SY!DIa_s>5ME=b(U3P-}-WXH?eQ^uk_?>eC+)uJ$^xg2Vn~) +FBYDmi`1ah}9Wkh;!Ti975J9uYty5owMS?IXf?S2RRr*O63*n(*$s{mM$1Jvw?pR({*$RI4O={?=QCf +H9Gm1PFKzF|D|Jt#z2J`^Kbg~7uhev)?Y=O)70}+1gA0X4?6@Fk672Nc*)QkSr}{cd1#^S&9UI^GK;D^M5gxn(1qrX!z?j{T +zTh$i8|_G^D&Slj$!Ic3Oih|aG}Kz34O7P`(30cECk_giF|2X^<6A)OUz4qjg@RH|8f|3OyY1*CycjC +9|l46O +P$VC7%&{<|MQFXeq!(>hcfy+*SN8xi|lyLGom_sY23yoF&g0>T;XK!(=F~z~dTV5K>TzRV&l5#C}0)2 +$r-iEO<*kUVeWboF~C-_a(xtcgW!xr;xN2q3Iy%l?Flqj*t8n)kw#oYA#om{OkVDIEgis-~Uxsu|*=N +*g7Ot5$1($kmdTw=qHr=_}FMgG+Th?0FYI?}P5E-%8sz44`eW=&=r7}A_~;Vt%d=BmUyd!&u}y-UASj +a?azVBz1TNrh6&Ju!Xf5dm#7v4eYu0~0Uw3F=prQpM}sbfD<;xmW2=sAqm)sSX_vqmDA`tI0{aqRh9Eu%-n44r_weVvQ|Q9kBjX&U5T^hR5BmGM!c3&_TA*{iS@DE`yTNs& +d4H7H>ms-h*L>LRN7s+A4itXXpbvaA4(d&mAl`gs$OsRcNWUL#Vc#jz^Bpxg>PV=FhVD0~=-8s6!jyH +P_^oG&EKl+`Mx+LnECy2+C64Ada)&ao!+-$@wx0{Qiuitk_q*r*JBcMc;EcmB0w6VsrJL!l?`;SIpSe +_rW~&5Jba?^?Tc00fQ7&4J_!a0~YbqLmzPElo_c&uJ6~8pYh3`S;XIWd|u;ryx)Y$_8c(3LuL^ewSEs +1jSSKE9VPI9imT6`S6x1q&{+q}8Z(yAnFCDWS`XQ1?@e$tm@sVC0V=aiTHVL-QH9CK1s(+*9L0`Ch+1 +gu2T!N=til}mrF6FTLBEkoX+J|`a(!U^Go$*!Rx_j8A2=V;bn62Fjjrll5~U&D&CSfyZ_ubsOSn;Hj} +B?TukfFZ7Jh&t%;x}F3-6I*0Tg0k`g`_yc@Ni%VD08IjtxWOLnLr3i)h +@1w&=(oO_P(dFvWM+Zv;WoPU?_wm3WdFUxhLP9D?(Gf8qL!**k5=D-6~(1Mye;{VAB7QvlIUl;twZ4{Hm@IDp> +m9n2yqgaLY$a>WgMP{v3HNFB-4fI`lmPYuEi7x1{+KD>HVuqMwnsvWZ6z*u0OS|q*^#ZEiEC!KA$X07 +y`j3yJM<}xG|mnWG^a4{XebL3b!jav?ADbYF82LG*}gdojZyPRG*?Hr6=K(s!F-4uR&n-h2%TVE<}8t +(H#H+%j~UzL^$&ZNDl6;vjvariy6;h0U^hY9p)-D^+G +~#*gMU%HE0Fc$W(p*hKd3oA9g4mFHUUKVj(}BDDO8FKsZ?-n-iQZj1kIZ`$_`b>_ftFw#+f$ol}kRLj +M=%FpjedW3i=%Aam9gG#Lq`BVsZZ1Xj2N9CvIIMkv!yR)}jFz;&kV0w{4HhqK+!90Tzrbk+rP+Q)*ys +ai+iXc*yro{P+#kl>sdIx$lHOktL}0M5El(j6oD&oaz{wg0oNR7TvNIm|MZ&{+p8!Ynw7(qG9kj?8Zo +DnkH^4pPJb#scjO0t6rt$!a437blv>5WPr4!+HDXj?!UJwywDiM%?!pTF9zftDkl(mHFd_Tu1d)Tdi&(S8+r|$z%$yC6xY9m|fdm2gHj`=>!sMY>}$l;q=;7*izWMj>l@&C3lpF;f*8E +sgO5KU-lEUVooyz9{0Scva!0|cRTrk8KiG_+rVe991%K!;X +2$+UyFQ~UKSKSHHTYwv5n~~L>@;G=@+W?z0rw1l;#_9j_xwpL7N+T+c=Zb;bk+e&u}%P|s!dmavV~yg +*H3nTaTM@Vr@vjXLjT;4}O;0Mx2BHEL}7>#C**c{?^Z&HU$^_=P*mF*SEJNc>F9}F|ft +=;n4@)%i~Pw=Z-LpUG!+&aH!_-xDnWT5yYsFaTAn@z)S!B89}SVI4Xc!xX2;%;IiP9(<7IKp@waYtmn +Ld?9q52`Q8i7vnnv16>!#p8ky1?AD*q1=r=h*IF|O<2_kSDF7kT>I`Jlk!faMfIKO%VBj(9hPZ%DXc% +nzbUh5a@@HULsBwqkPH>L5!g@Stgj>?!21ojD>$LR)_gs}`L6fUwO9z&t*AwtRuYU-F`qaqpkS8D4L5Ys#MiZ0+grV6OTjF6O;%z+IEP06jdmC~qFjAWc8i9>q^$L>)KLKQurFTv +?G=g7*LFIV!2Z4W&-uxkG#~j1dG}8TV0Nk&g0?}}01Y<{Mwn*&o_{^5T#+5}@zXw;AfVcJ=FR0^|;2z +>QbCJ`nH#?jr^;V7^$Br2b9*$p|%b4G}Vjm8oIOT?&oX3`;P@2 +SCsK%qn1#J~#{#2H+dsp&eFn|bxB5_&$C2-kB<^HAS{Hnw+)JrLsD#Y!UZOi=1qiyySx6E_^=qlFF*wNyP4QqwYw_U- +mu!VI@H-=v(@KO+=lSU`@8yeCBrm2plP|-0FC1ws%kZT@a4Tgq(I%N1E-~)n>2u}5+zNvqVY`A%|KmL +=Rv{(WZ__~a4FcAhe9$Gp=n!voXY=QxL?h0WK1ufFG6LDKaqzhm;y*s@y9l^sH8vYURLx#tIPZ*v7PJ +G_I0l3d#lYujya5Zl}13qPV064SrrUabX|4iKq7*5^t7*5^t8BX0|e!d5Iz+iND!qt2ab|x&H@4?Q5# +q<3N@HxZ5CQbu1oY-6td=AfM>NEcV$!E-Pk`Ff!pkda~y8sRMxx?VU&*Uo_c5Ze>!_L}?m$=45Q9Xuz +#Okn?Z@sZ7HsYbTkTAmD4?X6$Br)+glq4qRwru%gAkZ!nC=`@;^2k$GhXQ0NQ6kS7BM$^7Q^S-JZy%1>rp&H;N8pcNJ3{_uz2?p(okKdR(%1_@e&V~I +bXbo3F(0uxGc;ILoMHZ2u%G|Gc}b2Y~})nS>SkO)3>~E#8dngZAxf#_16T<)IcI^1=rsebmFkXpb^AI +evE8C1vOJ+3O}C5gYqUcm}bV9EBE8DI*(!}axnKC6vBlZ%;%D%T@5KKvq5|^?j=k_gKD?+)jDHW$eWn +q)Z!=*CliR!C~WBN=pqr@@jju}h<|w4Eh$9KXU_1f{kWVP{hq)}so-T)xKQRr(r*Qbm_3w;YbU0C8RW +SD)h+%Hg2Aw1!=}LtY%;OxYJ{DAI*`aadIAOOuiU7Q8O+8FcMq*#3C>CUjt5Vj)~}_4?LHyy8=adnY~ +}*ylz0cV$T;5s!3m$AR6Qd4&I$|}(pu=@0Rat0j29=t3XW9)DN7nmn>A;EJ@xPaP-g_I@|ft%IvFF4A8cXkw1t)IM161Q^woG^mdPp*tba?EYxaMdHFEO}k^taY`N +ns6i$NDY8*=LH7@W|6;FeVIhB860F$%2Lg8M+kBIb4s1g9FIep*-hgFb^1mO$!fV8@6Sz)+ +SDz1AC8t``b$c+-p`4v*;B-N5edfH2f8JX9H|$&zDD@$kA^5H{g?L^~B|)`js4$cR=2w%-L-7EunZnj +-Ttu)Qf1S$QyK^hS+_yYlga$iwyqHwJ>O?-@53xkyhKn>*p=wm#G+T8hUCX@H|V!YaEUW*aHp;b9L2i +`qj88@h!!P2?urXMCF6xe&jTY9Uq;#D1C?PDcoxD@2wWqdUUxAV}l5nSTETFni_3q;$S(t)T4O^aY%4 +I>JQ?D#H~tjnhJeD-bi#8ZTn7Lys!d_eHv=78vqQo)(!1g)?}#MKswIQfcfaO%q{y{gH!0+FsJ_%rY% +xj50ZJ3qpv2GmBNwaa^W^BIUr?nNWbfb^y6p@Ag8X!b4dQJTrlbF&;G1;054Ny^?1-p2-Qy72AE(b1T +B=Q$$OGFWfH__!2F7tv^~ARCr2RuVf*`CljEQA*YB;C3MyW=lp5_6753k72-J%*n12SKMpAu#1p_-7b +-r3fUymE&x#LkidT!#d)!&W{x)0)nG6B9Ogk{hwZL93;wwIcy6K-9vG7hX-B6+3S4FU_KF-m>UC!5ectFOo2GP-a1vTIf9C36%|} +x{#X{7ODAh&%&&it^5}&98u2HBg%k^cxw4PL1RUSx@Q|+;Uf);(M$4I)wGccT#3>10eEkPJMRVDH(I?QX14AOloME#rFhdpq@`=Jbzoz{sKq8Vf&4#;8=ocPes-ib(Lp7tM2PGDBFu7O=I2DKm0!`Qk8CA(9%%CrRZ{dsI4J`J^Uk(5kRiL+Vkr>S%V +@I$^(ss@7)2+Kj$AmzxY34cKBv%L%LmlE_3=Kx^9DL5jMn7gi@jv*qi_G%}!&;r@7IfwW8{0d;6si!1 +4Y@C&GbebATE+q~0b(i;$3V;(F(if#1%ld`Fk;kl8cOKQ38q?(1cDe6eLJKQ$BYP<(j?-{IKwY$=bCu&l_9AhJ=G)~oda5Qu2uLgLbT%ih@Ar8s86Rpc +cH4A820vfj)+iYFmzvZRk4;o8%ZOc>K%U%O=0EOuClLZEUt6frRmLE5EQRy@3fRU=Yhh8Bhf>yS{~H5 +u*GNa77wQkS;11O{<#WEm`%uGjvTYI_b>5|4B&#V#DG@CY#WEVuJTYsoCNAtqR>z(A~xt|x-Jmd8sbIvRh +nLPpHjv`pz)4ZG>|~K>R1gbD{u3m105Ft!z8}$$^&J6ro$-w>RzO{;8OPLezQUvFC8C594iVWbk+eIL +qi{bh$!w83gD~@CBMLEX~a<q@MvVVO#-^WB`QqE$kr#L84*W!dR-Vr`E?41HA+(UDv41Zg*iceemTe^M7X5z8{NgL;&NL{#a^ +~D`#lfANrmF%01wBrQOe#H7?z(%SpaU^6g1DDNP!)Vwl!R>4bHCeW$mq!LJjv+My +x%)RZWQ?U&ai+h`KcHy|djlH?@ +BtzL)^4yZEm@f!pfV(|juF@x!b;eg=?35o)=aT^1AU8c=CJr}@P7s_sJpTQ<^iN0Y|!54Vq4B-fkVMM +?PSZVU;G$P&rA$ZzQ_L3+;dx|Oc6tQ@tap2Jiz)|29q+U@AcsADa0tVBQ-GSVZ#B-sHKHzkd?FcWP#B +=j7%YO)1P5d{4U18lN%~kL`hMwRRuNqSVgC1C)NWzSaI;6(=@jOVL!d=km&aQ*zL5pL3Vf9k@=ER=wWYH&mi2@mG^bsD7H?2_Gz!4KT +Ha^osHvv^K=}NQ`p~fVj0|htz!ThH@06RwCKl37H*uDniWV<(w>)ZrQXi&d20E@Zi9=*R3<+Vq9}lfh +Z}|enfO>yBx8I42(=SF*k*Q|gVU`#?!hvJ^|) +cGMbh{?A_wrW0!>7&CWgsw#)hXv3QGpm1hnC!)a$i3|-GHPcRow)3Jb)(}Z!dK7T3pMX$ZnK(3|B4mD%U8%wJe8nNdk#vYu%ec$}>0Ww-l9`8SyL +-5CY`F^JaKl2bIoWWC&8Ln#R?s`VVS`wt0CMWckid8V9cl0y9OBUnfuWt*grHncV2vgsPgFzVM3fbD{Zy|f|KGwVwF?M$?v-i<-=;dV=2G*-cW|FUMF9*Z1f)Ef=sy=K|4+x^L6>!#t +(rZg2f_9#?Q81o+2nZ>JntV;gM-n>gf;mqb0g4Ka=ZbW5*IvLii9$?9=6?Il#E$PA5_8WaIw +w;W`Z{y>duu)LAB>5F1xT9rKND=SBOBQPn$Cgy)6fc&$bwlZfw^+Ew!hGA*7im?!ItYKh~ueBAs=tT#OgA>WV$linQZ3`1PXPOL9h9s +(gAK(koq=dq>)<@d3y4q5MBb+ATn6c=2jd<2Uy1>P>0OhN(2!A2K@O*+milX<>rEPkJ1vo3Jg*8vmzv +b=>Bm+nRc7T*RXdiib82@v8Y=#hZStDrUqe7g_B$>trJFU>pnrC<*P6N*SPSPJr0x6y{;KsoruIYt0Br2Lo#r}X<-t4y{oEDdRT`d-+>f +8b`acn+iIrgFcC_rF}O8>Fp0wOobUylTd^?IN+>bZ3iO?Ck +-)3eU@wj-fmPy={^>1(U&JF~31?%d`C!Rtlg8qu2#hOTn@4)8g8C(C2P5c&$zFNIy>U@nNN;s?%VokU +K(R!y1#f9oa6HdC8rju}+_kAauUy9wRJWKf5>67qP}2JXh{P+X5FjHUK>ItWNyq1hJCN(o_-vV*6>gX +Ah$VQyVDh651^n8H*v7yXea^4>sR;UCSj~@{^kr5sv@(gxIwc)I1)snq)N@&E|9{2mMiKeju +>?c`Kny2mjG;!KkV8y4cafp#xpSC8^)3QIsTRW-s+$IqAW&sflaf +pZrZ@LNT(Iq6Lrt;ZN3;?+s&_Ma#5yXaLHV=oB3X1Uj04IZo1;JSv*1#H#@MoZ3$h +6FRp;usUy`o01Ln9=7I&~v_BL>-~;f-jCGbk+sqGTIPN5v1$@j3spD0Q12aqD?izqmy9t)#TJJ1Z>s; +-q0i+A+jcX(lJ53W*8<6o4J6}pXNGf`SD=7?L8X7d2?pKY>>@tQ&Yij49UL`ENU{dUl44Kw5~qxb@N= +JXP_0h2=Op>9~ti(+q8mle!p=-P$c={5roakJlj|48^p4rM*$}|)80_!;65t+)t0N!8*Ufu#9o4zDe1 +CHji75VA!Bf*m=s+(xgVGZ&aOb~ +s^7af@U!I5L}cw;H{|i8un-?3jEiRVG1WB1Zx^>p&^>%L5RbqB)ULm>&y?3|t@?OvWt;>N{HueJkOJT +L}H;B|LXKGStBcJBtbHT!rOr7<`QiCDN0Q86|>&&_MZS^H9L)Y=#&}&YX>NLKgG8l_h%ClBShfQN5VV +^e|);`!%D%kWqP=Er6ooPwCV&U~rK-5!(b+W@O`$4YTRQVjvWHx&=P|rc8X^2^z$;ZCy>{*Y1m8*PXd +!ByueW7VH0Yhg~zpuS>58GyQE#dhRq}teDbNuFYKe?*hb+fh>S&qQH+CGLxW8-k+EQ&fp=yGSA%zD3k +Xm3=^5S6k%*De@JvVs>6W;LW)m?kAVnqX^}o;opo+fjDX^7!6}33Uc`{$^vc(m;e20$Dl#`C;N50)Gl +HSKp&c?96MA|yW&~ZCkZ`&gfgBq<2+MH3N)a-GuTpr7;HwlqBj_r{q2Nkfr8r~^U!@RiaZng=sbs`e5 +y6tcFRkE-IN?Sad6xo>$h#C^3U?{~Q^0ECUkS!{DSU>DyA+|s;4TF&1!VFd9GS(L^|kvWLhxM*D$s;# +!8_l(MqX84i@dz1lCVvq$7xtiHvkO+L@J+j;@;gFtxr>H7VWf1K4qzGVCJd4U~}}a9u(12QCsyw4; +7#0@o#!!wyCF28l0doEK51g2Zvbgp7%%aNRJWX7E5A-HOQc{nXA=TM(1X??=aCkz0&bVoD)~f>??A1B +sA{`amY)DS4=_%#9BS&bjeKFLL8y24r6Ogy5DJG$NG9E2lQBymG7p%s==f=lt9>6F17f@e6rb9&5hPB)k$FGU#|nR1LmW;-;1 +tB_kxnX!KPTnNMTfDU1iVx9Z6r8xwYcQnTY=4BDvS9y{P3oQ?F2`U!R1rU7mdrZ~v#%n@gW|KN9H(pa +9Y^@yuCH6kV60O$gFURq*>Cs@sIy^xRK_Hbpm#J!yvz4kgW(2vcqJXfrgz?+VlOu-By1?c`LNh@0+b` +e(VhpWUnFkX_B~JJqveV%w=GH=u_*}m2O*fsdZw7sWY_EJJKglvB1c4!#POiX6pmu~d^Hux#iGV<}4l +G*I^KeL0sNf4Ah5~WpMDRHtK}Ck8M+iz;7%}+T4W~DHLk81lnEC{#XS4za(;dJC!6{7>nWG9W7pOzR$ +j7Z9hb?#6^R*hPU0S*J@)axv_F?(jev}qmY|)K%gl*@D;dBe#BPfN`dka(fHE5|08bMfM%4)M2o>X8#|QZ}e_#t2!zwtPaEz>e^M^x+@HHwp6+5(xiENmKfJ5_ +eE44z1Y>_5tBlnUmBXj|Xc4i#D=HE2HAwreODA|s+#~P!VKA0k?fTaFpuh +EsQ#(Z3Z63d9wseo|dqYf7``>>mNP3OMUP` +6;_09*?YIL5@Rryts9(p!5m!5%$~)A+8$_2x09G +#*CtD6AwYzBF%{>jFxq{4z@Bcz^MYZ^=%Ha@mCQ_Yf&8grY{P)5~S%(fGzpaG{wPacgl^W=@_t$<6CqX=Z)(_b0pptZ++qu +au!*`#{}ohoiT&WW2z(MpOn_VoJ%x)qhmry%KDOBAQ3#8j1r>>mifSNfRJ!0&TL2}I~ES}TYk+B+9zM +T#W8#-j)leyrsE&8*p$M6kUWsc>oaWD0ovcaGe-4BSUtnZ&3EK`AO}r@kqwOt5jLBv;zNA+K{q;cS%mI~jB-RhWI&RMIQ-$D>TcAw6Y +-9%LnVFpfcxUSKsFybDC7k(?D20n1setBWh=nxToq2Lf|3(FL=u)lu?on726nKpgO(8s2RhuYiC?1S7thSq +DK1ytibGpu%iV?nZ+mdcD?f6LWa<$}g-|=G?M{rp0*v+Dc67T5Cie_rv#iEj9z(pl!l%7VScNX +u&;}}ML@A&qc2i3akjMbD-yyL;g>h4mpvB7nbyG(QeHOX(knuX)8Gn5dvIFRyiR&iHKt`30^!-nA$Us +FdXtk1n0iQMy+B#_XV156tPqgnTIS{?yT)Mjk%&DZ6}1e$eVw*DEJ-1EmrkQRC08C#>7_Z`U_J-iot9 +s(ODX~D3W4g4ZgV{mEVi;UD^v%}vEM)u_we#{m37rumHfy1f+7P&7XfM#U##g-Zx;EgkcX??1AfDdwf +>B!Rz;g^m)A&*=0rLaB{Zok|n1lGO#&qt4xGpF{C;W|u;m&$Z_zW!=%?@zt|sLJ&3`W5}FSFcW+Y7{7 +_JJ9a~cHD33J$VV(prJF504Uh7p&Oh4HfkhpjwTiCu%$Z#Y}~+16j{M0EvygNQ46DXkLxyuFRARbp&L +=zlh)%W*mo`66tI^K-I#bjZTm}dIcv3vV6R%bR|YoiH?S$%oeo+V90O+L2VSP576#c*jr`E=)W{D!Ph +0t!%qRtGc$Pcog8u?+&r$&C%ZY#ej@oeM=J(#{~VaK%&7wJ`)T;6X&DDLCa) +Gri7se8Xsf2g+t4jSO6jZ%Jr8Mc^0Im(xwK3EtvptB^X0f#L>UwWuP==0Od7}s<l(^D3|Z>EFhM|CaxW0xg@r{`&0Eqeq)8Tts(O%R%I;MxWk1?_E9 +XEz+!a^}Kh}i;`aAt;1Z)CVvqX;W~f%OciYl{_XLqC^p}I^Udw;?Tg#di!@t)Gnh_~zj>?Nr|Lg%FCP +D@s(-A%$nsb<>BnB4_fEaSyGZl=2elPc`@pB4^Dt}ve)etEnT;Yd$UH!Bg`WQ~w`OO9 +KQH0000805+CpNn_Y|+{{7%0J6ye03!eZ0B~t=FJE?LZe(wAFKBdaY&C3YVlQZPZEQ7gVRCb2axQRr? +S1`s+cvW3@A)fO`Rt2)*HV(E?e6B*eK$#yuFq{gPVD`-$JfV?5+Rvuid0F;irUlv{ml#j5&!`blw`;0 +RwpNxNMHaA27~#+V3uc#;PP^|DpxtXybR*SGRw;#oD^BID%mCfeH29TOX1mY +bEJG@GpA1fU9ZjMYcuNmwvh_Dz^yHz8cE%2=XuJcS{bVOmz>9@5B)WjJLoufjZ>0_FjQVKI&4zb%(6| +MJId&GI8rj7{S(d6lpQ0~kla6$_&{o!1YhQCNoc&s_gaKxn9EI4ws(8P3n@pY%En7mT_ieqWV~6xL$|(yg1 +|(IT#GyBeWn4fUaOBf-Dbaal%GPe9eMv@-K#@nU)!pAn=0$pM*(ptkKqZ&dM|R{eu4fkVQk}g5ni^5ZL8q%GQ^cLxgd}D`4M`0^}%#c!F$9sYgr@C@ho||CVZ0KY`Nf +dShVXi(+V0$4@*9fZ-D(nzCV4`-n5^@oO=bGriO5r*82$kVCHl0lv%%RjVZ~COcwTN?2js +So-6Fb?D6?f2#BxDdKKd +zlT=5U;NsrUGgrO8HnelaW{5DHrD9Aphd0E6_r~(rLB=2A(6fBp4d{NZ>%MMnT!QNOIW3k>izDjHU^(K~>7D5T%182`2TN@=0OQIKVZIJ +W*o+!4!Hqfxb>*<0)7KK=N!gzpCovHuQB8PsUwrgQ!+ROZDR*_|QZM{KFB<;=CvYLR4&2IE4ut3&b7^ +4A+ojF?2vBPN%+T=uJDn6HN3_Z%(N=Y~gEFdFp)uHO?;{=x>%+xKiK^ib})tAzwbzq!5HyHFtPO45oS +y^JHZJ@&n^|Pq2qXmWPt*TpTJy&vzTq60MvgfD3C3$0A9-vB?zEJccPs=dy&diRh!NV7&q16$V-T){9 +jwK#}UZF~PD;oMZXjm=q}~LXlc*9Ak55^4Cy~l5><}KJoU3VLufT-94y8C06Er)e=At +#%Hj-|3}qYY{`U%W8BR`^RrAq`mchL+E18Rq3#h{&TUb5p1GBFX0T6c=cgCYxY|3;@*&&g+5&Oslep2 +S2Ui{JIzfkAguGFM#5rKzWpA@|QXNi)B~}5>ZR3tGG!|7Hn4UkxDemg0XwRmr@$%j&cS +oF}Bs)_Bb2`%`?WL12ls&3r$NhU*dpe!o_akAsKH1dxMO9&X!Y1;N&6!J1$X0uCumU?D~uWXw2p{?u0 +5s~dJ?<7WxGVv|sa?Mg752cHin3^*+NE9_^33r7{eAFz!Q%ZSOctzBA(CsYzvJ<_Vm8yaY7kS?uJ9Q< ++v8+rLGii>cPuw&Tv*bJyS8r_6>jE_dRzk3c31su>(2j&(8as%HgpaSlZ#%qq14==w56t@(c<+u;B^4 +)*Kdz6Rx`~OIDFMQTKL}G80977+1ab$#D{8D9wGs(9ShF@ +loDaB(VQ^s|E{INI2m|DB5?ZL37%Yvd4cA4_YgiYs*M(`3z*-+V1t8N%bLf(mh6ChXk5GmM!DbLHmq| +P&ygd4d5C4eRIc!_Ja9cc)}9<*9))cNHm6`SqGIm>;z(QO*4J5z}v#wx8%VkBFkFkG3d&Ik2dg_ +EA@rZihUqlj8rNHEq~;+<0bRT?=8^EXP-m)QcxY#j!Fr4;@?n4W*A1mw%8c;jq4b=kB4XXi+G;Re!=L10&Hfs+rd~A}6-L}Jb^Qz=fX#(Y ++!NpPCD(bOAdJLjM0le*(Uk?whP*n=CV#hAWi2)1~mJaRHc!&dg4EwEd4+ooF6w!@2=i;$K@ZyoCTI#E4G +s2rWM!&{?cjzkwA=Rf_5n8*j;Cm$53C=ObrfTZ#m#)sK4L)`R=LTaCaPJ`dV6HE+dXHK__tTQn)Et4*4Q95=&OB$x96u8x;UR*){?T<^%a9krfMuhVRuuxQSrhVFw +ObDJKdzzT1&I2s8_e1sOX5vVaSn(0SHmc-Et_UKl7E`EODT<@9IHO>fsJyfmf|3F^?s=x_|?!gQ+|Kb +W1uDEEv8rN7p;TcE3KUDDVaPZFp6&;{! +ZAR0bz^CkvaLqj%Wl^7*NyMMTPdkpHcjuP%Oll$G!ZpU4Mz(4^QhsxmUVJHf@w1sf@wP9f-*LZCq7`{5MfL#QC +sKHq_Jia-Jmh*CP609j8SDiq^__wT#dt4ZS#j_H6 +XzLRp$JVus9R)g0NQ=Nxmz3t!e2aX!W)2b4pz87&xZyEZfsjRqP~g4;D>3pUgo;KVeDs^1c=I+|&?&Q +>Y1;Sq2u+FA9*EW(ROY;5@3bw8dVIUWSMuL{@*k3~a{tin-P)EDk@2`xfv%ers~IRJ_oIg_(_go%Ta-LFi^{Q`@%K_TQC +dZA&pR-VHArmX&K89&*4p&p!#&pHawyez8nSgusx)+maAnbr!v_%igk`mE)oRpwh0L0kORgbZs_3UB~ +Dge7HFIt4#dC)dVkyrlSVn8huj?E;`dO8!+5 +yB5c^P?@R|40f6}wi%mqtS2B*Tr8z}9|7L+raDprlDm4muKIe3t>}?gT2X7@P|ML318@u1RnBDaK6~j +u{KNq9#G!s>aHx%!*yRy&NzI7~eC`GEKn@03*%eEcz%7NDj$6#N`k?tv3#0o!Ez{r6Ff +hhacJ3g_B4Ji%?L%}2Lk^$yzR-VYgu!t-%Rv^+lW>-x4+M)Eb&^d=JNwPHx7c +m~=$YHxF$LPt)8F$=}bEA2FgG0=2Sf0mG#L}^S+(KHAy%X|}J3QymIymWva}Q2qO^Oq2m9meZ+XCuFk +%*MCH=%fLJ6chOh0z{{*~bdp^bOxa3(^DZ2CW)M3sL;9u+1hcKi8ak7Y(5f8>*^+w$ajx&?waT(9Z(k +#@-C3;F@UbzGnJ1vC1e%o&C_DN;J#9WoTFnrlhA4HJ2HHV?6R!p6{VS;dU&93ATt!w8+JU0g`MiJj7` +{M*F*58+dZ%2A;dRdZ;f9d0MZQy$pk1+aW!yD4mT?tyqa)ZHedVs7a^tQ0|~!I#-(gl!uka@o)h@>SR +>dgEsjdaKa4R8Jl6ZO&)rI5}^PIt^0HRY1$|puau| +3q~!~-+B2g4$$dtb7{RR6JOnDeH_>Z7S-TQ`{a7{`lxo5hsf< +kCR7_qB5c&bR_QJ=5hYyN$}(^fBDnnCy$>zdejzxG8jF26h=2;kUn+2oI)mX$2 +UoE3!!z+x|8Vph%+Kwko&gx#KG``7 +7RgU?t0acxT~+tLTG*MEE(S@s|1jtgVQMWI#ScIf9HyGOOBhdDq>=|CplJKK1T%5h1RumO7E7xJp1jMXFyBL?5z8OD$_6$U( +zdZit@snrIYB2?sT59{NK22F#_)4_!Cy>b=@6f_>Ge@1w5Dg?|JOKP;RIPg1PdY1BX}}i;DGY^1%~^@ +TXrAQg1F08%ub)oUJs(BkuSbucj=ub=cU_Q9qCA{=@SJ8vPqC&^af>R&cD)3O3uGL_Hg!omihXx9y*^ +qE^BDDWAU&9&Zyx{YN$;U+KtSL5>Prt9qyn*i>P=9YR>M!yU9(BardLu9$bJUq7WUw;?)p&IeH5%#sn +O+Z>%CY^GzgZqcSPwB;>|t%%nZ}9gW;hRd(wezMEPVFihg2}^r8Fcm})`svb3ny6`8g~m}bl6Gw98FJ +&q>}Oq=ouZI#%wM>kKNJc5UGX#L4Z?cEq&cNt^!3@m1n7W_~U$Iu(^I?kzAxCwjU+)=TKZz~#m5XLTK +u_IB~jB34R$VjeZF?XrX;VMc(d1j_N(M+FVx+$+Hdu7pxcx>;OjdXVJPjAnV#l~oQpGK2aIhtqX2$O9 +T14|Yc4GZQuCNrYf=&FYosCP$+q(@~q_hF#QVKMWZ*j@+P=}zc9Ops6S-5~9L;r>I*X4?^3oll25T3% +F3#qMi4kgj+hT~KI)YNjx9jZLwcf5@_Oh|c_&RfkoF1DQ9ait|6T49|b*V;H5f^bdlpyi)x5o-@*wqN +#yX1NNP{miFNW^Ja;jSlNlC)yF~lIh0NBWg{SXKO^YmRgL}&7w@o&@TFL98R?6^^L~D=iZuu>H{z5(; +_!Sp9)7&Io;@DQ3zK$iYODwF;db--$L+iq!E5gF7TLy#nZR_9JlgXOal7y10wj_taE{@5V^|f>(jmdK +!zTKxdDjcWGaX+S7OrP>QU+~H1}I;@BM#TBu6f@3jj)|sk5u>=(6sRzkJce`H2kG87EgAqqSdm)h@rT +4m@a01r#yBqL$UBL&xjv2a>LkQWjuW&Pep5h5e~zD7c>IV?L`p@ly`-w+8utjl^7AHrU;=9hsg6&O`) +;gK5aL=FkusH#ikX`VERU)TRie>H)&njUry40m%XKoOFU|(mp;RXw&ECS$4wJB^F_IVx`#&Pw;4ZQc8 +YJUZOSv@X0va_b897gl~ZSh;Q-UW(}n|oXIV-IrY7?uTcr^{JGH>$*!VSx)9Zl+h~5^)8UF|+U-F99U +ZQit>?6i7|7P}etgqY$(VP-j5lD3N)WS7AEJ(nb)rW5w-T3{bcG@lwm3j-RfqOInIyv+KC%?|Xmoqh!Ku%Y`6 +QLs$+EHIoHD;W~H8BS>zTMezoB1G0Itk`nWJMJcy5p3Yg7%300WE8Dne>XzJ@Fc8NRjb60m;3E&ni2b +yRZ~QB%eNyUQXs#8}l@Sj=wIkvnkmJN-7-13o?dI)P^ef8*DDi5xUX=h-^p +;R_35`h*l!sn+iPfkX~YRPbFgLRf)7h@|3%ISWr-Rw1%=zFojybl_!$mE1$-sEtwDrciVn{uuER0n-D +@C_^su@iO(*vPaxDI{)PvKQ?`{{+^-QAx7v!@~7r%fhy3IS{NiqDg?QN08`P2G5rs1I4Yc81CTsq&l) +iv{~g98i}K1QS+F*Z`Z}~V`txaTkQrqwXLde9wxZ1E~%AUOlN)@N23RwN~;{aOL;x*LQUUo&3+cu=%e +zM+W+2q&4OCPetugS@m7kxJlAc*jF&RIm8e(C*lnjjlswlGYaSAVIQn0udElmUq1V3>R${tEFqmg$@P +}d${K1jF!xxF9wc89Nrb2Lw$lTWQ(6pRmO6yj0f^68!nXOE<-P&?!F;d7i`)^>Z7`jw>(%&(gHP^m9j +1(Tad~M;X>=h;y75@f^d#1IUCKnE?)!;(PyHXf*^zI?vnt|SC2+U@qI3>+;R8P@<)%Z>?Y^#dR`J9=t +*rs9cBe(=b={+H&#R2Q>%IJX^6X*^Hj`wZy@Hav98LzLg#X}nP*sPS89nbBmmsr!@c${kV*wu~w5UbA +K?nrP_cx){^Rryc%B|zETOOi!@wsUn4WwL|dWtb!~Eicc%p9ghJeN*6B5Roo5S|hvcq2K#khoqU3OBkKb^ZIlVr1|I +eLDlfQd*jOMV4C->FvSkzO&Rz>@pfZDe_k%!URb;$+xZ(lnquaEcds@N8VvIVmJuaiPJ2RIACMnj7oew^{l=XZOJN*(02(5^b +$QY^A976=&ab1aaH*rxNYMD9SM}EMAtIm+_R3AS~jDV<^d{*FUYYl73AwRU!o7tn`X7 +qzIJF&Ov61dJXw_`(UiVY>8WGcEtd&j3_yZEtr(4%=UHv^^f{G%!^^#+GS*&vTrABl{ByCihpO^h5%j +`zRf40tur&#Vm1btbh>GF`q4=6@=8Trq+M&^E?fgB9qju~Az2QYpG|Aa2pK`7WJIHl&gPZ-c4!x9G(&s9-U5iRRz(Aqv +B#Vl5t?C-K$h1oXf;mhslCOVIDXz-9Uqn-996Pvi-B)^(=aQ)a}5x$%Wag#TY2oo>Bd@fG&c^~R`$Lr +->cNSC*%YUoT{m~m*t4=d^wWWs~piaFGuo57JJ3KIVO;+5|GgDccio`2nqYVOAJya!CL*=gYZ)^`AQ7 +3%05ysLis05vN`{DHv*9qBRXXx7x)(GNJBm%rc)x}WnJ>fV5yh0N>;;KT%q9^{b&_S-`7vkJ{_(t +a^kO(P36HFZ92#G3ff=P|8wvEw8aNv-9#fCc!PN2Kor)V;$hpC=fKOz&<6aME*yPcNIOHV2@6_w<_+; +{)V3iZwCRW1Igy{a16E$fEn)oJ*V$Mkh8Nffz8yQ6_s-q_iC?oO+*5a^dB^b3LUV>cjz?jGN;#xS~!i +5Nx=1bA&;yDLAO!QnothAN=Kh|r#3-A0iYljgBKWU|tB1nOS#-&2!kOjS&n!i6L4!+k_1h3se2nbk;}B^`fRU%4dcot +_r*6emE>a4Z23xP^JmP!h=LC6+3s1vFf4+JM^ot5Qig%hZfc+P=(}lhs>&p0jg>VVgKb-oJ0-`o||Gne%4TdbxIvyxN~&5J7)>Z)eG3mavl@$QQhfr}wh_e@CB(twU}yKmAj(Q2 +xN56ZZVpa}mQAmeZ2OqbEvB^RwCcqboOzm))Y*}C*zLm}^|GMC(q-6h!X@1%o5U~!=lJKMUF}B`1eWB +Mh$!kV9~tF;wf6*(qV&qRI?ZWU$k`2^taovF`(<>sZ2?6L*{X*@fg*nN+=$N6oAgvQiYG3puIsSA-Dt +<}!4fdeR?CF<9+p%b%B+NKSsj9=Nk#L|2;T`(eVZ-ucKB*v1X~uXhSuG;6&ZE$o7h!+&#YHLD5v^G<7 +OP`z1wZwlB8-YGCWrM+q>E#mi1}t5DB*-)#oi!5zg52R~9EmH7icFeh>~CC|02DhC7i7ujrS$8b7}b2 +*_I@GmtA0fYiTT*f*VjO`-~I{8%5gTP58lj9UTRuVI&8qN@{Kz7c1KcD4vvU36_ktxVJ{8mfAC3j@?{ +sY9(?lic9jqnCL+pJUn`^#bs{+S<3H3?7TP?XKu +49^KUp*O55N9E*or&axa~N8W7pMORXx{kTzjSX{d7?Je=7cVuq&O3l~h*5&~Py=)X#H2ib1ykAn{&Y1 +3Fq}esO7X=IZXZBKVmHDE+R_2y%Cmn14PK{zdMp444%Oa{rP2Z;lyQf^5J_KXN}J<1DU{3%8Bye#vos+ufhuv^OE(##gaqx=#Ui^7*%{J>Sj|!k+Cz +h1xwMLV_@O@mEUC-b<&{$moR(8Ng@=Wy3SRw8-;vhvYH%+^YO7?AWClO1u~JnOWm1>_}SH +FMa8<%$D+`&wD`*W2N^t`WMl628oCd6l~wC$8n%Cgj1xPnWbfpGGYSi+7AWaCOdG1frOhJ!bwf4pMel +e)pYg+tIpOuEheTr&ej}xrFcT_+TK8wc@!TI(Hh#L#IboQotb&PYx+yDP=Z4gsQh-`*`Pt=N4xlYH{L +pYJZP&W6=sow`5J~>FztFGraf2JmI(4jD^8%G#G!-YNheqE$lE}iqoDuLdlZVBK?6*f9?i}#>8{y>;& +gSw%&D2EJ7Ga4tslggZ?Lg|hn_JQrP(cxM2ZEXtqYGMt8t!vC#%5vEHPB;VL?7-$j@Zdmbgr +ydHom1L98UT;b-zIYqeGVhMWd$31^W*bM!0X}@ycRUX;(6L$O$n)>QxqiDR=ak +2&KPcc}SN^LTz$QluHa!TUS#!jGKpl(D#~4uUJX?xjBPiXm3)rxjl3#gjdKTqJ2x%f%+$+JxISTJ?x6 +-pO`%dULBLaE%~N|Ng_Lp&`sF@jC(C4gpnpFWLpqpbA|i_r5q%HUX4j@P5uxJO)X(n#-feqU2S0!-7x +)7say~%XzpAP97RaFu~h@1`_j|AjG?;<|&Ym?lJI98loftvn3F*3Ss;5hro0>@gR?b!`#= +Got7sBvMQ)k@~J+76nXdv6D7FX|h@Oq#VHS$k!M~?lHG@ewy(YgDW=SCl8MtvNBwk8`i=) +<(@`}-FA`02}FzsG^YBmnGebMWKbT3`GlN#%Mhvuwn|JlXi3Y-k(co;K!=A^ +EmsA=!@ejt!`aC*2{r>L>hwoEkJNGdAJ7Aj{i@07{{>RXp$((ZBuAVD8&$hO>=B?wQudq}^J(>9d`-B +S0UnJ0ZV?$~?|(T6r6u$87XLXe_}oPj)l#n5DXkogQ20PwP~zE{VT8Ql=k+*^=_u$7!;P*l`PQ76{m# +skRKn!Yj#_Zm6-0p*eC=OwE5U;a(Z4wXyX^UI#$G7m)6dUi)o_yyxB=|i^4L_XRu(qZNc6M{ +ub}hG}G>!wd8YwaD)nYZh8qHub@Ot-%E0{qDL^Rz5VKUG1xV&1JhPmoii{d6#Z?#yn3BS%F!>hwfHby +<}K!SbFq2}x+F0hq9{rQ_e8DKFG>;)@P)~M+wSb$gyT`B?qp5wuAV7lYREfghN22Zqy*$M#tm}SeC*- +FSSkFC|d)E@HrY*hX>`17*|jfoHto;F@I>i_W=y639@l@;`l!U8|5CbY`kIpHSvBm{j+K8u@)$#~{Q+ +*i@y%#X-ez;WZVEiin9lHG)rYsR>KgZdnRs=#9AzN#k$t}zRg1)aT-DiYQ^qNAYc<|q)#VwD_Fmau>! +jd~py?8q7#kG(~I1A)Vph-WHpgTw$>&Ywk9>}r})UNV#If#(Ub9)eG(E>puNt8H%4+BB +*58YD+z>2k#*4kr=)61El_9)@`=F3Y?6&mBwU?z>=q)L4SViO6x*dbnvgWQ+0Z{o+uv%j5j$Mj~Q#4W`eY(h%##0L^w&67St|r0Mnv7TFf-jL79_C9n +K3f{{Ep6h3aobKOvX5I^4p_|@8_UN{nmaV>FCww+1S6vMKQ&(9{fJrmJe>k!vzB~;6|)%y=0y|={6E{ +&)ia{@>>3qLE{iRfS;6Dk@Qw}i*2NLD63;d=at#ld^7tI9e2y!L66&FS;p;IvJSj*E>akRKpn;dKSp` +N^BG0OW6VpPPFqm(?mpC=^F*>@LSjBu?7Ld~rL&9!Y)zQCkiZOw%TiWDUW@~ewVPY)S1nEYrA{H+99&x*h*qN0{4Q|1{#`NDI92=)zKJ{ysL#)^Yl4YzOcg;9 +=e8_)-T@{etg_TuDa6<7G1h(@@$SiPD0~vT8D7li$mHIPHN3H7l~-DCS8MQTbkQqc@fHjKRSs@bo0;F +*V6h$MgCF0y@tYSLczwiGdQUZ?P~N|)#O +~EG*LCon%VNvBbR^=)U+^7DWmj`n(&?u+agjnVScJWOpA|8x*bdGj#;L-r2C6sJtnaoR7|5`btCQ54{ +8Tc_rZGz8oKApWHr{Bv0?aZ;!%Gp~KP0Fv0GkdY9iTekE?8eR-t5%~>c!A;mWOf+JPNwH{B=t!Hrb+A +Hx1rTUF)&ENYPiF589-g!>WC*{gUIgd8l>A(QhcoZf_XaQuWoe?LLtqTeepho+f~tmNO$3dV0}$CdDf +zX%C5ycve&;>(Qh#%~_Kl?fI-sGn%(MTSbrXov!0Qd%ErK*gxcI4>4e(`TfL!RUO-F5S;w9-A%)1tv! +SiKaG2NCLKcxQ^x<%@~yo}Shyu1{o&ASC84mdU_oNABT$~ +PC7aiw?Lt=v1`2;Qi@%Z1?jrS%-rDZj9Of7ccFxvJ1)d!0ASwcoeu+^8i5BAvOf3-#P01nGA07w6{Sb +6Y^m$rZUl5#eez#eoj@>D?}FFYXSbTpzH>oaHgs90k%vkP?O!{eg_aA6|a{{OtK7k@tm8cnpF+h&BBX +k?_!Zs^+vS=}zCUSJ828!x`Al*lv$pZd}hVK!bw_kq?;!RAZIn3abtLvCY#`jbQr+X%zzVR(-p~ +J=xS!cI?Jz%ZT99{q9}#Oiew;mHd{qOuGecd3KBPr0%IXZJQ$Mu&PF)QM+b2_A|?KQGHVORq@#F81|) +c9y%WAZZLXCUX>06N>f`8o9r4^%$x_}{bm%md92x*VWa}SX4G!fQ$t!7LF)E{+wmHL=to@aC8?6qJmc +6y2+;BUOSi)v=r}$p%TekLOvOB$x_|RHhB%Rbsqrk2c)6P5jez$TBryNiVMkNun=R*+0-gyCe+ePDtT +9-~J(yAMg{Uwb9a%i$#aN$DZD5P-P0 +RkllhxYy>r^^l;2I#}tqlAl_p=|B-xdde!*wD{~U2f;sNjD{8`0o&rYIM(lixO_+fI@LX-6q=<@r4TU +an5bns+l4;Q6Y!49J)I(BHmkAgbArkH;?@3_&9?{v+TLwDaxQ585JO0+3*s&u5B+n&ni4S?VCyhWTbF2Z>{{i0Q)d! +1(s!dq9)^cv0lIKCSXzRk5{9Tg&3mvrsiNA`XTOaJtY?W9_zN_320?D~60z&?kd=4o^eqiY0>5jQNVs +s!Y+tGaU~nDX;|#;B67(sdt!l;eHTS`E8_)=G%n9;aQm<#-58J6@w@T%lD7amo!^{F(J0gdW*wg`ClF +UYQrPS0aTg^M4yY6}_nis{)Rlgz&s?&6}&F+HJ`zyKb1d4_Cl=P!g{^BHhv@8CIbDRxW<{sZS6dGdkJ +HLz7S=-CiQ!OM>Z+R2m)#!$G(Z<+{(p9c$bZt#;_GcXao{_g41Rt@st8Z*-GoQI`37PCkK{X0ig`#w< +dbV$Ik#EwE(NRX#vLgm;-Jm^Zm=>J#!<^i6!CWYuz+2iiVn3a|hj;TH>(N4{2Vr#OQcr8pf97Yw)Z=`}#L1HVm=qa9v@3_x> +L-^;{_7!VhbI@>Sn;Zp(gJ8Sm90GwwEmPS&Nz#UrEl61ESh?nudg_^-9%+k8;^D`?t==^K<9%$4b!IO +?$EaBR@9HspEW4N`WvgxGqZR2n0{+jii9&1iiSx+ELT6Mb1VtMHt##yZRPaaEw^fe+Zb%S^sOFq+G?t0jiu0?E}2tmWPsZ#>X;d*&OjvnAG +={?0P5d(b|eC1^_r+2L=8Q{H!rSPu@Zo0xPBp>~DuSxX?m`oMlOT7oN1_FfC|Mm(_CnLVR{tI~HOIjb +=wEo9%ahaAheygstB=S{JWc)wn}*m~oRZ42n+p%PcEw?BErs95gt@ZzA#r0i(_+HRyfjdD-Yv`4g1kB +A!|Sw(ChSib*VdtF=0XE+nA$vE1byY}&XG7(HI)OC+RPcNjOFlxu<7J^Tj*#sWiOSThqJ|k+>TyZFa- +NFH<#~KQMGbfzrYBSwDns=NSvf5MezUti!yXI-8=8o5Fm1y`ri+|n6wG_Rt?ZnpY9uJCIjk@>s3=ppL +mUBRT&+`}))yqa>qDaV~dfbG!82ciP+ieX*_TztP^lPr>wQ+t=dX8T`| +_>h2)K9hjmkxV_qVcC!;r0YbI5M*g>adPO!FTdO5byfyucXGndQEXSQO&(DJA=?3$~hDDI2!Bw_KYkh +GQ%4io`bWQkkx6zx?A*uvt{h +cCAHmVh+&YyZfz^>5Pnao0ADF75jBGHocPBf*!fhNGT_i#?f3wzhyc?M`=X`Ur+7vaeFS*rArqDFQ{D +lF-W^YD=`Sy8yEGXe!CuY#TdRHjve9A#Ci~;-O(uwM7eUd7G$0LYX_D@OPufT^c=n?FMbD=q~alKo@O +^NqQxw*xqQ+fppXl|jrw$6YfIuk +MPt5!HkRwt+ZYosDAg$m)m=?nLabn7>W9#ml +@^m)KhOM=^kpQxT)J`{EDbxw=MuJ9VSzTQI_w7Rd_LHIPQa4g +$pY?=6faLqQb&yYyXK0-wnHt#HO-Up!Hl2f(I?;E(s>W(ojg7p0-rK;dNCA@-|klRsGwo>tVFMG)Ax0 +*s;;B4m{@>{D4`$<{U=awd&BeX^u{-eI27FDrL@a-c`#@}JTzpcI(jT;8WeWwtIow*LIdy6m~z8e=Fd +`~>xdjI_!;>_WWQN_8*j!9GrhI8#TcvsU1AnR?J(%7SqRUTn$7hBC86%(%HGYO;B=FvS?vvN=2&7XVe +d+HtLqTX+Y-fHspZ(aAu#Bw+6VjrQQeXyiqO7`E0q%N*{z_$}B_8pINoW>>WGNiK<)&A0A{w`ERa6*wL%bXCGuO@{4g8o~CN#YL;b~4(iiZai5@8DZ}&2QOVP57UsKfHRwqfL&+xuPD!I&0ViZ%2 +|r$YJ!aRZ*V){RdbOnDDZF%ULGjw4(W624Paplg;u9RRZ|_1AT8tK~)DDSF3%`x~`9}YT^wAYSk0`-B +mY@7h%b!S(4>cm;ZiAzy0biGHwc}9=ypsvWv>XbhQ>;lw1QitDbehm?rTOBq_o(et#c2V$PI0GX?~fM +p$LWUeMRh8iXF`Sss7n^$0(2_ydpHi)EGqaqzLST*45K&*Wo2NCnKZ0)c*d)J$)(f0PeBpcK_=S%gaorGEG(>|z%jN(q}T^`!!VPpBi^^=CRMJ(R=f9PiI7Dvt@acmRj_^Z3x?7-4`UHjwjE3&&!TqD9Z-@P$gJ^g4=0^;x=+ +lN}CiNkE*!k^t3;Z||9naLop-ce~Z1tl!AAkURwMcw|aJdG@G4LE@?|8B*nf0!B-Yef86gTtM=9`+Mq +e***p<;J$o7IGUrn{=LJZMD3v#kSf@zHr*m0NEkSW)CDZbe<6NaQAHj}*whH+7-xd6Gu#BS1-O4<67=FWDPr~KFh`s?L0I)) +WueeYf-Rqf{0*(%-19lB*Jwxa_@i#T012jo77pyHxAgPm8oy0Imbc1ZZD(f#=h=*yi(`o4Q|-I3o~*- +z`c~7P;-Wh +>Y(7A&eUk>83OoI|-Rk0i&kr-cP)Mi%Sp5Cct$(ZlX?+8D#IN-$yPM@Ypo;_fcOx_CnMfM +)F_tZ65Z}qq_8_UkasJgi3-m4oSb(5_^#Kp7(L|}vU5kP*R+d~QRMFcfaZ4dVA8}=B +h^f^p=<);?Lo&Dx^kS3$wz~*Z^eItiwR*=YaSF+Zy7Ed$Yido~Wcz%DR0uKanSQUCYyM7z8!>yhzss{ +Y&P8a!Z<9ctcTcDh%?QdyvgS~^BpRA3`b@RDO66&<={g{Ktgzt8TL}v`L2QK9BRa9&vFnAu$8aB+s)d +>0?G*J0Vz4mNaI++D)_AsxKcGhh!&<21Cg?apr^cE-`TENw2jk1o+ll +FzM6R(oCqirwHAJf)jQ*<`^SvJ +R)4q2_G53|{9*??r?+h}%BCxPbE^rc4S{;k`KO)wT1Eb#xJ_2&Xr7hC2YxgXKGS(?e(e10ikCiv=li}aHTzIR?v@=QVq)qQ*)ZdNOdJlhbz^-XQnUE +gr$^h3KeGI=Vt59E?5-aXD-pDuEqo4sIK^5^Em$c;K76XP~v511bH55#{dK?if6(5|9Ki@xs*-b|Ie3 +ys<{+Kh7^|^AlXrmgPWMGDcYN}mWLQE^6&y9zpFP|I|NI&OIx7UCx9DZ>sL*<80lpItDDgvK^yP#h~* +6Au4y^cV2$Sh{Q4-kK0FF;+<|)P2agp%jhp&dfoNxp=PNN3UQC90h#NUE>;{`9J09>20%W#&s*W*+&d +%a-w-7O`$8;W{p2E65n#B=BjRoc1aq!Ep8gn0DKjbcP2H%Twd~$)Oh57!$yUU~epDD2PE^48>&(xkGO +>)8feZ9fG`Z#4gFC_2gU@)K;h)miCqd@6aWAK2mm&gW=Y(~yEJnT003b(001HY +003}la4%nWWo~3|axZ9fZEQ7cX<{#PWpZg@Y-xIBaxQRr&0BwS+qN10-=6|yE)liLa_ly3YFpW5iM#c +dHoe$cvx{>qMM4&8isT5=wz}@S?|A``1W8C%(%x;#k(NN<{f!sT3owf!Td^QmRAp80AYfvZXGO`vxy+ +KPAgs(W-CTyN%2@lifWm$+h^gxr$LFEN#h +7tJ4O>~MV4$H8mgu5sO5r9Z%=7$;FXjyQ68z$EvJ7GapirOj|GL_*SU8=Pnz-1JYO@e<_S;-qI&vPD; +gp$pe=S_dfMC$j%9<$Gxcj=90r_X-&T;nmc;81Ioi-h~$dk+IPvH`6R-ndWZ6~79j^~Vv~WA}f&%e%* +qaUJ41!u18NFL6D=^%btKaXq~(FH>(HZY5(tUAR9X)>hct>i~_fXxB)cp%}|5DwbsQXvy{` +E)Dd#di=sC!8FBh_-GT8@-_Pj=O|`U1L8EFq|QsuF~nIqP5*<_M*K|7R}{GN>Z?C4MD5^}WltQ0eiv_ +;_PBo3X>aMOLuu3AbadR|as$nEc9_Zv+3YGT`H!I}F0vP}SB}| +UVqi0bCz1~dWJPRuQbLgQFqy;fWYDRQNp{N%f83?^faOT9u-l`gJYm@leS39rqSTjSC6cg6){K1eC|u +nWYZ>17vn$3UVQTd*}Ldc>#rf*p7KJ;t~M +Tqk8VA44GIm4|}!?(}Ogp-ixc0k!8D>BC`tR(M^%o9WUb9VG$+*hDuvmN4fz{#S$$p{xk +Pt{?h_r;*7kGcd~&rZWUhhBcuGVXXZ%E_N?_bw++N)94;dc{jW%Ex_sJH$lD)dCgS&_F#A6SczvOqM-20>B596^lcYpy?=GVvrgU1tQf<|}iaxnuoK{Y +kM_x8HT&i4lCz?*DL5o41=Brimmh+nxc(!2s3CB!xJIQ{VmqrrV5y_)@yrF_Ev^rxnO5oCEOn`PtOyL +ZRze3?~A%x*c0!f44^xfJrxs)NRG2nY+%Q6ya8=TGXVPfxThD53oA;`>+U4KIJlc+awvoE9)7x@pQxEB2w1D~qH(^q#gycaVin?(!zAF>GpTNzQqdJIN3MTnq3K$_suTn~k@QLyG8%;yLKV)e%t%F%QhG(AZ7@1Ta<-sGi&~sT6^&|fhCa|QItEJBz`(5;#$+)y$e?^!{i%@AIL%k1uU90 +M;Qe4`~+NDu`wzp8s-6pRK|F*&~EVcaS@oPskIH^21&pXDb#gq;${zPAR1^(@|%W@AU=_LM_rJjVK`d +jJ9eZ-H@|6{|3@h?yXkbqACFn`T+TG$H<$>x8#r_H)bjsRL2W0G5U;NHZ*CwcrHcuQD17(*D=O*qyo*~Zs=lM*O&4^4l$}kHrcRf|fhGLb_1x`&A +E^=`9kh4F3bRC@21WE}I(lt^f`sa{dXz^$7nT7nPJ+>$sj0uqjS1+n%UCBEaYy(pVQP(fm)?9 +TyRE6qSyjT(_Fl?4=j>;yg`Om0PI45@(iqap{&UcD9zrj-4PT?5_V9smR-IK +~zIuEs!v^f*R`v}C=-@?fVj#bg6D&eZb+howbjpG)Y96B=Ec4@o11id=S6PM`P8-n&`9VGE;8t9V11z +1zOM9dZoZ4xV^1EE6w1D6hATZ4TD`qxIe1o{yzSTx(Y-*rXXQPca_IkujxME7M=S%D&z|Fj3hpUK1H2&r$+12?xgg#X)N^~uzZbVTOOM=Z&qg6KA^&SKSjL +qcz>Q`(Y5Rak0FLAslQrfOfW3iondDit)Zwkz^SLB9O@cD9|JB#LNL?Sy*}{!R(0u&Z7oA$s^`ATT4T +#j&+V*grCqGQfLes!C?6|8B4xEwlh>eMm>lc7MT>gT9y;m_Ek6t6nAR(Zo?daCv>MFbwt7^sgVj&^{Qvk&%00!TY$c-Nc=IF!iZFaEW@$c8Y5x_Wf8{^jLe;nT-#@Qx8-BCfDPZy%I +7M9sH>T;^QnjT#dDD~2QG4*@z(J${qrvr4+eP+x9R8c*K`}DDXLOZpmpS^tj;^Ln_p0S6LaDX9AC8B5 +LE1SOVk)xCs(RZ=;!F_sA^Z0zmM(oG8e|h!Y3+92xsAbZU7*OCz%So=0l~+4)^4R%5&o9otAD$xbPR` +X6UQc6xN8He}i@3CB56{prB7?p +9IzaUb_MNz^;}{ZGeB4<-FmhePe)$k-r;N8|*ZO11C6(0=N9_ +q7<;k(oX9`rT=rt5L$nsB2&ZIntOy?IYI_bb4@a2sy*&ZHxa;4@kQgFP~pL-w+c6qxl_ChJ!Z8#*ma= +o_iFx`{A65Nvv|@g)`a|pzjXzQ^smjqsd?QN@OC!JJr!h!`z3aM7`OXt6$ero}%+qP0`*q+~DOFDGpA +h8{M}D%6%S=mLh5JkHS;h-F1`0?X>jxfv%bYWdieEZ{X5;)QLv(c8puT2kheY%h$*3InW)^(&#`|xmq +C!Hadr0!z2xVXOEk@hmvZyfHUqLv5_NtY#VXyo*d@*T=m~}rU-*xZk(h3b^Qj-;I%Sju#Cv$HF37l +H`EQWMwKNKUpGkob>53>9-_5TB>d9HhuK=(LYE~lS_v3uV~vD^@pzMj@eG{=(Qhjq=R8JVIy+PNF7^^ +v_(c+B8+DI&D3mm(AzFp0@RVh4pBKg9NKP&9h<=M1Ut}vq+_6id_3dC^mmTSesnGWKw^nFQ3m5^~nx2S!g +r=YE??06L`_HW1o4Qon8a;H7@Tt*r&FTMZsIH$g@5H&?LVZl)uU`%L2&-uM*h39+3La%wDW1k#t29Mv +@TMGP5=$8C|J7{RPtty`$G^u|*9O(5sc(jRkId_@&Vpv+)&vF*{O021GMdZ#bVy>}1Ks_E#5$dDp2E! +QcXrkPn&^t+K2#X*aJI7>(eZffIR4QF&>E_@cD#4*-m$YcZ(hG)-=CeIKmY3)`{C^D<=IQGa}q?o=v@ +{O^H9Ix#8%-o*G^o~TUKROtgYkt_C%+C(^d+!{;1i_Wlb{O9KQH0000805+CpN$=CI52gSB03iVY044wc0B~t=FJE?LZe(wAFKBdaY&C3YVlQ8Ga +%p8RUtei%X>?y-E^v8$jFr7bFNFL217sAzL8pra=V#ZbT)sEr+3Pm1ik7}GC~W17D3oe9AS+@@tSX3g~;50EBLL933$H6H6 +1$M7gKT&5_b^CP1?RR-qC`p)U1`FU|ZtxkNmm=vz-@xmNAqsfUF^ny8VMK);ff#FY$4^T@31QY-O00; +m!mS#!Jl|Gi70RRBg0{{Rc0001RX>c!Jc4cm4Z*nhabZu-kY-wUIUvzS5WiMZ1VRL0JaCwDOJ#X7E5Z +(DJ4$dN>ih*?KV8BC%b}3qP$YultZ5{1HDN?wjTKnIZ6y;cU9E6+1ckfFl%b^3U?GOh>t%15ea0IiJ; +D(60JU7tNUlIzwfx*)*w5T0LWaC6Bn>lvDIo!nrku%9p)A!`}N~xVQBJj+F)%3DnDM)9rSbW_|WV4H~ +HG)u(HZa75mUOR1V2c+1;7KY$XB+4lEgjdtg2#y|p9knqj(l9TBxdVyZFoO)=%YNgWG(V5GE>1CWayE +r?5lxHTrWqBTD=0vPFg?$S?;2i4`b@hr`cHL$=Too{657)@bG#0Wd%NDOe(2MYzOqYN>O)MHpel1lJm +u6GH_f4r1; +0m$ANZT~T^!!+yFk=cD#{aVl1TN`fJ1+F4WHoYZNhT7Sv}IreW^EcBX*Y3P}2a1_$>BbUY-7y? +!C}%io7o0?pXAQRj07tvy<@!B;SP+k_Uivy9O=DvC}tTEo +%eh5stKA^5hHEF%Ux)cT0N4Y4MBxV!dUp6` +|`YY08|d63xLxf@dIPRbFqq5aAELgY^@>PC2OsOTu>G149~tCpNx8l~C2(`yE^&8k=mqrsDS)LsXlsb +Mg*BKN7}3r{X;)3!>ovbX}obFIZg@|Y*DHk-qWA< +EAzAN&qVo^#3xd*n0gaDn>3s2hP+1>$B(AOHXWaA|NaUv_0~WN&gWXmo9CHEd~OFJE+WX= +N{Pc`k5yy;aL@+b|Hk>nj#MQK%ra*8n=CMSJYYw;&*BX%#O@lLAR4&fj;bhegRw`an^hEY9w5W;ujgX +HOty+lStvlt8D>x&Z3nt?mQL@w@)N*PI^8n` +#e&|iUP)7Xgg@J(T@>Lc<2T)f-e!a7SPL@x2M0F7oK%O@%0kZNm!;sIO+#YZJ39dZ;*+>C=*l&2I-Ja +u0;#zU8`)yXk2Z}vs-t;Qz|44>Xty!1XW{G&PPv)tAu6 +tjXLmXhTDF9(zyI~V*5g`-&C=q6^`7I37PiS6C4$_6^Fij~Q0N>t3Ai-~ec6l#xmf6113o3qQ_^VIM} +RwaQLrgC#~5m_i-j-)Xe_5(epgPSC*iDF%;nntYJ@>LDNhYCJzpJnoc!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ;bUtei%X>?y-E^v7R08mQ<1QY-O00;m!mS +#zA(0qU&0RRAP0ssIu0001RX>c!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ;bVQg?{VPa);X=7n*VRUqIX +<~JBWpgfYd3BFXYr`-MhVT9rBBumG*tyW#I@oE4?pA_PVr7^*agdeL{QKESJKD9?$sg|{J?hx^pmjIN +#H2OYe)KGWP4I3K((AnhV^20%Ka?;Hw)KXzvqFq6DAlDN)fH_pkW#|)MnSCQv-QqVE0GV^*cTgOGVit +(Mdy}AfzRb<$L#rr^=r_?;4@aK)?oTJ|9?%7 ++H8>qzs~Vc!^p^9Ig`xB7|YpXni4)X{hGc*xz^#MHvvrDjXctU2`yP)h>@6aWAK2mm&gW=SG|`^1$10 +015V001Na003}la4%nWWo~3|axZ9fZEQ7cX<{#CX>4?5a&s?YVRL0JaCv2pK?=h#3SBUSQ)7D@$IWW)89uCN?TQsdFwQuL@6 +2&6#9$plPGn=$zRQC#4h@P^l$Q&rhB9?Q-GKV>h-NwYP^>q4sfxGn@v(JT`YSZ&rS%vp?t`(YH +oQUv*zlO9KQH0000805+CpNg=>IjJE;+0JaJM05bpp0B~t=FJE?LZe(wAFKBdaY&C3YVlQTCY; +!02l=^mRWEfaqB8k11sa5Dl#zxF^+%Tw08f6_*mRC@qZ8vtz +ZR^qGsBFB`@68gcY`9;wbH$Yt0O;t!*hhb^MtYN?MSXhKk;}#)Vlw)G0xhre)ZTxJ@(i%tQw$UC5(kj +`S{f(lsVY=h=tM2QX|EsjP38^B%a6EtlOqLtMV{2t2OjCKPG23_i)=?j+ZpE6=3E7r`bc<5n+F#&xfO +J${^&PX@)i^x|y@bMRh)X}Z0pm#FCnIWKp^S>E8fWKr8CTqK>K))|Szhd4cHp-*Y`9u2kHSomju*0vG +952xhn!feRJw^Tea@6Y=35b-Hvhad6Ioog-)=-$xnts;QagCNYT$DV^I$!k9Yx1(X_%Hip31BYxW(Y} +z|X<6S^1stZ^D4?HQs{+0b()9|(>2@m5+e#L)oJ)G%dEMC@X3f%Q@56rOV(~o@uEf>NfSx45X#fQn!} +LD&IF;y3JzTI)9h}LjFI%w7Th%7N(pf_cv7%p(nBQ#(T;FYqmzoP$uIZzVj5WrAQzl9w5@5(yi1>FG+ieR>*-NaRWBBO`2_ +$ckkG+i}~Av6!lb}z%%pBc;=h23neR(rbS~K1!+onRZC?Ed(g6M45aOUOmhChHJ2hLjo_KgAuYK9#Y! +Cng~h0Ooun@ya;Xx{Ur#^=UQKF_HFRppN$|ilbX!R#g*HqWeG&>*fv#BwIwmiY=lc>WKzXoe;k0j_m| +_`*rGwEw*%3;U?~;pfB#D9`$V#R)`NT`y2yI|V`yE{e1Xm6Pricq}(lpdi7BSJXQ5nQU!Hg~c<>?gxI5=%NeK3qaN&Qs{DsF!zVEsE~>n`3!<^ +LA;|UOIUW7CbH^TOOz6I<&C!035bZh_y@x(;jqp$EL(Lf_tSk6@B3zR +%QUJkYBcC0KG6>J|xF>A%cd!qZRZD6k__fHZLA!(J%rJVe4VsxLFcu;d(vKMr?j?HXwc0&>GF3?r5n& +>4W5N3Q?KiEN7g|e-ombpQv&mE4Ler6lP2es)1N4C*lzw6NBDZDzKO;6J{vS5`C%pJET>1?SNY_JnJK3uka +#SL11>4MDldBNhFw&GAwV$~u>CGZO+2v9*!49RpbAVMEul4lh!;Guus@`4Tm6WM%PZxM>@{CtKV8 +D++HF*Yt(EOZ#_=y-jb2Pno$(^}T{xFmdpUZ0ra1DA0@CvY3fBir163nggSk%JWfX?maR;I=0M$3u9n +SW;#E0^HB2ab50NMgQt%gFO)5K7sssO<~Wn9#n(ogwzc@Tpg1e}FHn1>q}t->^sHHSH20JkO{cHoS;( +K=jqJj5qsXG2W|8BH6TJ-`966MEYZ?3jP)h>@6aWAK2mm&gW=SFKog~Qy001T_001li003}la4%nWWo +~3|axZ9fZEQ7cX<{#CX>4?5a&s?laCB*JZeeV6VP|tLaCz-nOOM+&5WerPV4Z{3fZ$>`k3*0YD1zkJO +L7R11_mwCYaz1elJsu;?>jS;EQ+FR$&YOg6(CuU;cy<`42R>TR%A2AenMAR~rjBNjC=W?7RtVFJKu5iIZr2cr4BvzF +axF`n7)Ao&K(^*PwvbG%b8Dp_b}Px2xi;{9m6s0zue>w>JtFdX*5SaJ+3-xVY{fOt0Np4sXPH_f)vU! +#OGsR$Qy0gA{I`=2j&hO$LXp#lnvt1I_oE#aDzyO)$x3q3Rh!}Ki)-!iM6G#QKh1(cU%!5R%bp~IM5| +~j8s7*}%^EV4>y6z-!n8(;%A@`&hxj4Rr1sB%WwG=tGve;qVXYc^C)a*mC{K;DAcv>j~GazTM- +HIEq9jv33^=AE`ITTgBzW)TkJ%pVDD@X%=p~x|XQa>1X5zrVwKB89`ga=TT@T5tX2)ob|Ef9fFIlft{ +qEJr&qs4CTrr6T;0>Apsnhk<~oud-RIZ0VUT$1U4H6j*{o#@F_@u1aq6N#Yu)1{**BDVSvNP#Bcb`Yd)f)qJ$kzzi#O9cbskUu38AI+J2Fp&&y1@ +UDtNgGo@27+rDVdbmYPKzx&4n&i;@gb?|hi?fgmJqZOS4t#A@OSTap&5!Wf}xaA9g-lSlIC=SiYGngd +G7+{eGH+WSe=}T{MO58g^$~dpuWFcRe$Ts`n0NZ)2hsx9q!OGMF`YXy~Duq*qHFI0 +f6E*WP_feG^(((TB7l=zcXkb?F$wn2bhbN?P$3_bjl|ZJQI=Vq4s8kgq7AV3Fc0@xu-VxqdN)$r$V?& +7HB8f9Z5`jqedXPT@D}e_i+cB>o6JZnN6aXEC;*qK_wtE?#!8WIOlyM=nGzQ8*ZS$;v)t6)87y)kT;Jk|U150y`~PwAfgIEEv7oQkkJy57_EC0$?9^)+4JjN$2ULgVO)SixVw2UR-77-m!u0h*{Y;qXK +y5+Vw3w#ArM#c3-JW&l?e$J)^D%b0Qo$j>Tfyy@b3y|Xb7bIUvY%j}Q3E_(MnJ;r4UtBk{e8Rv1?m7{ +WnUo>AG0yMFvAk&-ZE=3QoI`m0Z2Mz;S_2zo@pHpP`!lqAK*{-k1xe#kS{T#VvT#NLuOX>mr31;jbIN +;Q?BmPBN^Yp(I^+53tXTVxlQ|yOEt<(O8qNvz-zoFb-XlxP`Ng9(2Dg!rZ>@7(hdrk^YZdHucu0_ +)bEjWaio{;v46JRqZ2j~uK$DSKLS&Oj%O(xtxMahXwDvyuuo|X;V6`Jb=9)b<3C{C`8Cxzw`gpHPd1@OXP;vZE_XIVlmH{(mY@qpY8Xu +?X03(FkSXOn}ssfhNY%vlCp&BjD=iJf=uzH*m010K4)3Bc*Tc0*;^FNi7_#Abatys#C=W%bWV%m0L{X%;)*d3oebOi+!kBxAw1|8pc_id^HHrHW +aK~xi-w0rO0OdwYeGEWbQ%zY;RkVU`(JXQ$+-36qL;V!DUc8a@uY>WNWCMCA~Iw=pgt$a +EPkUfTDEA`WAbz3+=iHIYz#yDt?<#Fw;VH3XWDRTTk`K@@$ +w7c9M|%RZ-asHTX0AgNZz#iR3r8XNDk<2qd5admv&Vv%yDepDL4!rp +OgVUijX4+-xc{16lJTH=Np5J`Mi<@u#;zLsPK+8Di$-VE?#+g(1%j4V{K-+$blpT0@!cB07Pvg2rM+0 +A04Zk)ceon786{3%8VEt{ucqIIsl^@36vbRXQ~$W@+efU#!ATtgpdPAZA<{!QDQjYAz{=Afv+kOSHwt&H^XY771;?)tOM=D_!ev#JIX+C##UU5FHWb3Yp;_qGy=7g4G>+VrP_fmD(n+*W3F&wmntkRFbJtrtNks*7=eCniRWQZe@vqRj)xN!nSz&TxTy +HKmgq_J-bIL*2P>zxj3J?)@tZWTD9GK#c=O7GXmLu`HTgQ}85xU`5IC{04v`PD5s6y!WhGhwaI8V)2c +Z0P8@}=pCHq;j5lFB0)#QsIMbOxtZ=*>GQ72P +1WSZ7ZFU17bDb(B3_F#S>7-JxnLEj;+$wjLQC}_$qDb!e7UYbkoi|rtV$w4y@K}imU76H`$7P>g7K+D +`IU0kNIdStA%r0ejbGgERFUvG`;+%4gSn-TAGbN_F!nm^qn3(WK#Xsjlxgk^WjRV4<(&IY{Y>|QytCz +}SH(Al4bRD?ZQFdhmqalciDWtk5T!wTwn0#l7y4xugFi)Uva;8n^S=QOPFX6B@i!|cS%z+FmH~%mkvQ +6eD8{O2s0?Mo>$D+bxo)-G0)T4t8+zl8Ta`o7##BqkLh}_852_WsdW +mliRHCj3ieu5(NNL6Bs21`o@<^l#f+UeD#?;us;T0*@lS?VTW>pHXN;j6QyqZQC +~_Nda;o~mcJ7RaDquzI_#wik5`En`TrCbWI4Vp}mn;!(0&7uJ94ioo5BK1D7KCX}9JRQ<)k3;8xTE!@ +BmL@I2lAZ*!F}#2RrjpQ-Q-_VVcfbKauC9xe@M!m_m+D4bnCsIA{ +)iR1_mh^vfTDFE|PBrcq)uZt6hDPfrWDt|9`5X$lDznk}z6n_H-xgzo+P8y<;hFH0kTd=!@V@#F8PzX9IM +xaxrV(G>?$M2;5*GQ;yZ(}n+8rV5Un&J-$wB5_ii?cukS2GOiW;ZN#JzpaNYH!m^(++JNj~UQyQ?)N!dI0|3%8=RT{l7idK7e4JFMSEO +0LLJXeBxAF4{Wh<$8gPmwwyqz|9_juYtp=l(5;zN0qsh>Jcu=xmUGtH@dbVlzMRQ<-vL8k?fSrXtk4GH%n!$FI3Y!mXL1F*T0S*xu73U|A=X2B26}EWHCZNgp3`$-r?tdVmSiXgc2{V7v88jbCDeM}T(={0c#*& +%(0pEaXeXq6)+9114&;i&jfHtHm{oAmz2(1Ybk$0<%1|*+fgAbD@}hz-f8!J+ +mMKdQgt|4FdkGjnyxatg@{B2+n_T*sOs|END=ab=`D|W%BSrb*2ihFqE{fBp-mi@yW{&U-cTVOE{ANn +Y|lRDtTyx*T(5bM?T5VORdLjOZ~3it%=$^mZ9TH`mDk2qI&O-!3$Iy5z@~Xx=HXh4TEdlT+-9XXuY34 +Y@jiFU!Ueu-8aC##DB}v%8#)6X7!5d7 +4%R+lE!esSCA5X&2n|+7=%~$6JOmDLIe6t4(=n>VDRy`@Qyep~A*MVCAj7CFR?iXeG0CGdF44@G?A3c +|8|fz6hIn+a*~|2jCX(C2uSO&x|Vv6}3Ssy-#bw46CEE){R12!&64r-`TR3+ul(-2pGkl{2a>>Qh@?< +k|$ZS5EOtvGJXJAiDef6qtCjKMbc8#&OCvo(9SUmbb`Wl!~tm(pW)p-$Y4imI2_uh$3CCD6!z#kTn8* +Dy9#Vq&smm1%&-yt#gpdx5tK3Wxd3MK`AGA4Nr+m!)JY%?f2-u;5OAbTBg=&gI?}G2>R-@cPx~rw +xuAeY+IE+(3mSZ+eZ78MIFMr!w*%(|38h+hw@oe%o~dc3w*)SF;C&npisTClSQ@fzlY`zyg?&!~w7~J +KF-U89jf*3CM*Kp~A&73!dHcZy(v6(bl1B75ZY9YSm~QAKN;HCQ+)h&*SdX9wi!%v7XzJ|C9YDI|{To +g_7^1nm|3ZOJ+JOzMstjx`n}f12Fp%b@5FUe8e4X_*z)#WOq7`M++53jGT=I=ke +dw==ikIUbGd-vf790K%HT3%2dWzAe^Pf_BCnah)t{VpzFM>bE=2> +qeL{{y3yJUflr-MJ(h848u5Iw^?2%qC;gBPzMtGo-KTHw~czxnp*)8|jvp%~9uA7Sk^2exgKg2G(EBW +i1gDGBjsnJ!^^j6%^%l2ne{H?1-M#I4NQWqauK^#G@S +aO>-CJa(gu;sy%5E`4vX;<4t(S>XFS$GGsgJ6#tS!QeHR2Z%T5a?T*PZ8baWxa_nQ9?>SdeRoZ=HAMq +V>j$VOBKBek(alU-(p!gOZq;w&ycyXhGgzwi2rI`n?P>6V;Rk(T-dFO#4 +z4VoD<(cZI*M+1@(DO&_y@WKTpzlCQ}4rNMH*bf9|p5VfF10od +$0pWTrzCtQm?Kgdhln8jN6O4bG(aitjS0v$1dcD~ur5cD)aT2@))H0c_S%bAokU{%Y{Dve}jgxNTDZQ +sfK-_#=nH@h+8HU^;{)G2XJh4i+5d9R-;YtgqHGhn0RWbD#?#+f&8zSO^^!-eHGb$6WO?_#I{}c$eB# +z+NYYQKz`9#WB%`WwjL`Y$OA#3OkjL6RG%Pz_JvTVEJr?MkzofS6G~+YP3);~AP3tX;&Y%2AXr##l8q^Hj`mBW;864y*G#E7^|*H?R +sXBV0-bt~5sNUAwiTvPp0Ci=eaW%c#?d%a8By_2}SN^rlPvRhVPkahV{|7zGX9n^v2j@m6Y2B2;2#*v=FV18^>2eFy|Zn_+|uuu0NfE&tHEU-=4j^89&_ZgJ2kZ4K*DmoHVSH +&vmtOSRhgf*3sJ&wXUq^pfWg9U~R)swH{`Vzh+FwKE*JP%5zJlc8$3lZ|i8TzS&^!ZXdCWl6#l_)+v5 +Ntw%Izch)*dOSw_d1Zz6ua}rKE>HF$B0u$4+bRg>cmXL$zPaf$PgWyq50nuc`eN`%58zAT4mMWmx-P-2JOF}oph1%AN2{+>eO +q^5`s!vpK0eul=Z|!$$gb;R3Ngd8x59?T?PB7vDxjDinVV{6W-CbI2WUC3V~M|eb66rC^6jSA=hJU*g +R@}pZYo7cQ6=y8eN}Ho}E6L-RSx(=1;fxH{0pW_I`MMqi?piXT$qJ`E782GrGQ +sCYU$gjK`0^0T%A)TB>Oszd5~Q93EXykuQ8Zzy5Uo?Dp~K8GOJ0#`5-YuEBV-Chd9|dKhl5PKsIw{R? +_tiZlYXj|OGGsKj$ChV6XZ(`6~T<>WdfW(Ok8`C$|6zDkVUl%licOfbbERbGySV7$X~ScT8Z0m0+5;b +G}t^{TU2n9*=L9A7`ZZOd@ozS=mcf4-);QMank&cEg}tloycbw`1-Q0|Un?^g0sI3lu@daD|cnOJ)l9 +@q7oqw*dY-01Wg?3+!Ow`cciwE&-r&K|v-+(eJz?@Rm7&G_a0P4wSSC*S?g&Fp3QZ4@T=9RAzgi}XH8 +?z8YdGxyo<{?Yy9{svDj(O65l#^>mKsr=l3D7jFa-MQ5SxpRY`|C=%NnPB();h#6b!*B@Us8|augYn7 +#0#Hi>1QY-O00;m!mS#zxj%uyY0RRAV1ONak0001RX>c!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ;bcW7 +yJWpi+0V`VOId6iU6PuwsNz57>;j1Y-7joND^4hW^aqArI@+m+=_CSY*v$abLg*LR!`SZ8S^e6ZsAc< +;@4oYvV6glLB_I1~a@*IO4r9=z2kRE4KSzF_SG +{G-US2r@qN@Is)Ex`A(#_N0OWKF=HtoR<$)nQZ0B8Qb1mT~}N2qxxR`q(Fy6*Y!$c#&_p_zu|Dc +#-}V+Yw10FQ<@A}6kAT;`B%n()|hhR(4%|8MJeG^Nq^9I4B3wN4tW7Q;O`(EO1_5;Xyrqe)|clKWP>f +WJGM@U%%g6J3+C0&OvLc{)!14G!9Jn^W#C9-`7e~X!b=}f#=ISmC%#VtR6EB|SGOcQ+{!x+zmk|`Nz* +{~s%??8<3@G_8)ZcW<-5&V=}M~HT*4QYxKSVLs!TJgiu_B`f8aj74`*z6i-}Ngb*BR{5zV#5tK<7qwl +lazAHbS4klu?W_+UpmWrDNKP~$W}9-i;fk$2pm<3>>@&?zA41OB0Mjw(6Ty#}wX*0T2~CWTqz&r{wPg +?erby_q<`C)qUo^G!RXABlnE2U+^zkX^t<0b?Bd3s6e~1QY-O00;m!mS#zUGGio<0002c0000j0001R +X>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7VPs)&bY*gLFJE72ZfSI1UoLQYRg66j!Y~Ylcb~!v3rMI3Kw@O +z3f=RPqe#bdW9M-N;+y-7yO9 +KQH0000805+CpNiiqKz7YZd022lP04o3h0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo2PxVQ_S1a&s?dW +o~n5X)bVi%~aoO+b|G*_g`_S1Z42S`dSF1BrfzJ>9!cw5{yx8xzTD%#*({*vHyKK%SrtsEq$CIMDl%i +y6^7O<+UmyN%F=tHBS-{Wu`|+tF+6eS05b6+v`{jDMv7ErJSl|XH7m5|5oN}N0W#foQM`&S;=W%zFc3)sc&DOa +@xK642|g2Opj3q4faLRK4CS?9o2}u#<2S7JU+S+}(#GgO8&oMrq{MNAAMC=Ju56j9Na6if!9bBr?_DCZ^5)UD`& +}gqBe`fmcOcR&^ow^16P<_^px#n-i9rz7E3^ijBt#;^+wo;W$PtdPhgjOI4O!8glMYorcJukspn`QfWIL&PDE~QZOh|uRc}tScvpCv!CA6+!3x1+KLO|@A4 +kkw_;iYT)@rk{W`pYAA4qOM99<^=QWu(AD=b<08mQ<1QY-O00;m!mS#!hTwf3x0ssJg1^@sk0001RX> +c!Jc4cm4Z*nhabZu-kY-wUIbaG{7VPs)&bY*gLFLPmdE^v9ZR84Q&FbuuxR}ebcfaf1jpob!BfgKhU$ +Oa530zp|?CQH{r}+b2-SSLvkD +2{c;froc=|k5(whSQ#*ml}epBru4Qb3bX^%o%dGm2+OTE->O>m{%M*U?Yz+5jY*4_#`y2T;08P4umGdMTf`0nx)+7E5W +QzgdRqV0US;l*ss<;?+g!0#xY@ces?q)lso;$g?Pqmh*E? +6<(FfYy2n4J)W3b%Wy}sv(GyMSK%z{t$bf0Kczl{~o^MIfkH%cEn-XlTlBq5MJW|vpoPiCcpe{bYkVPr+g?n!4>EfK+e3Co`n@ +T4MZ2(Zxgajj^fK~^U-78f7eQ1nJSdFsJ#}>O#&P)THZON+4?|}nr0yXsSnz`>HaTme>3(uV}i85G$d +lSaGH##zfem91QY-O00;m!mS#yu**9+E1ONa|4FCWw0001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7Vs +&Y3WMy)5FJE72ZfSI1UoLQYomNe6<2Dez^H&VKSkzuP0{U?>;6s`X+69^v*md_(6b3DgZ8ntXawt1#( +f{5VQj%pkaf9R%+ZsMTzV~LR(P(rHxw97YU|a=m4W%n;iv(-uVO1Mjm}&!sS+CJ!72v^C1xa1-h_Lpq +R6j57eu2W}b;$*kDYbBrd(;6z$Fc~6K0<1!@Brayhb_nyo?OkpVgbQ1jxy!WqF@2x9=)~@woHO%N_{( +lYyLIJ+T3cQhUi{<<7$eyksT%kn!(40*i=5r^QpRVW%}hdRb{Z)A|aGD1vu^=wg{#Q=+`E;??r-6JVj!&q#56MUQ$u;bsn6b^3f1Z@KL^H4dIDe;A5y+5M +C5ypHe@8w&Y-iN8&7`CeW4R4Sb{$b(w;bZ+vV`iY52S!fu(43Gnz=Z9IyN--+0L|J>?N&Iycj&4DRk! +H<4y9<82))1F}%WWq<&L79s8H-TbGPLGw8>;Z@cMie9Xq2<8G2*I0G9gw|m19l^}!&P)AMnF +f8sq*Tn>a=EUh&6Z1vxAT0i6*Lw)LVtmeNIRz|&rv-?Qmc`0(N3p#6p>GX?y|r}&8noIYu#iaqof$1WoLAvZ7&mgW)u?Os<6_6FKup3XDm5vE9xZjDu3L*%~I}A!VscD{&^TU!arTUXB|@=})4L+2%}=i!!nv&l{A*fg=mM9 +-DU`GwTlA`;&C;^|6F4iKA;UKV}`Le(`*s4nI3#oaR$EnD`Z}|MVU3>jKZkU789!cs1WGO%!3g^SI8M +E189%!0xUlCkV`7;1plYGOT82!bO~>BU?gEW1iIxFz3$}zJvSQueYBek3*GTAUJ~ZS&U>Bh1`?Pfn1zEg8%ez=JK4s7wz5Q2_4hikhir6`qyoe!LO4&)#(Cpt^)IV5-Da84XV4wc*#UuX0n}dhh(0oA$TLW9~MUk-67@iy6JAkzBy=zEeDPM#FIEqm +UgREB^yfO9KQH0000805+CpNkqz4s&Wnh0CqM204V?f0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo2S@X +>4R=a&s?YVRL0JaCzMuYi}FJ@wRE7}=Z2(0Tmd7Qz@$v3_yJw0?^WQr& +`?%e^B}Li!P?SJq@@{utJMWz=n`*=E@0YD^8*zWnnwJcY!3$YRKc*-=N7vi#1qS04?sC! +ZJjZihug*rKT#%|Vv_6oM)&3n-(#v8#T?Gp>OU5k>zKG6VhR?UABxn{z_g8i`TLo0+s$Z}B>@Pn5N_k +hC$)Z_n8n5dAEGO+D_3ZZc(W;6TJ=O3O#{R_m%99ooYF!|>_txRdSeXstKJ=x*u(OztLq&`9EE +0IrIWg>?KU4XG_sV(E;(7B)N9&R0$9JP1|tHqG285qYDw$zwxOT6o{g)9lpPI>-Y%-V-MH5i5AP!{T1SQXo`lBhx{ +yMl<)S~LrwUEb1InunX{~<%R^3QYe^__QICwv>-gQ+hP%g;p)Z(kT1jmD920JVf5$pL{7K^up7y+XF; +5vG22};nO0c%pRO{=trB+I;Lfh}GX-k~r+3>)A-0g9q{Ba0oY09s>2fF8JG?tWSD71HsIr(+`(`afQZ +ss(=Nyy1aj{lCDm60OMNJjAsd)(H?MX!t~Q*Q#Hf)o5Tei?{##%}N8mzGC*5g38 +ejkSS5`#UVx8ols{jk2FAS&nZ<&(-Wl`19jv#GV^lv?o6~!h4}wgvuhzBR2K;&d>za7%aV0fMrbac?7 +i)5Xnn6`tx(eo~yqQ-Tq{z@y-sW03Ws&P7lZ=6exO(p+t|`3}y-W!Udk9^GaylkykQlfKg%&Hfs$gVJ +bPkuU)!-B71 +Ps@7s;YTI_D2kcI2n4riU5L;LYMNTL6?0V!v;$r_bD9O^6h6Fz|=8l;aGWiUf?T*2pX}eK8nMd_dTsKj8keyIB^SL{Vf#`EQnm=g@x@X65Dt5JSOW3i9*-^7&)jt9!94 +u6i-mFLM%WhRb|{f26yZ67ghNsWaXN474@1c8=y!a;gLpaUjc52l3Tt@O5z#&;fEg}=BRbm!eMHPYeK +IpGz`dvf#MCKT!|9Piog1e=tYeJ0H&Vfk6l*BZs=NQb?51lp~D|WUVy1m2G#Ruq!HxQIIsW*P;G(bdY +2Tv%ph`e^WA4cDh!DxU&6AYi*OjjX?0oobwkY3iPX?v!1dgCc7rH* +aF_CQe;!qZ*na^iZ{M`az(=!eMFG7nqy3xsQA$G;-YFPr+66#M6|5|9#0?}%Dq#jfSvC +Bnfd3dfG0W#V-IH(`EOd#1|*nPc8`*22NhK(X<%Ve=%97ajsa(%V&&v@@&-KMw=L+qXyWP#RQp@5O#L +%A3$S%zM9ML?8`;XPNyP;jShB>$^s& +fD*)&&PQ*fq*Yg8qHR>RlmAeZG(i>);uj&1nuk5r3T6CEvM{jbJ83cb`drb&QoASy +hp-%3Y177kpyEXZyLVpvA?vBhRgR9=v4OOLHhc!csSFc_?P>10_Rj?1>uyn&df*w!8JcrsuaR8#F6?hxpHyW05d{4B1rF#R(q%(Gxct9M(pbKiQC^=d +SzIg2%GIsLpj~F?wdIzXy{>pLSOQfDo*_&4cFC`GIOm*q9KKCQAq6|o +W;%gjddQoDL35W(e=ZLwRSl*>yX`fV}q()pV5z6@2WTLXnMwlzBlW+g9oQCb7}VpQsj2RJQC-e;IWpj +#e0>PFt>kD_80J-go*s~fzPN>al(7aovrDknmySp(RUjWhE$j)TB2RyZjF{h%gr1`6{Y$v2p+w=qE>21d6-14u7y1~wUTE4}?{y754+P*rm8pmUc)VCu4g5CcUe#c*hXAd#s1;y +PIb<1P(JyVEF;$CPE@e*nfGb=-v{DP7`%|A_2y_4{r@r5%c04OBq1;?fV*Fv9oh5+iF +_aF+vw1n6P8#0LWTn7z6*esItBl9(1><#A-moSEO3V8RVttPE3cx7eV08{543%t}7-{Sf^(JDQHo)3f +@c01pIlI8pD%j=RD`WEw}P6WY_L-i9J?0=8-EhL(4ph^*{IrTPT}^1?TG!5{!9Mw&grm}7}hP4o%U-E%iZtK;Z(F`0B~Y=Uht-nm<^i_0F@50gE;nJdZI&5 +bDpB&k3DLsLP{kq +?DHU^B@1T7=5gJYx3QJR?5RXv{cY~pY#+&Py$jgO}w9wwUy*-PCfUaUp_o^C2iFKzJv4nl$R&|6_bQr +OxyG=(XX#noMM(bc>QBIeRR!^~D<(-N=QZ8{+#cf-=9U++`%3X9k%F>`mEhczM5BzndSmk7lA_@!)sw +7JMR7LMq_^_Q4U+t-#*?60ml_HldgOjpoZN7h$cqVzy7YUs}?L&I(MUd~+1?ajk*WnXAPZr0r%d|y@W +xY=hE-G)MeSX`v`6B1rZ(S0rM;%4$G65ucHX~k=Y`BK7u^E)Bv_< +&kmYQ`MefNch-bD#5R`SkVPJ0)9q6ftcnsGT(17a;)7J>Op4w(|{}u~0!*-daGNUDtTKN0g!6BhnJc* +ZO{kyy@Y_N>2fG7yuO#-50?MNRLdJ|d}`V#Dwn~Ms=H<}jIrdv#N!(Q~kb1s7h2Cc{-n2&>)H%<3DCi +|2<>`mF@E%$DUFSjER^=&YUZqzISLNDXS!k#Nwa~a-iLIi+R8j!o?j*j6P()iru@yoW%snl^JQT7;uB +XXB!ow(7f7L+;Ko6U_>rBFC8VkWNe6*~Dj2e-;skYf$z3;L{p=!nu#t?5CcZxtn0$!yC=r#q-*`|EKq +Z;4YQ6J!o-h>R`GO)6CP+S;lFZD39G$#c6?(T_Y7q`Mv;!79m2!9mX +=YlJDS+=cZlKB$Q4<|$a0{jhfE5RWSsl(b72f`g#%EH$YCFja)M5Jl+Ieab>@Og+tD64z@orLCM;a>U?JA +cE(wWlvJAQJk`tP}RlX^Ksn2DLd2#fV1qIr6yei0hD@o_PBkhV9x|46!Pi=z-?0G;nf{ +Kuok0`lC^LgU{;j=CBBaMB;X)1Sut)uYKI8K4Nk7cRB|}F+Na6fE{Fmfls%4ke9g^9bZu9=xfnH)RsSsX7BK-Ut$iroull6Ib$ +0kvC9d#KD3}2kWK8c#?yqOn>C~zr`=p2mGvfkLHsn=d&;82|MBUlLBRh4P)h>@6aWAK2mm&gW=RO@F8 +JFA004s`001Ze003}la4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*=b!lv5WpZ;bWN&RQaCyxdYj4{&@VkEnt +00KHDMHte!CW9s(yiE%6sFWw#RC9j*hM61=hBu#F<*;5P&;T_FJwo3v64GSVBcIZMBhCl=4=E>T7}pq0IVL +bD0F$3;sVCUlL!TcjZ}5_fRC1?@O+QXotj0rT@-eI!3?n!2$dNx{e%SI7)Xu+C9GRHQkrvsQk~8iF}F +)@PHl%)N9{c@Ur`KSv+|U0n%+*MKFKT!j^+nlu9Jhiu>|U+A4pQ4-D-GG~YE+EX6$#WWT6*hy|ZPVyg +lhdRfk<+_8ohsa6se>nt*GJOIw&WIqY!4iQvxakfjz=DTQO@ +b0n>)E;26$2eC$s<>6bIfs~mfw+e-H?S8*Or6>!Y*-75EfR91=;z?e+@2U$Fqo=pt0a?%Q&3Qq~Lexp +qd0(uX+^Q!7d40?e)djKw*(h6ZF`AsXbPP+mqKDnk1>zM9-N=ay(qI+4rzT-iX46`-=pX#g1_?n57%RB>c<}Uv6E=S}?K$z^1(^X!ao=fb@z3$etKPP7_eCL`HIu^3^2;B}{6?L6FA)1cmD8Y$?vz-C`|V(#zvXUD| +L~o-^;FVmKewb#frF(4!SkOVJ_P6{AkwfMFX+UCzOObmQNBPE-qHI@8$QrkWbpI_^wUQ-MFP +hTnStpaHoA=+;Nh&HasN36-+!hCA$>)U9x^(pLArgN2e><9Ukij-%eiU?c}w+-z!q17JjEzs +3*E(p97hPenY3LQ6+o?nGnPmEpb%Blbn?fDiW~ +slxtM=fGp{9?3Y#e3$#Ohkiaj`Q-@VqNpFbZnKg_G-h3)4}?$+X1ybQf{_p-N_1_v^m5jFu#!Yp0%Ij +Y5jzM}rlV8`xrCF9L$<>iByJX}e`SBSJo|mQy0|<&ll3eeJRuzku%%w};()n^8JQO%T=<4@)Rl_u6O1 +W&ub^|;?f&1mJk-i$-tn~tRmpc~Dn0jke3OScQBz7FBU?82o@R_`YC5*}-8!vuac5qSGmJTmTFTtJ=n +Q{)dGh7_>|(iE{_*il>Thgc6CaKk?4AvA&Z8H)B%jHO|-v5?-L)O1N5CTLt-h-TgtqoDKbQM1bz!bPKn@Q7iJY=<6$y)e4X$oUEZ)0$Ub#(7$JC3)z{|Cmh7-L~nS8?-)R%trE6Cw}WSB1NsTy7|Io_KnatukQU9 +V!--C#2<>I@ft2hz{>>E5%nV`yD@S8PtjoUTnjo@pwp8>k@T;C$A623I}+SKem}kvk6tZ;m^6M&F}1b +NiLJ)0Zo-1$twx3-P+yISAHI*7_-!@AZIFC`n*lCJju(1=VXqQ>x90zE)BCXHBcPxmUaTEwC`N9LCM| +&=Tr>obeVHs3aI%kk_J*LRkHZ;?=DC$;7$*28Q+hxFWWGRxzLb3s6e~1QY-O00;m!mS#zzeV6bv3IG7 +yF#rH60001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7Vs&Y3WMy)5FJ*LcWo0gKdF>n9ZrjN9U0*TFzzC +J4*=!zzm4S^fg@LYPWE~)d;tFGNB(tSRfirUKZu9Rwb0cSlhZN;a`qCv5TO!Z>HfPSztGe2d#bUJ+yP +7Q)B;RbSS`d22t70eELVr(4mOtb?ugZk%%6wU6Y*FNb)wJM~7i9ZXpF +_?Cif7G$v#dC@%IRN1az7j!AA`pNv7OaxsoYPM#NTQUO~f$V0R7c7o`kLUmRdi!enHBMhmqv>Qa$=Hg +lnK-|x8GEDvi`%Yg@ez1Sh_X|+)w!Js}`YM#Uqo*Rc}Mqw~D0k!d>hsO78n5y?4`>c8#qQ*ueTn;p2!Rgur5d$B2^+r%-1htD7qMoi(iGDxgUypc1j!5j7 +NPhI)Su-eqWs4gq$C@5fU^S--rEBkiR6=NTBOv>NoB=Vx2z$ +)A$jh|@N>+KzMF9Tk(WF|^hX=I*aOQ8I6wBW~-A=nT1 ++6p=F+jvib)z!4Rxe6gHz$Z3uLTj<#zGRr1`>m(P3_(rgKe4b#$Q0jitAJBcy#_2TP%i_6X|NZsDqys +m!9PgTni>qg2e{K(cfd@nXgqP2~-QrcTf3gRSMfl1jD;MJq1b&%M;c-lYj7`T)<@+F}9>Z& +VfUS{kO2z4vTG*!=HgV!UDFTQ3TD@4urnOf9rQ$4UljjXZu8rcCGC7$Zf5F_6}$QbD|Drn-_9_ztnn^ +lPz2{E*e0&KWK14q2{A;An)HQG}L72J!%i6 +rLadbel>#Bb07nM=0LH;>u$SOjpl4Z5jEUZ`m?m|Bz%1wj-sbh~BpGN{A43Z9xsw8fZxxmNd)0%sqkZDH;Th(W2ObT%V8D!P6ck*g +*)S}r33qz4#}5MY1=2-HZ)7O#^-Jof83CUl!&QM%V{?ySj9qRjkec+w;jptJS)$W0a8LBFSoswrQ+lf +yc>m4Swj(4w#{VGjLaRZ5(I(wACxKsCBZ49%Xb4obZL^{C|xn2z3RD$jNr{e}eI;-lWzncR{B5@FMQr +rHwA!1MZ9wcOd!Z^llCS;Jb +l&l(=pZ)^>RcW4dA|DH9hIEg15niOLaVr1Au(0}~({OV@$;r;uY2<3KB)Aje_dhy|xzse7mvm^-ZfcT +BoIW6*kv%1;Ex0LG#q|$MVVdwk?FHzlQDQ2(n-41NaWgF6hM}n>+Y|GP@b|=j03TSl3{ocrO<`oyT8^ +E)8O4_+c5Yj#4DkswhNcOdqZD95=9YC%h>~J88T6M`0Cy|_+$sZ^1gdFvDzxs;ZLW`F3LndyHRIW@XY +LMq~3dpJrX6QvfSGpV>ZZ9&EJQ2D9I;<^o=>F%3e~#pTrNK+`lDs0Z4sh}#c{5Es(ul1*wV;LF&z$Da +KFMYHysoP{j%-=bQ>`T}CH_5q&^u~e-)@rW)*nKOmYEuA`Fnz%_&z|Gc5e~wcP)M-I_P2W#Lqt*AIk_ +oK0a~Wp}jHa2s~h+=F0uMGoE&&OxmMwaPnu=I??&#Rvo3=WA}ut!5l|CA!c^1ws{U!H(uadcOS$zR4n +i12C+HMPSq`s$^`Sd#qFKUCc1_EveM@dID>pA|lmo&rzw +uJI%>;QM$t3OC_2A%yw2x>+sCYE9c+jf*l{KyNN%TzTKg}C={(7oFDeF^b<#AkBle%ZI!xQA4G7rO7e +xLLRvdDEFw>B(*z_E-xabdL(f_KpMn9X5#^snW5p5|DCK>ThRXJB~M-pXhTLrT?t*GOi!oM!M1w)3(r +Zh7r7fwJUd=WycQ`_`&yvG&E~X6Ap`X)BVczIv3_BOD(%xPEaV(yxbEl+ow0K$P0OVJZs;^N-xV*1-q +RK^(3B-Yw5dsD%YP~x$4S0#KzTXdExasAo-0tec +9$8aogk%2NixYcXJO8g@4fDgIzLNFYi=Qt?DcdJ)GquE=XRU6XX{g4|X~LVvt>@zeWz2X?62Uog$W2JwKl#p_9&$z|Vq ++-*q0c0^AU-8Y=oX^?Z{pytF*S56h#Su?710pwmcd@ggnficosnDZb7m%2RI$EI4e&5W6fhAix~v;oY +$H?Rla&i1;WU<|4!r+5cstll#?^~uU(7du8qCbkeI_62h!LY!H(H|!4-;@ +}Ssrj!2yP)h>@6aWAK2mm&gW=Y!qO3-W#002=p001ul003}la4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*=b +!lv5WpZ;bWpr|7WnXM~ZEP-ZdA%EJZ`(%lyMD!%h9RnzSvOw}$W;Ln+qniv(;#uKSGYc6O|C4~6shBq +c67b`_nX-lcb7~0f!qmbBa`#qnc11yRTM=(*LhbmvaTD#yWOsC+M>E9?S_%^^R`S_+c5ZATs5@WC*&N +S7dfM3!y5R;Nn4YSGeSApcG+fDuLWvF+v3)s;oDu!d2v;;CAllwP2IJChK$w?y)J!b-MfRXeNbmI0p)ZOK)`=nc7I?HywkX#j$9#-&tweOGZ1jR+AyvO*!<0YzF>bqff)hH<1x%hE_hP( +%J#!gnky)06NgSK3qnF^i&THd{Afvou|IZP&0g +CB+uklF%z&mtD(J`S+6K#cjchx>}O1DzZ9fX<4+ap(URkklh}nZlC7`r=Z;mlx$hnviyi<8RL95Q&jI +HXRiNlnEuB1T*;DX5w2j7)T1P;E8bExl6vXuqTuvv1Mkt4ZV84KU(&0tD09|uA3ZI=0~q+Rk=$}>jXe +W_yRtmTXDf2vbZpkr>$G9l?DGzuGz`Sv?!Zgq=+F4#pIfAD+neh@?jiNo= +1xWr~!|xq?{92`wrio1AJUx{Q>4(Jf9KxChQuZcaqH$ZceUmE;{2*Y0a +KK#nk@G^M!b|zn>DekMsq9 +m#_vV7t~qO87bOHCJT@Miys_WJkhyMw!f6f5$WAHWC?Df1bXZG4uDPB`o|^X(Smp5V>e$k^SQAW)8_H +?hHa%zrE*n{J3U&ymZ12P3=YYJ1s1n%~awca3faW%l3m!)Yx$-p#DIW~@>h%ODv{wQ-iZvB2PtQ+>d@ +a3VA5jKDTI7(ggNXX$Bg)`NyQU0isy}&~r@X~gjDGy)^p}(K-`<~*L;fNnhXaCWwbTh%mpx|>;uATXN +OZ^}@xK@F2DrwLQqst@d=#27>f_KXlLqlD_xR5tN5w#&Ihm7hNi1ENd`F%wmf9SPAsI{tItO5KRuY(m +F+jN6U@c;!Auz^XQFlCEU{QgNg-I>EJ|4?)QV-yLKes`!+vqytg_)irtjMJn{hfD3> +{Q0U#&9@1ejLx|F;fU-x_fucC_fnX!zv^jC};aVsZ?ENq4SrJL|7S;D1fx^%G7D!!#{w$X*2sXLRtU`zx=Y?*gp2Tf%%yeq6S6l8MU) +ZH%rVdySm^*pdZutVBe7oW+hucs6Fi1CYxU*2QxA7Q=KHs;w|5}D5X?#HQj5-ivMu`S=ho)e>`9u#r| +;R2F9RHAWl>;+t?`pRI1d>Q{Nu0oZNd;?7w@9RGMBVt~Z`nR;~m=*GgL`|SW+rpkPvgH`39C#s84X6H +xx?#^mwj;i`g?2K7BjLwwJT4x79_zIFgEqs006X^;RzpM;56WA~INRyE%O(62wR%s`E*x7#)%yG1hM$ +0oaA;>)9`__i+@lYdxu~O7SRc;EiYbdp!0YY&{^%s_GMd^d6r8_>qY*?CHn}MdHbjAfa` +o-ErtwzoSeah+qtWkGl>AW_RovW~4zrd{GRM2dNHbu*o{VLJLwlx%9k_wKHq)J{(J|^SSo +5)8sa{+kxcUYw8Pv07ipbfCbL;mZubG?)3KE(kUvv1#|SW)=o!VRmoL#}H!JM@+=ecu*PqN`adR7_C3 +=IAt6!n5ioFDjhw>anJ`ZdE_=RNL5O1etx@(r@{odH{*zA`ulM7Z8XmD;n*Tc7I*);LZ4QNX%7-gftS +;4ol;QCRQhF&c0f9^hnuyd_S@-cKAOrhX&NbHiNWN*JJ;Dm38LSd0jG+@!E@d11(_Awog_zFXkT?>Va+Rt6Jfri8T;w{=eNo-P?_oZ_3AZ+5V3NuYE +Xs^3#6Ab#E{27v3P6I(O-H;^#_$=M*6j;m%VqYY4$)zHQpXP@BL6N{!3F1#d(pn-u4r)sPS15?kiliK +p_QAuF?UYD3m40iv0N{5O>zty5F7#a42-*i6~PSCS&h>rmCx>9c^%=fCxu;cE$1mP0S28Y;V_&V)3S$ +3U|ySu-gt?bz=Of%KhliL;gio+<~iVV%2~~tjG2`ZP(NG-=6Cp+F3E!}Mu2{pwzDYx7n$cTkoF} +I7gn1E{0KOr4b3|BHV#-xE$jqN$mt%l24CO)%VT@AtceL%?O}pgD^7G?t!F0V6>E0Yn_sD~363= +~6v@#b9q4-82z$#Nkdhw4oXN4cjz8-5*yE5F;S`@IYCXyF*!heq)$^PSQvH8ejc=e@+r=Kh9=~)wIDB +l%I$sQqU*y3da9PC@*v1Y0pYf3kRE#ImymJ1`E6fCpSK2G34a|Xr@(X> +vB)Z^#?VoY^-AQQo7*xF0SwG%pYJGzZh+0stRx)^$GJQ#JJ$wVwKo{ntiHE7V@8k@%1&C^)bQfd<_O3 +;Y-SJRsJ#vYnCx>gRFR6G|fZ9p-FkaJX`H^k|o%9xN&zB +K%7RmaB%nniekFo1%m2vrumZ@3phPJ?cKl#}S`JrkPaUSlTdcc;>ElxMW{4XZ4Bsa;$=zKHOzs5hH+* +GU2BCl-)(-$?=KC()%d(!l8zGH`X&_udlx5=VHMY;d`dunTFC^sl)2^S@!Zj60yrx%oS3hhYnT +Z#f5=*)+ac1(bZSqS$`oiwRZT+-%gewHDbjwxkN)c$+es9_@O*-W}U$>}3Vfj*b`gp;hf8vC +`k2szeG_mPKY6ivqE;Z2RXIfMbPzBaGR#LB4u3$Kn3vbl-q_m5pA1*^v=fx9Zgyw(1wuYA`^d@q}_H~ +sHF3a+%0OB2N^0Bqo$tGjrZep=*sDWKSpl;!G6GhQU!)VKdRK|Yd!kaoT!OsDC#pI=6b=mih?(ym~DE +^Gx)y)l**+mQZj8}8?61G)S^!^HRZBe6Qn1*rPY~@r?T#HsR2%o2G1i>fbdfkSi{aA%Ma+W6+v2(nrj +ny&UAFh}j;CEb-!vY0IM-s0Qx0|KHb%zqToBsikLqf^?Zc}6%b-5ar)699*CGHA^?{Pu!kLt#n?W1-e +2QO&Y0LkEdMN$3EJE6hR$21~_hXY|Y59=^|?2e#=Xf_lJF;qbtN#i+r|LN7+Hz)G4-kcnc4!7VFkLLL +I-Bpo~C;=%eiu}tI0h1f)N3Is_d69eB+MtY04FyuNF7WVR9xcd=6*(5?0M?6nG?y>N2YX%?(Tgj&>wJ +>c6;u~ckO5@L1eaWln90Ao8mhgbG9KUl_PwR0V4&~wY| +=4*)S$;PegIo6afTIv?0JW&94m6Rr?y3x{uE)+wuric!Jc4cm4Z*nhabZu-kY-wUIbaG{7cVTR6WpZ;bUtei%X>?y-E^v9xSZ#0HHW2=< +UvX6t)aq-D5+&Jnwl5QqSQhV|d*O4(ljAsk4w>Y +fW`;=tat(#dD^4}6r2=NCB8G_#n5~l4W(zr6uc@NKz>bMrqe5g9rBm2Y(a6dj6&hHMVk{#ZAE3U}6iS +8Q8O`B#k58zVWPei?d8=s@EhS`%5<`K2MTUFAcT_od2nc!)W?xe4sJFY96+T5sG?L4R6(y&I^)FPHw_ +h+sn4mixg_pSWhhITgGAZt?uTmuF7BMY~Mwlm>Dn>ZE`2-4zfuJq2vw_wohz2b=eyUC7O^ZBI)Kp41D +N*MUBN${Ujp8_tqP3C*tXAs^mFQ{(=zvrRbc?{1p)3D=is`>&8vUF?C0HhNy5bI->l!0X54sqXHUvXB +EUYTSxIQfBbWJL5R@8C@dkrd22N2=KyOy`*+)JNuV$qCH#hh+?wRjv)HL5V& +V%3%3>HX2t~QsT3dtiGVT!D!;Dw#Wi3Q~BkS+ZI*M?OXWs+d9=A)PcuSdD35hTYL5ZQ$(n!C +OPgJHjh;iYPjd0+E?d>KvA60<)Lmx3pk_;U~O!`?{BxzOLViIXw5&Vp+FdoX4TQ2Ku#>+Ve61>s-_;S +oIlaJH!x3vNg#tH#;Hkg)O#wsdg^8$55_3%F>l-*7;`Z11wWg=Y20{7?fkt9Nw0O6OsvuT^t# +j`VoxZUOg^lA_J`s~{CNX};~WIr6QpyVo?`g#I=5({4!USrFpnvQoB9@;#8UsCZagS!R2`fEwvm0c`q?gc*iZqc*}Sp=&+;Ohg}4LWC;+ZJY{MtR@pVW& +>m^&)4R_TuMR_v|`hyKQA>+iz9Q^Pw)=A2|`MBSu)uz%5kQjKV9o%qog9oP#PI+kGUJSA+i&qrP)T+j^(Ju(ZO_6FCAP}W +qa@s+fjcR-2z)lF4duj;_$KMlNB8y^Z4W?(EZ8&3bNJ>RpF__{X9b_e=@-ewWPq1^9{`@nV`$R_a_CJ +bJpIoedLH=sWa3YWc2szWR5E*Ti`^5^%W2zRt)#3>S(!EzoNMh6w}79A3^~EL!1}}3^T7~hmSkgtzA8 +$yxA#5LJjS7Or9igASgr&$(_< +D$XGteK>K0qBp3}oH(hTZl;!-bCF0wzLFyNcZ^J8rUu3G@OX&!9sUqq$!%^fPBKh8UjKjG8*2B(zwQ? +WYC&(%Wu=^B23t;a}rG>W4^6MVm~fja8B=$B9pDLPV?A$&YU);X#8ilO}Id;1b`8oNrS_W_2YVLLHa+BlKwihkI_X&ohuv+PwqCN<)B>^y(*_Hy~>yDRH{Y&m29J&Wxg9wlOXg^`}25C-!QjW)Q4Xz4w+oWg2#^3 +-`~`Hx3#GFBO53jZ>(|KGH>p^fI?Sa%pHfi~WeA~?sRAI6oObLgG$Y{akQ<=7eNeo*~Ko8Fm)-=Dfeb +3|*3uT{Shj26eN>N}_)NP)h>@6aWAK2mm&gW=TyWn82b0002u9001Ze003}la4%nWWo~3 +|axZ9fZEQ7cX<{#Qa%E+AVQgzv$p5}Oen=-vmXox65y`vz-3RZE)LNH0OOo~8?6pV|Ci7jX4deG!srE)BZara{e3X?eiw +WBoGA%QaC~1V|s*0jDVtmcjG=r}PSOSY9Os8pCRE8I(3dDlvqT2CPR1@}C%50%TE`UB^cK2e-HBSK@u +#p=A8&Mzw~m}t6I#i9L0M +Hr1-Zte(~n_IEs!!iwyDfb193_5oH`jQL1=Vu_gke^8T|(&3I;Gmx(pxj4Y%{l2Ikpdcq8_dMXawoZ= +p+!B0fxK#7+l5}M0OfIH?Y-??-U*+T15H=+WUUSD2qsIY+aE!cmtIqXC{WAO)}C0FuaVIlBjGj2FgK< +rVqyX=p(5~8@8vSfl<>P#RT(XJ-I5I4O013Ny`3phjI0LsGsC%q8sE`0L4m&fAm`TBMT!M +wpN@@pN=}%s&zP^}W?S1&OrEuDcALXi_ZsX3TV-N3zBT|>n4D}{=2%1hhug`o3&&0H@I&CTGDTjJxf8 +bA-z%A3WplWSU|Ah1BXYkSQg-REUY^ZCA#j9g4_B}QxWcqmfkv7G@ng8`kol-T60m*oP?TSafCd-b3M +9LTw8Pyv8OzO35$It*HNy3k)_=i|nkl*BHp1ZbdMON-sv`Eh?AijDw-O4&cI$6JSwdg=AmNCL&9}h3= +g|4BXRk&%b%{e@12zM=b_uBZ$l9bLJm3>uY+Y(*$_KDV`aHLHN)6bRXiTtj0~-AsvkTF +CXy;uW-ID8`9$00 +w1Qm582kATgg1GPTZud@Lkhw{w-Jq+e;xZRqX8A5bF9fN@WT6i8__-E=Owu89RdvOfY7eHc1xKU0TGW +49rv99|!=|`lgpKM3{rnTU(^>wTv949*@j&{Rsq@H2K3wm)Fuk6WTyrwskn4E23VSI;1M$|SHS2rrR` +k}v@`Hp8p`K*Q(MyqhLo?7pZDwx>(ZNm|gV>qp^oi{cGPqE%>!5@05Me`n^DM4N-XHx=@6aWAK2mm&gW=Um=Z>jeI004yr001Wd003}la4%nWWo~3|axZ9fZEQ7 +cX<{#Qa%E+AVQgzP{0R6RtlpH6*zL!q9_Df8YM)i1tev}DEj +XuX=<}#r{zJ*%$vtI3t5V$LRnUJsuPf9h*fPP6ru;&@J>N?{>P|bMv-m}Rupa4={kFiqjZ}P>j?PbPPDIw7c{r)pEmyNJ4Bb+m +-e9LPr?4ajChOcmvesH0+C)9ivuY0xbLyQjJIDM^(4@T!YTz>k2&?no;7=8lw@6aWAK2mm&gW=SH!5HS)3002x9001cf003}la4%nWWo~3|axZ9f +ZEQ7cX<{#Qa%E+AVQgzSZ#0HHW2=bRPB|a*ANidje +*hAvt?68D4y5AXz)B2q7-GEY@o=Lj*Yl)!x*bYu}bW=1k+f??c6Ol&%Wrggr%vDxNIOC~RdfR-UI +DD08SiyaXEHuQa%1a?3@c#-He}27r6MhZiH=!STo|nOrt-#La8sMi&NaP>PB;-(78p15=FPy{;>r8v| +h(Bt*Z+oJ0_lgxg1&d_mW*@QsczQ>kyhy=d9kuS}!SH)BTuQ!TzJ+`1NBGHw^s#Liu1X!Cz_RBSsnjG|#*{uo1 +$l=?vLT9_`GEnd0ou8^QG_JyHkZA`SuhFvtJ%Fb^?Zq#r$7KEFd&zaixM99gA+sCUkc0|Qx3==s@JBj +rE_dAv07vMfuo?6vTcRz;J95u;)a#DKPS-C1w1grkZxKOEZEg>k6ZiH<>PjMcs~1m9#MAOS{=BE1Qrg +EF)$40R$)qPy?rSPWrH<04!hO@iLLx_fLMb$u4UAaYdp*;o7t*-@q@cTPf0W+^nMBsM#6|IgLI=aC +lc7rRtcTTwS>2ADHe38CrDQKmpH*y*eiz(aw>BiO^>^dstMjaf6{9&=6*oLq^?>t-%XAHATVow%eBWe +RFQpHCD{S!4$ipN5Y|E&Sa#Hc@C!JDRr#tHfI~Jw5m!Iyr?5uBm|*7Y|zMd9qkUM1Cg<33>x%~{{aq5 ++|npo#5P=3v{y4JjIA{w2yq+Z{U%5LBb&jvj0k%ekeLNum=@jYOrPq|rDRCyWu_tT1^?cJIF;Hc${3CV;+o(Ba&G>;ZtlH +Bc5v!$K+|+LeJMZ(4m`3h{!XKuF&<#5$=%XjrNE$Vxfus?emaTCcX@CYM=4FW&=+5{VJQi9+j;sa(9swvnH+urF6~B*|x%V{MOWwEa`6a^SY`f<&7C +=boQOb18JUkA8*5sj7;0C?uIDPsfc0aNNJ4EzZ6~UJpX5luNp>dF_u77w#7gy3q~%v=Qw6R1tcA15ir +?1QY-O00;m!mS#zo4V*`41^@u17ytk+0001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7cVTR6WpZ;bWpr +|7WnXM~ZEP-ZdF5DJZ`(E$e)q2+9CVd1N2vFhEdz$c0Sc^X(RpZ!zz}GOwzjhWR0p#dAI$e&dn+bsr-w;W-B#%YT%p3d&1{CD_rGCdUkb^VlQqeqNft+=x2?uJj){#R*8Kn# +v3#L>ioKI(D3fAyMO+&CT$*7d%eNm{OSpUHiRb!*=am;hB;y92j+suG4YhQd7v5f6mt~6b@u1rjc8ed$AkMKK~jvB1C_HM%R80{0@#Rix@X}xfh +((Z#*>(*-v&;eq+ZpSt?$v-+3D{_#T@eIBqT!#r(Bi{ +t`|OIe`+`XO{I8sJo?-V)otNgTmd*!3w^;Uc(ZoOFj5g|h((KaMzT$(WvG_B7zL6;-sM}_M9?tyJ37)MO4SO`sZ(||a5iHo^%H^06 +f}|{xh8Y>yiK;%63?jgJ(;i0P&85kzr5lCDZOGF$LpfVMk^>TwtTuwmK2Ej(kd-m=Xor%To&3&&7Awy +isyQQ_DZKzC;bxUw+}S?1o@6LZ3OneXGtX_Kd^3Xya?d@XYF-G$`g21-K1R7b;fQ510|lb^!h*r$5+> +SCbxs88*~wEMlvpyFUOh^a@SQ*$&^-dyL&y9I>p+R8p*9o?+dPO>w|6=VpXj)7w>5W*~!(T4K?28a9567^F%)9XX2-FbwWFxC$*Pm}1?;I|Ujs4d +J21lmwDQUs?!sFW{Wv+3*bwPEt}opXzSW+kL=|M +sfKv#~l;>2ONPU@g^!8LGJII3WM}SDb3I;aOZRl1AII$2;ZYof{=m +|F46e^eH*VD1>CHr(NSC(`qzRxGP5Vlq3Z(AgTm +95EH|^xPp3`P{e99_k6okgkb`}D1#OEfr4K&oyzgKxAxYjX(Pvwvv%s|YKLn%2XRl!!KWu20t!eTJqi32IVo$RvDMgVm2_$TXBL*J9JH}tQOn +RJK-|@o9-%v{f1QY-O00;m!mS#y4Uu_V`0ssI72><{p0001RX>c!Jc4cm4Z*nhabZu-kY-wUIbaG{7c +VTR6WpZ;bXJu}4XlX8Rd6iYcZrd;nz2_^~?l5N%g6%pWhb+lqz>;>WfpsVfL$&Etuq*|ZoUR!5?-Ok& +mTP-Wb+ILpk9_2llomRNC`wCP78pe!^1UuB@CT!1X)&tj3=(k=Mrg&LR3g?1Mp9TTxHOYVN*Fs-=26U +IUEmSq`;6_kI`|S#F85WVS)IQ%M6QvkY??C`gsCwB$ +&GLQmLXSFeuYzoyI%(Ql=>uU>_0iKtaH0ctVJ|f<562Rc)qPO8q3%4z$9P|GvP3(4~PnZ2k3A7d0HYQ +_PulX|-`_h_rPV29&lHM%U;FW_5j_$0EHSN37cory=8lbc9`&oCcEj6F+sbaVDUKwo?WE_Q_{LCGNOz%Nax`c3#qC0P}e*)^1$OcMQ0-g?OOC5J+dA1nAb +C*-Yw~OPco#Dup&yr+LT9$^3wY#UyHD{rTIgTgKo(WowN3C30lkolqT_7z1Zs9rzI;^n%_6S(_h&tfe +%)cL^POC@9TA-(5c1TwdM-cP*-l?dbb=z&XbQ^Sylz`7ZFt(J$+#$p+bs3= +%kL4O~R}-hI4>i#c6$ZskotQXo=_p9Cac%w=NSdUR`UZXCehZgIcLI%WT41*rWS8qGl>l);Y8?G0jd51@{Omu9Y_ZWN_P1EHO +j6LqX_j^Rdc!Jc4cm4Z*nheZ)0m_X>4ULUtei%X>?y-E^v9pT5XTpI1c{qUm>KJi!+zF-NhcT7;K8|URz**-J; +hQ?1ye)D7G?D$F@>Qo=pDzk(6Z1d7Jb)hc$|su|!cM^^hXzK4G)V87ovNo0}`v+U4wL97&SVXp~f{xL +wLhWa}-Pv9}esOQq|XY)Y{f@T0Memv_=Ay=6$paDmB^I?^#@Fj=3 +xhvprCctP-(eMO&!l0cY6OD?oUMhP*_9T&WD9O!N;bygn_BwWwN?dkq-ognqv1E=DoLI{e@=q1IYZ8` +L9ldeR4q`%@r35B-d-hHmN9&gIO7G0oK9$1+!tbP*^3GV*diNI_6ycpg6cibDI0@;6;Uzn)@0+D5edS +9_B5A*H-G&#wrn9hx4@+`VsGJ%vP3mb!e6ACnVs}YXPQilN^pbPo@K5hJYRE=iwHK-u4u +lK@*y!!vOG(uC+ylHX4Ea;GOHZD-N-_)rB*ewE5Qt}1#>V0xsHf>004f24=dH)tXQMKL)yj)jr-lgfl +irG1Z6leI4{69ZeF*Qm22<=D{El_o70-UB7jKM7=SJc^Ga)_!QBAXf)y19goD>H1?p%IC!{7?e9%5e* +6^yLebKoNti)%4aNzKwaT|Hp117=EJg(VFRiz>0669iLJ<5R-zObcxLt*grycWR7sHR)`k*s$@2WQ@g +wQ!7RcSH=^a06#&gD(x1yixWKQadL0%NMPsb&DJ35>G9jep`LeaG7J1HOy;d5+;=-t +^wIX-#N#e(sZBtmKDia1&_m{!FZFqBgfy!ZE!*v6%CP|*KKb5|9IDY%;?az!iC5YS1=;cmmgZ9BV*)d +_YDqD!-iCmImD{i>8I_(IiY~;1f-PmYyMds=#vf(^9=HAo?8aTQ~=H_9m8)5SXJac~&N0J4C!7lyW8< +;3Tn81S(wDX4W@&Q~?wH99oSRYSgIE;JfB4va~dF{+uL<^8*qj?IMM@8sZOs|8_c1WG<|9w;sN@z^A!{mBhRo_4ie`S4_W#Ee1Q& +KoGLCd`dr03n|Fixt0deNlpY{5%t;{4COu+cTwgc9lE{u^uWPy)4>BK?RfT@yu-~(wpoeB-8KaP3avz +O&X7w=OkP?8`AG?vRRiRZt4Kw83tkK7sNzM~Ri=~Ze1!&(Kcv$8J}M8x8}k_ro(~=a<$({#KG^LMr0< +>bkm&A$!O%T8hGW;wIfi$eJ%Z#>06E(o%yED4>Dt-;5N-dR9?^xqG~#*KBX|>JM(otQ6ezk+jbO43xA +Qqr>h|50KN91cv~V%|d$n+QLu_H8f@yh|Ts)|cli*SG$=|QI7A2x6Rf{j8uwEI6IgpLWM%p}2ji{DWS +ZG&%79SkUa18EE{FQX;LIUiTSr>!mZ$Qy#c@PJm7l)%XK9}rz8CXz`UP~})$x;A2ahyUzBQ1ho++pm| +TM9HGi(iT8c8u_{$NM>ZHpSJ4ZVhrRyW$p(vDt#=g=$Iz*1cXv+&gL?r^Wr6N>|LPLf}IcjFmo}7Ldc +xsYYC)uzgI_U*;(5fk+8SV=YR_t$?anF5_LJ9YX%So6N>1(qZkohBBmvoD3XyB*P2T(9E<8!q8~apM0 +nW@#K%3^}E9n2%qbL#8JXM-Sy>16*|w6QhS^q5&Pc?XzmFB{04Al+BIg=hXogxBKHWQeNsem^bN2bA@~jefZ>SL{MRAF&HYG+CaL$?_cj!dyDfr@iw}26rsQktnA0k#XmqT89>pS +&Kq0W#Q8xB!Gf9C~_nUO?`?X$~m?H&WbTRjR2A~ZUmf17wt@C_vEncTL=MZSnjMf$vQ=x-3AARJLUxZ +IaG3F*$hfQ{O!ouKiP<=c20PujP(VMtNXC534`g*E^Apj{y+nNN7HiIDb|}0AA6`i^QBv~9v|#-xLTh +s5^S{fZM&Z+3<|C*3CJy#uk7x?)3N=x!wBm=jIU6iLjIyvOCgloVdYILK|avN6^Kv~(%5K9lc9 +uUgkY}G?Bbq4?%4c;J-c7}r(fmzWyg8+rvWvZ9}MT`N7CT|Px^TG1hN77wH1sOVv+#o29cXDFv`ab1D +{Gysi9D}#zs5iy3;X8UB%uu6@rItMLotd#LeusPKIZVs~*1xg9El%nwNU5^N$0>Qemab +^+}yEUTdYspdaAN5Z>UQtO4Yg`{@z?bcl%(vAUe4TLx9if>kkGVquccCKB_14Dtk2xE^jDMu0RjAi3y9;jNF7V4GaQKjR`Uodq% +RU14l+fZk0ZQe6M(*=Mwaj&Sk>8KLB;3E7F?DH&=p4PhM?cGSoO!VU5I;p%hPsuB(HpRoCy{op&~mf> +0VJK@`>QAnUhpMej3o{G>4cu9vy@tBIcz3Cw=fhWBNv(cx~U~$L??jUV(4XOnkKH#jxE4&7{%7v_?-T +K1nrAxJ1gMed=*x)x>Jn(A=ziIf=fP#ciWZic!ViC}pRY1}~HGBz(y`7e2fn!V_+ahwKm?VoOfK=|_w +xeU7d(gOp*7@IRU6SMh^VUf74fY+-A2INNCL2f*n|MI>Z8jc$jrd!Q>_mBFE1Rz%ig>`xL!xXbNNngK +;kQ}Zr#-#`-Y3ano{)eaIe^2(79B2>W)3to#$HNUJ+!JO%?CX|&4z +y$64BBDr6^)@yHUrqf4H!PZDuXzNP#iwC9uM}I2;^1enxmaN&S`8A<&(a?J`vi8U44KZj15Ctl7w@J{ +=Y}^Urc!Jc4cm4Z*nheZ)0m_X>4ULY-w(5Y;R+0 +W@&6?E^v93R?BYNFc7@!D;6q(NT{nOIR>zc7HEI~c^n#`M}f9hHW5m6NUDzizDrV)t(TqXVw&O(XJ=< +g#5g=q@B*h*!9EwvPt!PNf`f_mQY0-LeaL6F<Mb=x?@~mHiIW=?B9C$xVL +}&iWh>Dm6-+5eSQjsEZh62I0%B3U|PciFJB!n;kJ9lw=OyiLpuX(wL)5IBrwQn9aNf^YhXqed<9!2x2 +Vh>WDbJRqMJAgT>N6O0AT^<-EA(lEYJd7#vfca1GBO8F`M5pK?ECqexnR?BKcNvg^@;)&zz{F!u&~=O +*Zy1YJb}ihNzb=B&kaNR$*GQf}{?2%P>w>LTZfSHUQsOxHWM9{97rhxk0 +2^o8d34!2I8!G@{K8N^D$P10FED2ywPPMo2J^>H)SGO4vk+~w=5^!#U}N}ifEndil23BFDVz$4o)5q5 +a_4qJ8pKi!n(#T?4EfdaZ4jj5YhE(pRojY+deBZ&#qMieGY +3NC|Kg>>39Pl0&WCH6jIK~fCsjFkWnDH!@0p0GowdAWmxM^>jCT-H}(XyC!#-g!jn+LC-j=-Qu$-yli@DoEi;?xRHv)gJU+qBy%2>L+7^cSN$~#v +JioIHU9q)5+(zdPr0;NjMXdl=$#t*MM>FiVx31{+!pwEJYm$@gP`5&Rt0)vm7oxM+(LG{&n7FzmxlX- +IQ9O1fv^RC5tqp8-9n%R#4NnfYZxVdx+UTLpC${rn1I>1#{!CbslooWkhXN;d{zyyp)*Kzet!M{Dda` ++SNAnuRNm=2LsMjW-qJ9aib;d4|lR{1fojKaw*?YuyNuGOkOh){2I_ch5$)v{r0Z>Z=1QY-O00;m!mS +#yICcJ)g0{{RR3;+Nn0001RX>c!Jc4cm4Z*nheZ)0m_X>4ULZEIv{a%^v7Yi4O|WiD`erB>f-+b|G*_ +g`_igxV~4?Q0>0ZL~00w?X?b7{e&BylAndRFc=`zu%o?D{*XR3)4#^=kB{--+^gFg(pyR_R@aLQc +5gCFVs)Ve>pOyej9gWp+IWyC%!LSUl+l!?51L#b+fuJFTs-zrDSMiVQD~{JS)&=H$&~dXDgc5BIFX@J +6k6!DlC<2m$OtE?}P}VMz&u>E#IEYsFR^K{zy0JU84+OID+bwCVs$*esj~EAtAulU*QnGIA*UrG#`2W +)yr*aD$ppu6Sm$nVFdwX5c~A%2=}S?-;%1F#a20D~c4UNoQgcTRk_J!nO<(ylFpUX1bjy_ge!}Ss)eQ +SoqdY|8IccvdHOMi{buH_T`N@5?CDoMXz{}{+&4p206GY= +LEKm4-0yKf&KpN6QkF1iusx}6u!O6%mmFmrR| +il7o(()=0$F}=4DZc_J(etuwo4b4^DRGe=Us=`ocI_?Yjpqi?Xm)76DJcR4&Kvx_n{G^eL%&2iP?pfjA4@q3Q +U*bZG>hFS+oj>ZM+HyH)u{p#q%Q($el`@BuH2CBDCJcJbD|Fru`h)gF;#1=|bYXH|p5&;1eQe=9)YX& +}Lp{gp!>bnlym1lC`8QW*u4*4+OKda(b%SHVG8$}TCFEvk>rh75W3xEqY@d*$toh`QhBb_0Lm8t03!eZ0B~t=FJE?LZe(wAFKlmPYi4O|WiN1PWNdF^Yi4O|WiD`erC953FqmMFA(sK?;U2Hj-=?DQL +Q#>Ef{lYzV@aqGXs8p7ZC#7ge*%1!be-I*m)*Rw`Za+%1&6XpGBkaI4vp+r`YO^PK4SO^pmrS%R +5L#4->mu#(GCkiUs%I|<+669FLfQmX{KfdRw_aK^zo!@6B?Fi!GwB{lG4J=0!>v$HcN!)Zr1`$iQ48Q +LFz&Ngxnd`U$H9s+#YI35|1XA_2EPvCeot4L3;c#dYa&P1oTstks}hmrydS;4SWmHU>NYUy0ZgD|xen +j&NZ@y&R?;%kG>o`@C_orG4T@C~F~KSuSY;0jSM&s|o>H5KlOs#5-3i5QIy%AqBsYSe(|#UKqqwnRjK +`;)LP^wInn3AXK0QOBoIx8Yq22)(j~j*%8$kZM%(Fm9NTCeA5j`nZ@1W0}mF!@-r4N^5Zce9aajPrb8 +*XWH6`p9692#h7m>ebO%R3`x~&VDyNi46z-#{rz&pydX&+06tX|;?Reo7c0a@i>G_y!LZqEsw**@1(X +d6jIx5;WFg3(YVxuw=8)HoRTyNl?C2vJydX7++1O`{l?YYwC@gx-n4NmJsvW7N4%?la5=~kYCk&H7u_ds2cQ-E|Jyi?gDMr5^5nvr&WEi**Wz&5lhSN9xh3> +kgH&28xjP9^@s{8x&^&NmzO_XKTNlGl|wQpS$_1Ip$^&CM;QM{(bwBpyQOT*=i0W>(D@x2ja*SU&F|v0AKB&1c5%%G)a|}faPL0#WjuWDMW +LQHvmWrKH^{oVugjv(gS~YkRl+HBq4KS+tHozKTjBQ2a?sU*(`wxS2Y*4r+E@BC+5vCZ&|Ubhs}A_NZ +?~a=b=iH*3bErTO^S`Fh{Fjlwk30Lg!jZtp9SCIS1LFj>yzyW;!0abk?SYGkg!LuP(UFrp*73X=gKV+{5OYbuAL5)24lJ1H{JA;baCXj8Wf0(B`TTS|(i}Y%ot!=KToSL7z|?Gpsbn^5@g4Muz5OX=8aKqW%coZqe23<~?C5R6_O%~0e8I +fFqk`F@h9S>w=%kN5=zmZpzG$E%SATwB$I&<7!3kAG_^W4K)Yst?*N3_)TOchs*8>xyMFlM<=*56zY> +r+s1!c)hLT4z;4*B`R#r5@pC=-QtN<|`JZk#|t%5$}HVaD?tt=W&a{H +gxUn}20&I3^aG?a4>N3__tKKP@idia7MP`R&1`qnH7RN6H24j5$+$EcM|hL7Z1sa%ZJP5#S=td&G#kB +l{gvmH*l@6plePRcN^)gHXw7{Hz&D>1dYi!=IpIg#TTA;|E(jxJi2wF&z{d~&0*a3x{$1Y*Y*eWl1(O +N!hu(-90Xck#vj<@uETgVB%6pDu2~`;Yf`w>N(qH*^Jr0gxT3-+ +ue;przJ0Lkj^-Pcmo@oHQWgHnk(o(hhM332lG1?=AJknPG46g&E-svH`nNy2cRC951aVn5q-4(4ctB= ++E`@>G5wSHUEdSD?%r&Lzp7m-!ai$N$WUs!t6=`SMo{FeQDsxJA;d+*5ukYMMU0({lwo(Y#d;@`@N1I +Uqt(>?anfa+j|1VcLG~C5JZ4B=dI=slOJ{lc-7SD9oVw6hE*X8)hMYjbf;!4w6k;twGtse`fBOYSSX) +#PUs9<=?2c|iKtG#0=+t=bal|KhP%ec9b@C|-R14{h0M0yfm3%l_#aS90|XQR000O8HkM{dyM^$*2?Y +QEf)xM&CIA2caA|NaUv_0~WN&gWY;R+0W@&6?FLQBhX>?_5Z)0m_X>4UKaCz-mOK;pZ5WeeI5DE-St* +YA1E$G_lE2qRon*c#k6arV8^%ADUHA#8B|Gq$tb}$hR1j#ndlwKKb;WW~KmgA-B@k +AAY6^5^^WB`2mHUe%zTKiCzDUenpKD{lq2EV%LZTL6CE*6#4YW2d2S%e9t&Ut;M+U9{viYsL(UjU_`% +L;#xsCO0nub4FfBsLFrN4!nok9+5G7VIon?^%zDmf3>UBc&+C%}x;Es)Af2=?q&MiS}bO>%c=ZH#$QrX{W@wJ|ow3TC{%O08$-ur`+p7?bu+$=rxfz!{rHlqAZy +nl~3C*H9RvtSZO|`67Ct+os7D2O6IF0?mG?5A8RJT5p+*aai2|5xfwF3n<`QXZFyreYm#xRea=;pnQz +X9UH9_aV~@hec^_DV|&sBQuZHuS$<6`Wt)i|(?PNcQ*J-NQ}XksaGh%24wc5 +RB-wE0mdT3KkU0j4r;&!Z@QH!0UQ<|rf0dP>mJj%d*|cdV0%coRWSNLDGpN@JB%+RMjoAeo|$eu>Yky +=3xrpD3^4G%vRaxsAi*nCR%lNG2ym98XN_W#J6IzpMelM0^y0*_SOAtHd6*1|llHYp`AmUVuD~H#$a_ +8k@ILOh`Dp9A|oFoN3W;F*Z_7XHh`u032zczr?|% +=)g}pC_!F;7PY7NuEdW!{=77VK5%A?WP!M0X<- +wc)scYr>uT63XC3@s#N8Ma@nW&Rikpov0NLg$Pu`ATXy+r{Ey3We)}rP`b8=9!WTtCZ_hY<|9FOiaMf +$a8;xvBG#N;IH%EYo&`nxBQ&a9{aS|hmDFs_?D?B1ER7fsPRI_DZ-WBK3Y +S4z(RCQZwF?Bq^3m4w#pwj6f90rfWD7;W+i)i!F9l@B6ALytSz5wS55f60NFr9O9&#)C9tO&d9iUVvS +gSmI3lgLASds%{bSA&!84oybgi@43E>Mj$bOlFN|w9MQycdz~Cncdpw?)|;Q3Nm(6!hbGQe5@9 +xouG*$+pb0CGPR+24dVD+Y$*AX6X*QicCe=%zMRg>^i%j$2s}?@A;$I_ct~#_ojyq`Z$ +s|ivPa)r%%5x>eo*Eq$BM$(>-=aPax}UxMO*II(T_Oro52xgTLQ1+@cii7orVBKLZ*y` +Wuuef{ih75@TIO9KQH0000805+CpNs%K7**yaQ05}Q&04D$d0B~t=FJE?LZe(wAFKlmPYi4O|WiNAiZ +ER_7Yiw_0Yi4O|WiD`el~!AC(=Zf%&#yRS8YH5GjmJp^fy4w7FeE1NfKcS5C#zLAF1AC-zsJW;+~(3w +v#Qo{&gDDbxww^*TgdaOF^$4J2fp1&Wq=i0ipF5>pQETdm%85>zQri2NImPdk}tB{d|(EpwYa30PV +GtH)&=iBd4;$%0|pvrMm&xN^Ug?b0%6 +5H58LmlJLdF1kQ1S^bVzhpmQM8Xyt?g>~iZbZ>(RtXDambvE4lqaaS$WA!SWzlE!tLDdJ7F9WV92<+E +X##D+!r3-u3I=fx$jB-*)!Aqdb5G&kd1D!#J`enp6*laiW57<#9hyGh(_V9&Ur8A&tKPlfobsp*P+{4^F^1 +3ppRC732xdQ$OpCi>+A99$kre5r|K<`2Qw*wgVniqIua3&dU0C*(C;U!9#TSK0Nbn`T2C_mFN%Dr471 +KkMImzZz0#`M@?jL5;)&zI`=${yUY_D?(?2pQVhh-5rtx4{!AYS5B_gL??H6 +`9|}t&*(qAs;t6MVmNoTZlpPJOz`-HF5euHIaEo&Nh@Im|=1nD!*czvchJaO}YMqmZ<#Og~3xEo%w{e +JO@_Qc1jlX=kHX5Ekch|=N+-X|>15ir?1QY-O00;m!mS#yjDOkpd0RRBd0ssIa0001RX>c!Jc4cm4Z* +nhiVPk7yXK8L{FJE6_VsCYHUtcb8d391vYveEtz2{eml-|-zTb5E57Peo9g|aM6>7^{jlPD9hj%94Qk +bl3nleBYb4so8WCq2FB3|>YGFpxn=XCJizLmk?HJw)512N@9r{S<(Q0`8pd(($~cHSmf)5ZmeuuG`B7 +wCzjU{r+*wX6WVIRuaK>l7&`EX=4)e2fS5~o?0m(F{xPHWDw#sX+Li;dfGnUmsvNcqm1k`+Un +qxL~hrslN;>V&7O{<6vE%EV{Mz1)XCL<`bhRzS0@Vc%>#RcC}c}fv1@T*g>Zd&_3a|PZs0uBa1NictN&0-0|XQR000O8HkM{dfp(V47y$qP0RjL3 +ApigXaA|NaUv_0~WN&gWaA9L>VP|P>XD?r0X>MtBUtcb8c}yVrp03-QFcwhI8pXOe5t&F7&?kmKtbqHoDaD*15*TRha +!d1TJUiq7I5F0LJ_p88|eMn&%qj)*e9t2sgpUV5?X8BHx>CK+!&~<+C@fUYnxhkG+o&LjG_`_&7kG_O +)7GU(eXuvcnPz=;tG59&-zi;npcE%z +1yD-^1QY-O00;m!mS#!jX-ebE0RRA80{{RZ0001RX>c!Jc4cm4Z*nhiVPk7yXK8L{FJEJCZE#_9E^v8 +uQcY_cF%Z4$R}A(cb`eW(F2&$Oo8(XkrQlL1rHIMyY%QXdHqxxqrS!jdBsnH2tuB&g-h1=8gwF??ptp +`d?ruT{&bH(ebujskBJhELDGmujUq0_fY~{MEFb!WQCL6q3!lt>@fW9lR_xqb?OaptOV!Zosefx2Ldk +W}_Er!5VTQZ0=hGaR!S@il4p$)_6hzUAkv@SKOk6{2~`iZAV#(*8h5E<}31vfF7`q$9eqs@tF7^C$p1 +mAK_RGk=UPD-gyUpKJJ@8(zwG1m9t+vRuI?O-GBtN**NRL;`j1HIjX505C?JqTs1Ku%%_{KN1(QpzG6 +wIY}3pWb^+R83m4>Zpe&%Lg+^*{#ErR{5pjO~I|J#A2~1_jM$c7GV*A0xxW_ocYZw#K#22b +9Q=p%tLyx&p+cF-Jv@O_r+HxXSt3A +o(u-I~5#=p|9YOi~8>P0@eYsPqbGG^7fq`~7L8=5!El)lMUynyEuN!G|0$yG(4f$D`nPpNs9KF8N^!I +YN?<7|rMLc?mU;n(lA`U6l)0|XQR000O8HkM{d`u(I5a{&MVhy?%uBme*aaA|NaUv_0~WN&gWaA9L>V +P|P>XD?rKbaHiLbairNb1ras-IG0UgD?<=cmIl0vw%cV)v;2Cexy>QC`+QQmIDX4GB&l3Ncs0Q5Sj#( +qIBp`FUG!m&M)WJGuRZ;K_(S~pVL|>P%=U7FojyDXn_g@LR&g8S-W_uMB=AqmlnZ0S|^QWGq{iMA`m) +l)1KF_eNGH(#CCJJc$u%(^TUC<-Lu9}SKBMFSQ#hD*uAfp84HOiD}{uRA_=Kn%ra|A;5@6Tw#YfivND +!HY@JaxA@9}^q;e-4VG&eTYVv?is1eFoqJ(p>(3#Yd_JP@cU_#*oW8g=MnJ@2!Sk427D)Rw242%9y4L +3b{bBYwg6&H~v7&Jw@cz6mbI$#kP-w`{e--L2_hTzo*eoi62UD}b*2?lLO1WkI(dD}0}&qV7<1=`>1R +VDMuK5T4#_D}hwh#{ddzj#M0%mv9E_P5Je{{@dnw}jsY8s`7PNVk9Oq+vg%jWi_wgO5g!W7Q` +9W?Zachblwi3uww*7_6Z@16JL;uun~uNnpOS@8VueG~cFd +lJu6=1>;F`-(;YAePcxkCj|b^VUaGs<+PECyL!K%qOGKeiI5=7&85sxME$a?i+B>ffd0QJXJ`DBaj^P +7IBT1j{L1)U#*3Kzvt^PNmx|yENS%~$rf}GqASZ;pCN=vbGb$!2+B}mMR12BP`-TbwAsU*On-UJ*0$t +jbm>k!)SydL@%49N0)2yoCsODs)OcWTH(~N(mJcvo~JNVkBtZDHPdGk`R+FM@MwG +T8uE&~gvv;CqEzkl5}(|%MqPk#8~?!_>SV8NlAANoGpQcjNBptxGQiz1*4*#!U467I)hR^A;Z9cPY6P4*dMS4 +HLoe^U-YcOXC$HDN&%c}Q5Mt$2t~y?hJB$vv4V!|`U}k^Fjw0kCEV$xVYYifkUKU__;`g6V +MqJoziOb3Nih!Hhu7Fj7MSVA6Sd_z0I8R2nsR=NV0$*wCJqPbi<9j5848#$yv?>|jv8i4x2)YZEudDi?Txvmx$$BPdqOE +^j$HBZ8zw3blL51~utl^`PDErgBBX>%{P0ODh~kONwHL>?iHziA;XJ;jI9ie`e2?mdOKgA@t3ZgdZl3 +0$iYX+{VFY-$nRbtd*yVj{6i7|^IeEWa?T6w_USan4x(PZs-epu*OCntX&( +zjwG6Gdg6%#q@Ba$&~azkY(S4V5uh5r!-zN_WMe5xJ04eyli +x9bxusVaOci-=Z5m7?59xVBW4yNPKAfGMD1AU?sIIN}j0dhP7pSm}s^5vru7f)MygUUkRXc_b<{Q$R? +M;t*5xI!Z2@Myr>V-ZzUtBCdX`#a)O0Y=bRERK|TsT{izh(I?|8i0cfT{#a4PL&rqqdcc6*4`9y3AO;C{t+fUmK*51pnQ^9om0E +#_YC`qbTvx2j8wx^Vqawlt#vI{3A#taKv+q2j!$*X8|t4J+B7cY{4?+BFv$EAE6rYH3mR5X2*%n8Vy| +bg<mJ}d>5_XG_Gzl^>#O}6~>!#8L0E +|*%kpVwbXj$)Sg_A)2uPfIa(mArf%W9~czm|<5r#ew8`cBlgi$pMu2}lLQdK;o1QE8^8tQ91TurjxW? +`y(ZiPdmo&o>;g7RnTPmswY*}HFP)-#D~PJ +WBi(dXKAn7q1PEbdIB2_IP(;;#We|%FRZLX#imE{z12ks1Gr-YG+c=S%VHw_xz`xXVS}3s;uBK{wkH@6GXzuXX5;<{5OyXrMCJ}Mw_qOBexe +vMtw!;N)W=2Ry=X5v6B7qD(awzeHF_$!8E5LhX-4W11iCf&Q!5lFWiWo^R#~1}Yg{Z!6j+ct>75FkdCKMkCYVu&=k7@Lvdj0E! +k2)rG@Iq+s_9NrAq9B{od4&CcAobLGWBhx|$#UI~|a~hv)?Gy0<#-w0A?9xz=-Bj +0n9(i^)Zz}!XH@$)n|MZmHWGRfYV=b$0pA)raW+jHQ6Ebxn=zmqi?^c6AN;$`m0Km$AT{2S6bo~_*#R +lOZ@IgPPim|S?*bAjLRhrg`CKbzP>OVxDU)Fxc(&dl;jmZcUz4R-^pv&?M_-DRZ81_nO_p`;w*9luqm +{WD4;~Z;Vhk6hMO9Kooxt1#FGvkG3j!pD6V{kufqP`T`imtvawux`!)=N!#MZfQ7>0t;ln|2RN9X`2F%(k%ohdp@>TKYDH!j}eY0{{v7<0|XQR000O8HkM{dt`V +Q}cLo3e=MVq@B>(^baA|NaUv_0~WN&gWaA9L>VP|P>XD@PPadl~OWo>0{baO6nd6idLbK5o$e&?@1>4 +%UbhU0e9nT%4`VPq!NL{~{UM;(^~i;#_!A{YSj(Io%93xK3RiOHmXut@Cgwccm+Qb!xo@7gbT__=Lr209tQ}Qxn_Hjo;5rnN(s@2lkq5?rE#sW +)MuPAX|TZpPAVp-Wc&f}){LVS+f)US1m#3xT8PkDbGAWQw%*DuCs~H*rea(od?i@1l_WFo0m|tuRfYw +q;jT6T}SF{SVTT{)}WQvC?B+;xZ2qkk{5PYq@7#YE&EXynE~{&S#_Ld9)mBIqkXoI16 +3h8K1?o<@n`TC3);ydhv${BD^<9g +^dmCu2C#x5eX+F8)TBgGavSLK%a=c`^Z_2N4(`U<7atk!F)|s-j{5JNB3;4-BbRnJSPr-Gla)dKQ`rK +$CRP4_$#{0VX(a;v|ItWl(reo*cKfwih7GxH`z7yaFiG5cprrp>KXsFXLCUc@mGJH1=DdN&G4ry>Ef` +ZrKmRwRrQH3iqCwf1|FtmU|k_-djnvL3-n8G5CSLbUl9`87)(Ny-uLEVX)*MF^m&=@)8$WiN*L7UZmdz4vJ&j)3ub%Q30u&+pGWM7-<>z=p(j~gXWP%r|A_6bZBFsg-5<3 +*fA%egYG?MO8djt;m6_AuE+GMb%btxzYt*2Oan`hs@_)Q#`q(@o_pOX5Gz$4NYe_5r*fwDY>%9NcMjo +xMHuUG?k^0lEun?F#^LsCKYhBHFoU4?K4Dk*wry*e%RpwufBkXktUTrZC$(L(ph|`3Un4W|bQ55|S&n +s~a`qRX2sVb{K0k@YO7IrgMcT!BmjGnT%KoTCZ?kJUoWAZ9_T}*jk#b8LJ+S&~kn@AEFU1(Vbc}1&r$ +(0(&7xf^FbI8!ccDEMfmE0r!ro!>;$IHJJGuuR#{wusf79g$n=W4VI_qOuv={P#_9g8NLQo_*I)|rh< +^cF4{rU3$Qi=!gNOpy-lgZTeJ9{qPGAJ`zPBPn0h-p?Q^h%*g)w1HS4g_w~McSJvDL3$r^TCT2h&1o* +>0Ku-(l}EbD^MM)HSYr;!4;ng+Wf3-tzP8miZW)k+h+uI{a_%4f2tLDfRvdUnvz-SOd47S!7%QEME6_ +ryP`;U&HW8{L>K5U4z0lz@e%D^^$^wS +&@LS9?R+4VaO~+8Zk4PP{x`kjdp+b6o6a1P_p`(jSzYEf~BQ-s&j{^I3%B)^CC>=4Tc*>Ie|M|=t6zyw4i_;yw}se01Vi2Y_4w{9Q)?>m)sL_ptvP +)h>@6aWAK2mm&gW=VWSgN%MmPb8uy2X=Z6}k+T}ka0f$CjOG0H>ux-zfx%Fe;#_v +KVU;a$252-I{X#d;I!wM>Xs+&YiRaLATd7;0LlUaV9BVyxZRp(^`9m=dhL=Rk#%>GL6s;W@-K +@L;)9@O$ckDOj0N}{pjss^CXFPiO2s&TT(o5jTvP|XUVl<9G;DP(&Xf{l}}(9UVA9yfMs_EZl){Foh0`eKYgk@-Iku}g|QO)T2OkToz!Q+dIp_0 +X=L7z_nKi^7N&{7dkKx1TuS}IvK0$0s(h(iq+^-3BXQsQF=%FJ~tJs{W8vTzF{ZxEx@Luil5EQDI@Hy +e>)+vFM-j~IH#B<_oa{D;8-mI9_#--*f;I9iIbr3!FvvRO#%oB(bmNFvGmrV3DWz%;4=td@!V2k47?V +_nMM7He$27v`(FT7eeWI^1FSS^_Fcs(qF|KoNRBwcQhe6Wc6cVuX_@ifRKYce*A1Xc^f~Cx$CSCsncm +jn#|kSTkS`!tZ4B>tnlvC$b9UGcPTwpnI2NK84BKs_eu4ONquQF9FM33-=rZy(A!L(hO|C7Bv}}9C-R +rOu=r!a4nv-m=Mq>P3LvBUJVC!`h!u5c7HV-j +r$uLvma~AhCWQ*0YKSRXr7rc7ENTCTs54k!4%jVm1d{;PAsUK;XmkkE0WZg$GBEctLD^aRI-TVhQHPUnE!!J$L^x;MrN +A9j=ST3()%TtR>1(%Ss-MxW{0C;LBl8#~nrfNHeRqRdb5Y`w~pHoVixAFajOH-NPZkJ`Ob`C70xho}B*5X}ZG&`GclAY5J&-rgPai<6ud<>T +)_X6HQ}V4D?$LD=8_+)p2c-9MIhxh7%=@^Y)=4i(361Cw1X+1zEmgw>HAn3eBYSTiwuNQgP +`i{se97FV*V2eC$y(evzQ_ft0T|?+T`}lJXttIyW-Xh}{`A<^2tuVB(Jc%O*+)AziA*Nt&kF6KtS~73 +~-G#cz)(!1A|Ms`R^YnOt9w76PPA1O>%*VoUt-=ZfjL|tlw~b`mZM9xuhyyoh9(h8~lmXL}9UD-yiiF +m{@qmCkTw;?9e$f1qEU&Y5-Y{TAHP17>5rE-b+y%EUoQXYc53@^i#W<9lakB@qU7~99FQQPA6Xtc+fD +a80`>dj^h}Leo0vuqKW}Iw2f!E{hq+#l#T7KBtgVA +nj-8Esd@=xN#V;27?zqt8@g*I*i&${H|Whj~>lIA1%Rz0)Ywh26k1~xc4avS_9HG$_5+V&I{KV#uDWg +Hen1LZNA8jAL~idlax)cZuzR+$pw;+=3;iy+K;GQ`Rl+~(pPgnuyJy9bhR0E9fZT=6im&!?&EqLnFaa +TND~ABRZgk~HAw^B!EF+Ng-Y!&~6hTJLoys|EvCDavUP +#>dgjy*@vFUH(doUWEx79{RAYj$6rIoFj7A^_@ZE3N`zFO0b&A8koft+bc99z)?st`GdWSTYUJ2vGMA +by)A>yFvmC +9!wg(`sSro?c1yS +W5FFcWCMWsmOz~uuoN>ewJQWkAlVk-)v^+G};p~)i9>MwzI0tR_N@$o@Rx +WOZO45D+M%(L%H>O*l>^TIb6U44;%F5JqPXb)x*X;dFW&xIL(L8@`3Z)Ip6_ +}Rs;R=+P$=+4==4qeC876>82Jdg>M|P_+%w#d!W}9M6Y#R482WP@bI#qC{U&|W*Jh=@FGJK +yfCDCh$hp%Fu{dc%?nPKL$*(R;xCeNJ=9vCXAGO%&+`u`C0E4|LHop;>J-lEHut|Ts>hETr71e_+2PTxnCq62_CUG{SZ78@KaLhT3R +427Q0IPT)~?sUk+yQne|V?^g +?=}?<>FK3whw3`76n_S}N0tl}t#~*>z;$R#sTxjSjOWNzBH1sVpNa@H27A!bTRJoXt{(7+2ieJBq4Eo +~i`00P0KY28I#RrwEisg3gM>mB&?^FHj=!jaIy+;gs_$V=3`QAP>&eMzc>3J7hf+=pNx7lr--HKwhfG +@HUw*V0TUFUMs-4x#ik*3n6)+kD?_At@Jy$0t_r?gu`OOA%N_##p3DMgckKQ`!j#wDlEZ?yDr#%(hbsa8E|{H!lX(~TLm#MmPwbC`V5 +IwLOkViGdA>&dT00sap9EYrMnXYx-b;Bf5 +8B$JaU{p%>&FuB}>V$Mno2rBu!!9*$0))qh}r34FtJI~4_=YdJr8J}Bh;FM?2elY60-P% +()0{a!{Y3j^>$pbE9YSHR_j{UsEoGWPzq&AaI<7TPKauuAs#E-i)lQv+oHVaSkz3yT;or&b;1^NU{a+9h?)Q!UZ&v1aV9E|Qv@|us|7YH*Ljp7L(C +opOS4u}qXc3b*dbaeLO>9cdD^B5Ih&t}Z2KwPy@H2Um^EXiNSjJ%Grg|vNw#622xPTLJ5hdEH+jD}tL +MJjcs5bHnb^w(I}gLU^%EBnUSNeD=ktYf54=g@hja#lFXS?A03#3K;UB?S_ibp<*F(cr`6R7($?Jg6> +1U|b}O_-L0gx^MH6EH?hk>6Nb5(<0AC0S@nwmGq4zJROOd%_+LBjY)F@QjMfssg}u_uGtB?3I^cvCV) +4?s5mAan~jtuc-Fyg(}WqgWJl*?PO?W>9vJ%hIR!SqmCNc{U&{kKlNU%d*naoUkkiP*7l5wTedpo4zd@t9Cfi7n5S7oQ(m|=8B!F-ep$lVWQq3RT6&*oWO +sI*oKDb?R>7_g8SCISTX7?%4M|OvVH9(E5OyPFQlg6G`yh7n@I&rjBsXJ+SzMdFx+>$bAyo5rOj#E8B +eT*kz^g#Gtjqo2tGded76|`gWl`>E~YU7E?fEA+sxls-)Z{TA)*LhWhw$M?PP1YqkLU>OPNYFWr7Mu%!U-vt1{GB^UX`)UzS#mOrrXIt@!tG701+!r}cM+{)msw)Z#<}fU&<3n3^=(8Sr=d*eY4Y+v(`V+aB!lN}|0VD`1t0%d@0HA< +O8e@VUX42BCB4`^LCTe%_x44oTx05T3JtAnjZiUiM)lwJUgqg6=&3zGIjKq^{JJd;h?aI>TCVRN* +|3|N=zUE?E||53~B{*s%0wP(-|`4LD9u5${V4w?QEJ@~uTKxUHvDoW_&pFjy!s@YQuF&MF4_fbO(lvY +S5twQqD&~b`G#r4p0{ceXMg4eq=QTzJ0Q$=q|lX36~ZW2CT_9Z+x(*F< +c$d@c=rZm;|i{L7g$hzGFY(fDQCcYc%s8UDRkEr_NapFxkRbQ`l_m~@VEh9PO`zlHgc^)yMA%vb<>wM1?nXu1JnT9{E5HcFRi?wVowx-(W@n$Pz5k8ij)G1WqjJ? +&JFM(9j6+O#spzxNWidqC^$V~8@%O{QG3q-o}6Jgw0(7Ud_H<{-istXqAu*E?PCx*EtTD!z%tEjUV{y +vQ;Rk;_N>i9oeho$=gAQ;*3Ix3Y1SDjd75-lHhHWr-uD~I2WmzN#&<(;?raALmN8q1yc{02fO&E*-j< +EW1`7}DzmrY8LQzjKB5h&sDoJG19iZaL`<#Lwc9lqhj%qo}XZbaTyV)M5q+7=(o2su^^NgIn0Jky_%+ +-ElrvL+Fj{k6Wu08JUZ$XW70Me^$At8OT8+92=KO1#69*oFwv2D+}|M87Jo9||%Z#;N6`}B2cIzFD)s +y%>&dryy0&OG5AO0ZFs;}&{HEW+!KEVHapK!*YZ**&HiF~YK$?NM+=15H8RhV7jW2VwNUnkx)yczct> +=9^)Z1}*wDOYc|$(dDwPe!`oEQg7vzxHhMJ-EC^N`p)IT<<~utY8rT?h7^s=46d#^s85rjcZDu4tfRi +P9aJP>!0;|Xr_fX<&-A-5IOQoD!sNpNbf<4VR`{Ud2eU#qVPxDnNk(Yx?cABV_3KV$ucTlWr#;??B@oD0 +H`}cVIAyq5TO4>o~$x)2}Ud+dV-v_(EU7&?nKP#|$Q4jXN8nlMauv$p4@V4l5eenCnjcmtCFE#tE5le +Zm55d&^cAYR?76JE5cY(IfoI;@c@zrGf%&p2hft725vIi2A6XsNl}`+7CJw(qlf*NAK;J+sZ+H&-(}T +?3F((k7A0r#zT9_vYHuhwTw9#nyy_uL+TXAJa-!+NKtb`>7DcQs5}-_Moa;VsbMXW$}|k2Yq +&f=Fe{0-);LT~7_^s;oAym=r59zB0OVP+aoO4_FOiLUpu&3IKL6+smEk{`7#L! +jC5vi9ECNVuYF@lE`O#DOdaXRm>_n2cCI#t1;TdMA2ZJsXj7+m5$w8YU>{dIW<421%Ih +V3*{X68r`U04uB^7`$UiC9+U+)Er&*LKg_^)DkHl?`(SJl2gpx;f|!X=*qw&TIG=GI-I$AmGV7b?h5) +T-mYX9wOU2QO0@Ieziu5M-J&w2NBVb+7x^9%o0BlR7>+mIiN!+xEtTLCOZ*@96B<|T$V6NRw|(zV9?z +u1bucMEY9xYrFH>rA~9b4Q)3^TpFzu$fE}hoSr%WN({MseMxx6Izswi2pH4|q?wy5=`zuOzz#xEFsf@ +q)%TFY8M}ACnoMgoq^byw9k`$031mpswkBB`V1UHp9arLA*n*p?3ZM8JunmSVQme1tnZR{D%heV;0*{Z)z?ATl9_@8gZ|(_8=azFcC5^80&D*@-DluCg+YC#!(uD-CAM=AA1Rt^nxTo +W0@6aWAK2mm&gW=X~BCl3(;005-{0015U003}l +a4%nWWo~3|axZXUV{2h&X>MmPb#!TLb1rasZBR=~#4r%P=U04mFJ0`0Me!nd@UaJBk%bj6A|cyM-C&x +ON$Ts@o2GgY3`2&Qd@r)V!_h``))8_yqjqq%B_GLP^oAJeNJzweMCi(JHRv|C?F?)1NE~hOVu4e+ZlJ +v>uPjo6Y@x^JD1CjzdVZc22-FglJRX&#c!4MjQIUQ6d;h+PWx3$DxN(-IzuurC|FZaD +qO>;KoF1o*NkZW~X2c2DUzBf^X9lRQxcQgb=FLK6u+|XTL}>z0e0P^OKy6bIO{lr{8YilB7iow#0#Z%|7E1QY-O00;m!mS#x~ +@5Z5F4FCWnEdT%@0001RX>c!Jc4cm4Z*nhiVPk7yXK8L{FLq^eb7^mGE^v9}T5WUNHWL1>UxCs$6S0< +AIqluGo;YdJ`Z}J;xSlwZez1KiMM5%bieN#?FRA=*@a +^#rM<-`TcEN(5X{Bnz8xm+)sw%6Mz6ZaV(jrldGMBX!sjTBHucE_eiAKO-6!^M5(i)#)KlNNzj3vk*GYE{HSt|GH6;Wl{XKx9GC^8Nmc7*LTgrT$>U;{6p*SB1e1bC8l?+BAu;!t!Z{<8r?pqIzi<>yl($ytMJx`IJg%yPU#*0{3N`%=dN4cHCh%~Zqdmbgn(Pp7#7Ph8F_p%xr(c+$z)i`d=~aJqCp;t +CfD*lY|qPUJ8L8q`MW>a%%i;=YdK`1k;vo4G>t`tSqGvLFNE^B%Fn{}u)|jV{yEqlcG=E9i?lC$Y(I- +>Uv{__pGDX&I>I{Y7UPjv$ofj9tp%`q3nYA`=Ax?OB5Am{!?Q)-66!?N$8;JjWKqj>(3RONwTe+IgNs ++Y3;dngS+r#%%IuAmZhB&wRc@NZjNIqvi4_r+2f@T-pGmSP@nGo9_nZSx8#kdht33(l=H^+!3t#C!#( +#z{g9yj#BCdxtbx7j#7D-HwaaH|Y&4+sY&q9x)%%ZQ$2?)28d@FLw658^!D`*=xTE}{pq7vgjVDR9A?pU;l?eC{%a +1M@iHT`^h2C3yc~F$m810}&+lyuZohZS#ANz5%|(`5ps=q!}TAfbZV}Mf_>Oz=Y92vmk!e)v&Uv6H22 +egy$a9IjYJ$tD9-`;c17xSsjIbX=K$o(P#d0BamI#yPvI_CpCcMuiPGMpieFVJChu^O9fJ8(btf3CR48$(aF_P^Fz-1sz;F +}nTHZQN@ucpAgUnRg)SsDWdBf*NPggjEP_Xcfl{3LKr^AnDr!gjln{2mi;Fv-lZ?B-fRJSrDrMqBcCswDtN#*wKpZebH4XEQ>tHxf+BWo>GLc5WJ3cDGj-&LwIILWAg2<@FGSm+9s&Voy$I=%+l#RNIH9K;vI_l +ByB~UZlABS{wcD1@Cl_ +X^Cw$=oFfCAi1LB<`w@LzFHXo--oYGU$Dq8&&PY;UG9cogs;~5uJP0=I~We9FKjqj2H<%SSzcd;>o~a +ZtK^*ax5o?7`SOwFd%QruXZd+Q#LM3=9;XO{mYe>sdFrVq)3P98WJKTtA$z|ey|PQ!3(W`(ocYPj +{4sQ@ju*9j_tUaZpzmfdp$GXh3j5HX2bkhPhfkkgJnx%?KH(+<0hv6>=b&F}pG +|H8J#@nV+j*79H+wa7o9JSfh#9lKBy8t`->_|-U=K7KYR5oacSa4`Rs3U>3y!6^yjue<>7#@HUQ`S?x +_f^YV;K5}?He(1133Xi@#FZXlb_!m{qUL~sL^iwQfWtgpbiG17s^=fsI-~4qMU`34VkITBu><39*Pq_ +lTA&)szsHIb#m3Ov@8@PPM8Dn3`NnirY3UyTWNkroYhK8du(fJkSZV;BeToK&S7p ++w@P#!x}hf`XUapEV94@EbFG%;(01>_kd#|Dz_3z`N4~ly-Ve>OLp-yP4}y%)gU7}-1w)I>0h`0n=Z3 +^}Xc0#)Yv8-4eCus%k2Pn{pu=n}RnevDN`Or9*F@k9^=TPQj)XN~qctPXKOrBIz+V!NbIm8E;}r7=2{ +=_WGSH7k1do?#@wPqeMfXp#VDJItM-2-Dz!|hpB>{0$1XW6-lA3n{+;%u@rQu2E?SRN&o<|65Og=_}s +Cjf4ZhLGTCVgy}t<*EoR!x?tv{xQ!^|Zi$%RNUPnnFfcV_53Qjs5KBfztqzebETEhJl~&-fe(iKF=tK +ep6Y&D&Cn?b4RIWtzZ2GPS;?vo@Q`2)nAm|skif(dRs{XejO9O+U}_pY-@o*w_)(% +LRwWs_hgo{U5U|-+7SL`M1%o|F-nOAf&-p!B3{u%nnqIOCcH6RT8B4rk2hE1PZm^4ncIEZdrl#Aq?tt +74Mq)oaA7B2J4(I>NzJ8MZ*S2z9bHm;z9h2zo!UG^s~<2>M +E~Uh$e-8hqePj%+C?ELZ;0v4@_sCw-Nd;lA5GdW^ep8cM7K58KnMNmH?xV$=q?flD1c|oS|FHxOrjvF +Gvk2T2zw7)SjdM6VQI-!FHC75=cLJ*fB)^z?Ze4P|vfEB;dVOr?P#LObhOViG(DiP0`FXgy3hsxPIAS +gCQ!lkm6S9v~t$SF{>buRFyKP{u3jAzGkw7sA^i=_!S2QF-Vq5+=5+<1P^X24Y-Tbu)~mAYBKUnYAxH +$9Fb=}r_!MaxJA+FS~VI6anKCN+@DBYjg9lB>*qnU^X6uueZg?KiIGko;iS!533~H%ep8{BWn6?)p<| +=m1vy2bold2u8STV8Vsp9RFupadb@Ng|Y^g_LiW1Kb5kEI<__lb#iG_KC1^<>6r7iMnvv=CP8d2RBb$ +lm=GMYzXKN|1thy4(Jg2Hqq)W-djN|uD>m9G3=fDX}C%MV~Tb)V9aJK9oxcnMGNiP5xaUsb>T>~Es1!e7`c`90*MMO7Z7&+Q9D66DwvbgCf!|_E`w# +)X@Q%@cp8Z_1vbw>jiQa$Anqp3G1Blttqe9(Ueh?*Hv0D~(mRo80FrZ|J00%(K5m7rQz}g5zs9eQ +UsxjvAdhW@7TWIL(It6sWRDTdXH_n%0E;*S(w-4vI$+`O`15fGcC8)fo_j+V!>}uaSF4{B5}+qlP?0X +YfWS-6J|x@ICoGts_A7e?N#6vyqrrTHJ{WrE^_Nwx??hOP+BnELR*714>s08C10`cH81EHfoy?Z@rI) +2oeyS)_SLSKIl@2j6gw((FIZLlmf_6h{T-_?Z%!<3?-6rf?yg9yR|YqW)Uva;w)OtHWogltaaya=)3z +lxubZ|i&~?kR>YG-#p70l^hh3H1Ip3#VE0m#qqBVH?^2BZo_!se=6?@B>O-kvnjc3UA#A`xo%>|`pUU_@ +6aWAK2mm&gW=Y8{KqgIX002Id0RSZc003}la4%nWWo~3|axZXeXJ2w?y-E^v9 +xz3X}#$FV5-pHDF%mp1?j99uCA`@K{l)B)$;sFwppJY{(f(Ne}C^yF}p0z%d9Eedeh9x?CG1Adxwe7-riH+sA +{t!Th!;(tXO1c)uIH*%XLvL%XxNFtuLx2JYO;BaaK3J^pHtAu1kbaHSp&80{+uLyS9XXi?twR*dR0P$s$RAk^n6t;tJP)!z#Lk8gjRN1!u$dzZ3_rgOK6K-!8r20z1|_hY|hK +JI>*_AH*V_Yl96B5&6P}WyKUFymA>DO_ww@moS%%dVmZ$?OMC_p`~w)u%XKy@U@;c0z@?R0R96+vP_d +E2bjzNqIp5! +c>X0}v*Yv(0+bl#@wTUD0dBXvF>1_x9v>7^MDLyT7Vh|5{g9rT*Qxzt-DT=^Dd0a2V#RbRj?76 +wMM=$hB|Rg?o0kSprqo3-@q!dA?a!3x^WXK;5{biZ<=D|#=kBbMvG=skkYBdx#vFt;@-O1KH1CQBTwe$lh#Wt(Mu +R`C~x-3JASAtrpdKYeB$2SVlDzR +!-b_syo5aW`dQ*s*6jrU)W^(VbhcZNqc +bAj@fjP{tiWxB35?E-_`kyE6XBj~;o0Tw=#d_UTr?BC0c7bG(gUd|PIOgS|*doJ{2`pz9z~S1fHaEQo +@bk$8XLmB`oxa3NFf*^}W!Xa_!-1ta*CGct-@;ZLjPB63g(IdqtKf}0HE+r +vHgJSpmCN +M=qQJuk2yEWet5rGAvoDD0W&*#>_C1`NY5}JTu%Zml-<+R}=)cM!bNpin7>sa>&db@N0AOu>Rc7Z4*a +QnX2?*3_2`$d(^v6RH&es}VYJs1$XInmO;VcA1@;#Y5B?UZ_pu0(1t{rvkL0>?$aPa*0w-3K#e1>l~O +WgGGRVE0}82tAeJZ*0-VDuzVka)6$|F)Zw&$2?N0c8=l+H}ez<6CU;)TWaV!QqhyUFWV3MQQS`TyIvy +jK5`gUsu4NhV|(`fbk1bFcWa(!FpT(LA2%KOn%2t1MfFW5ixqnv7t8efh7!{^-|6zf7WE{_rnB|LE67pYZ +IWfBvtT{m*}G^v~0?fBvr_{m*}G?9-&b{MStWZ+`8`U-nFXxdut-%8lW&+;;hzLF^bBoLB%T#&#JZa$ +jKj%k_lL1UQWF7m$XB&0zTb{C@Ud*>Q3B;|c!peg0qB;b?%8UH9?#0Mp0OI%zVf-@~{9x6Tg +D2TwHW+t)zpl!g+h~#TaK|TjRkPER +lTg@cjvs1%q;oLDuVeag)M*N|hNm9Ap&bGL8RUa5SY9AFcb6b0CjjBg$4?%eAf|(dj~;*e+t2>}cfbF +S9!Lk!eomuXZm!Cvn(>{ZsoHv(d|_Lai#c_Y{|L8*#qjst;dH4ze0y+jkliO3dqJy%tX#Hy=>Q?7Sgb +CJ2dCw_cmTKMc{RtIJ<2<$CE#0TL<)N;==5X|u5!JYhYQ_VGuBibWydGIE1xEnd{N)PCLSedK-MD%E& +@$amKnm}6AgLzAil!Y3`t!FS-|ZEgr`MW;4Q2;PrfL0XVtIP9=s;b&NAjv# +?k0`JvusknjTOcHWUjdFVk1+F98-uHsz)sq#T?0pB!5n*EmN!m3XE_@#3r#)W%t(g@E2t+{4Da{(!#s +Pr%&zJd^;|9L!k`BQ2AAD}ClqnnESDwTh6}j8W?ul75irkcq@EMF}c +DX38%f-(8>WC6>zam<^4f;-|lO_5Nz=jwg&krZ$ +S{gY04Sr;UcW2<58G$HLx?R6qUKfjMF3ooU42OP=+J*@#H~}$04@IM&1l@^T==t#w9-|g@oZY*3c_X; +XEq^%5H!D03hwy|R7?ApCUd`4yvRn}QT4*@V1mb9<9ijlqFT#bEd!Vn36?F)Ix=#0$>Mj8mork7Z6hz +yhAvSt;e0hQpjt7$#m7;j=U!M%m;b(@XVlcLKShXH2`d0_P6BlaP#e%wSrE7yPU~n>ocM%nU(2ot_jd +KYLvJk-14t@a1c(on638kK>F-$t#DNe_k9YKAX&w!;gfcN#8S(7C+U*L`Agi6F7ZB +?z@J#SBNjEQ+hsd6C^Kn)CLFs)DdLd_gp@C9odRy6epE@9)2rqZ7{~eLQHhtKvg-wYhSt?S)f@<#I8B +lL&R`K*#W36xR)OF}^IeC|1`f5g_xus+I&(0P$GQvagF-_WE7+H_?gJ8{m7V%IVpva}W6cJ=o-M_OU* +0rAOT9Ho_*${=8X}u`0VM;Y`QF5|vxCi*knAvQSx%XB)u3T-G;;BEfRnt`2G}*WPR3Gz3WZ(DDYS@J>q`uvl*Sw(FKTR`0>?tVFnTP2hM!nP?o!Oj&!O%S4MZhm|O1v${bGDIDp6f)QaMO8^Qv-Bb%pg +{-NChgZd{R-XQjy3DVN_3UDZZMhjp&sVrycmqQMCm|D+zz$cCGxz63b5kw%J!1)u5rfWvy8LkXNellQ +WS?Y1xW?uGs4F=4_z|5*!_o1R$0wt4c9owu^=38vbmT=(Id#4*7Ms#&@AY#)xaz`2mzcJ-+yarp4L$* +CnoRI^v&RtrT(lr{JBz2#L-J08J1 +9>81a?CW9)tjZz&JXm~e=1evC^#!iu8>Rp^le7cKYD*vx@`3=+e!$mcS3j$lXTSytlI`eKz5b%!Ea!^ +EH%nxB%NICR)T^5_fv8=7r`BkCEiibPsR9uKnZ7bE-a1TlXbFWgpwcO0F*LAGjrCVGh~YvOXG|XMi+k +u-&Yh&V#O?@nKNDn<@PT@kB@+m0sDQ*~LNW}DIw*BA*0tFRu)SEgov?`ve<|UI4N49AlTL(jgNTOBx} +1sgD?u=Pd{;k~LZ=GFE*xBN;f-=$!fkFJHxXX!)=GX~emQym^4)s`_UD(cp1%FN`}*$nH*cT4a9^MO< +;AnVzW(OD`{DVEZ(n@%`i*?op7-Afr`pfR8g>R-6HcXY3y3#IQ=TK9^wWbyU0-fi=qe(pz5Kdd7wB>E +#_+zEx+Uz7U%;GcV_lCoFdzOm80h(V@bzl7-dY$X{$SWFLwU7XENm-)V!uA;eQ$sI&uaB10>Z-t28#@ +*6dou)IrcTVfEigtPuU%1f|m@>v_1eA@~^2Fqr6?+Bn&N-xc;aMd2kAiZ;ECf$yW7pp=S^rJXb|U`{( +I(Q7sDC4bMXsxp(3&q!AYxIxgeI)~BZ}@rCS^ZvHje;ZZpR)VQVNlHbot1kjQl65r&D3kanNb-Lav;8 +&2p36sgh+3Mk1g0Im_If~gMhi=5-h7tOaz4a-26u}8M-yV`OWU&C@$*FJzM(b4;$dJl*?Hh@(_s)r6A +Xcv{+OBi|nui^1THGH2RDxwVy)oS49~1PjS@2zR|DQB?JlcLjNz8Wvz%zabaOs&!?*iseume_QBi=E% +3J7J_3g8qUKRoGs9pK;k_9J6M;d{u=CD)PW$f1k%@ZLT0asv_27;|ubCnzxhPZn#A4s~*Btvb5g_<4C +|8?g|(JS5gIRvZc|)gxfObD)aQ!Fk60Zi+=ja(S{_F;|$b)3z<>%>9lN2TScH5y*aM0E|cR-1Xu#ych +10{)W-_c)!H^OUw>43$yFq8}r@ +;v?MUh?Py@hRj#0GkiZe*5N)nUk?2K9_)Y+X;1$DQus_8!a4Ca<2`L+KLq_1V}s?#JJ!I$+yrD+UVD3WfL6A?qg88@|)O7=l#SMoH+Bk +Y?p(z>hrUGl4i5BvOpKBeN|$dSJ&l|{FB*f$jM9-5cNPVMLQHLVc-0H^7YgI_4+NcDenVz{N&S;r=j_qd>bvYTdQB=ce82SX3E~sm!*4~6*W@>dCJ +Qb{6sn{G=9JrG(+>sz%&-l-*`H`s^^5$gz527uh|Ab}wVC<=AL0$X +RSU?a0s5DUF3#t>6-H^~CZXn?a&BI!4lHH1*MtLBDQ5fa$0-0kIBRf)qQ#&jmA_L~}qWilJwT>1k}`r +S8r#+JYQK^8iWH7ny$Svk~$z1Qh731V<)z{?ZtCA#_|h@qQW{J?D(4tu< +`5IKBZ%-+=2s$HFVP)FHd5bF +XlsZrWF;i711*3~7RE_22F4T0@(Q=qmisxH?wC;V>i-jp7bZ$qbpH>6}=%OD1*9}a-_oAT{Sm=}&?kS +E?s%8RKce!c3j+s+^#j6$-a#&qNd)KWCFi=ntohvt}n4&I>m$D3#9X|!6+@SLSzCb0Y%Ytmlm6Y@P$D +Cls{;0*hT)!4TgQ$*iHhG6;iP#kGzfh^VXeEjWif6Jb+u79y*Xu|VbU|Z<5KArBgzhKl3-pMMqK%hyx +W&h&~pn5)LzN(g+4|E);hC1ZX0TXiJ4v+KSAq)Hb=+peMdrA%?z(4TzTAkbI3K!;q&HB9E9f)vDNjQ5 +<+Rma7*%E+k`%D5fRC3>fhk>V$SOV-u>R1gtMTgdbpplRYG=iq1^)1`a_Q%=&WIyS=vab +e-dH%`#@RN2QZ4yA4x)*@jN8`-?@CbhBY{BGK_z05)&L9v98dy+dXHyp%tl-9qgu=6#u`W@}LgEs?SV +XYa7fro6zsMw#OVrts(k^7KX}d_*JQVpm>g1u@PL1mu7=Wu)lZvlN&#a +S78%sep%a7|y*0!84L)1?qz4rIS}wWSdXDZ4MSEBVi35D+vGik9(rpVKHspY)V|*vI=d06*3b%w~=Q^ +XAVcQcLL;Mk$cYcinvLr>LcrF%vZ#9XIXvN0)HvnkiVceoQw&PAd{XKj)LD@yQ3rb-14TfXt(4Z6pLa +Mqa^xDXUiqdi*}zvtt9{xpYAY2x)oB?`4x`@qIe4o9Yx@pMtq%wZ+u&{u78YgmI6KAt9mjhS;nivo=0 +MjM#5Z+zhVT(ctt(T|2@y1!gh|{E6yl1g$_2dGUA?(z@U?s`lRuGl+et=Yg6oeJ!e*OlqGg(XU^=)LO +T3@R|=VXW{vF9Hx(1^qfuApA$frCgQ?un;#yUW(NDByo8jO2J`=TQ8Vg75}KcQ-k13CnDbI0;(2@cGHT! +_|Z(K=O%pd)9#C(j*^;}4*DWdIer7Yf$?WwADms{h01$?7X>3w(h6uH`<#A{N#rgVC0G`6+nAkt6Jp5 +7)FtD*rnt1dZbz)ja4rBtl(r@aW1R6XWa;o{&{s8DcS2p?)V(xiQ`?4oMzX1aFcomh=$EbBF3}t647I +edxcS*ce8jj7lFtz|JszmRWpE;I2fkQg3w#Csv?^XdEWGpOX1oT)F~C8A{vbZlHHKFWRwyVq2<8T0Cx +v?KY9E}pPB4M2L1Bj+t45&MI^uk3^#cMKW2kV>tw>8^UE}9`E47v!GF>xvy%5uy3;`CXS^_wDD0N_2w +Vzds6cro{?*U)7=Iy_rtOTXn;R7T{2C;xZV)i`?LE{gy7_oDTph7!uoP`7}D>G#xwJtODSvI9tSZhU8 +J|$^{a5py=T^+$BO$&JkD~pdIBj-Y6(LN$AO7~7#1}MWzj4R{qWVf>o9Nydzn%oWD5ETO0#S;B`?l8N +EgZC7%^e&j*=lLguRr35;GzphzPFW4wvF`i0(u<;iorc*?Nh_q?|7mvv7qCjIl9B(L8)K}GdjZXM>4&3<3mn$*;mu+HcU +_PB=%OA6BxTr2M>4s|F7}jVy9i{sc_p(H9U&&;;jyQ#h(1%abVtQ0yo$h+iDD}n&yMFPZoKZRgH(Gv6 +J4bilMODuI`x&}A0}U6=)<$G^wBy6h?lA^LcXp9ZUyg-VJrd!HAE#$&J2c$!=Nn$J2in-ZH0e&YJ5cE +g8{~5Vx+2aJygl_Y)l}e5*`xNfjI0&n0LKg{jVgO1ejK8xVMPxYLiUg-!1BR=Ew&i&|54bAc2fA8hSr +G6mJCb3GRDY=72VWWk}|=dLaSrs0|8&tV#|PwK92m3xGFnLdtt$R_rlona;gvibY0I% +FS2pVd&HZ&86n8dKa$Ly}6{>Z)244V@R^5GNCKHF9ChcotV>YvmQ``5Ej0;80=-BWDacCG-fQ-sJUcD +0;yo#bachSjY~oO@pXU_hdW4&>0^L;~t*Ulf;9W*nb3~z1C@0qJ9c*ZXOTCH4O7&xeJz28isGPpTS%t +!y)}wT^?vLIsKELZq_AU6=**m&K7Mr$?oqr4W{7Y1A!acnNRx$-QXZ*3#-BI=)5HX72bn<`l*R}$hMP +7tW{2G_VIH-Daz>& +;qq`K|ggT0UalI^AYuY0(rhcs`KdTNX5Q)OdVi9n5~fpSy0^LpK4zg%umq;%*lpbOq4p6bUDd2EnyEJzj4z5JMB~-1jv!- +l^74+`BY4J1Ei0{*KR-mSQI@RTXLCuQrf=TLB^yLR;R&%BWuavEqv(gP9z($>^0@z+cP#qzU$um4O@C +5JVqa+uIPTU+gi|_$mB)fm@$*p#MAzQmcbQ|8X^68^g6cW;q6rF*Go6KqJWEP{VlhM5w!D?~0>F=#%@XKha5Y;GCq0jI)1EEhb~ +2=ja4y-a#6@d7hlJW&N>prV1=CLAEk=whv1wqFRk91z;1QSW%RBMilW#KgwwVFU4{enhfxiBCdgIvQT +Uxb!O~;&3mY^USWZvRY|rJ%_sD06mf~W0PCd!Z7bbV9b%PUxfh%b5X&qJ$%xR6fEa`-NDH%6BMF=gRj-dz@Ug_VUDkV)1mIdN;_FXuLl +_V9lwmqum@#sk2UbMS%Wv(bWoiafzzWs0-igFcVwQ&9PTy@N={P-A~pQLqOHj1K68KY#*QU)nesPMbq +Cbi2Rg`d0Fq^Mo5U5cRuwkiIp&pw48>(i}11?}y2DxI{xL||^0g+xy2qUz=0e8c|cj-#gN-)}g)s`1( +p-Rg-bUzU=fhQcN=i^Cwi&EJ&9y@2E@mA-DhleUu>WOu`p560R6YDP6)mAXJKm;uV +UFdWv8jj;1ynsF`q@bO>}mQh@2#SIPnFCVVQ7S&?%toZ{(q#YQZaGj*lo=912BV)Dh9>i1{W6LS +?f)LWyUr3D1sLXzB>`A`VGPZO0_xu3FD3lOmiY=8#=GDLUIMokTE3>A_tag(g7M#K;7sSC(G6TTdUaf +x&#J3HZPZKlS7m(r&+8c*Pgp5ru0yycL+Ptm~L5K!KJYaHZ~AM{mm(5Jt|S3m>KN@el#uZj6$M +%W6PMDLOP~XiXTjBiD8ksc2c^ILjE0f)Nk8<<=a+ILZuqlLR5escSXS_k9WTn^cKGD;_EnjqDp7EWev +PXJ5HA8OO($pDp)a*73!4EYtK-w-|*VWiA+W;Gv9MZif +YPHLlYeQq}f3lx%SM8V)7dP9?cF-`9#BIVeh5*7^&G&N(|3Mbcg1>3uiFqM*)d{0e3XIO-wC5*3=RF? +(H2gShy9yjhwjG)VMMrLt{yoH4E3%v7Kf$(~V6s6|$Zfl@(rD#K!{b5%@4o3O92ABF5SsaiKBSuE507 +U(a}7i5MF5AA4xSDBPk<$H5pnyrWuP*O$t3$T)1TiDW{Y6-yk(Dd}rbQ)pBi-3V!m+#hhnGHWh;b~?3 +gBRKg!ud80u3_JfO>F6c4DAK5}Z*(;t{x6@!5r$@v +J)6&&?63{fG9q(eaZfhmTGoP&K&k4#VR7Y6 +WG`k_1F#rt?Spo1aW`VXCZ;tihZ~d!_ebu{RabT)0StO1<4H@cZqN*vwd-jDtDI~AdlyiqRNkK4UJs* +0p&OYObpJPr_)Yld^*XD`iu%F*Pr5sTwffL>qf+kf5?skfRx1ZVdrLw4cP+33zm}1U-HQ~+s<>P +NEre;jEIM}-)O`fJtfW>Gm|&p6FjTzl1|@nMB%rjyM*35wP5SzMkdbZ=cL$MTz;bD;&1w6JTnV@Q4v4 +!dka}>!IUPnyB*~i6VT3(8fg2UHl21v9yY8QYJI|HU7zEAFD+JzqfmdyYpu-{p78jAwv*_jr~82_yNFLQFOCmT-pY@n25OO4SAn-cNB!y#jM<=bm7GW +|ngh<2cXCpUDVqLKer#Z7d#fQeJ$!f7VhaD}~H2yY$tv@Co7VW=9X0*bcW +iEBFFq6)M9673pFHUv)egp3Qb3`>I||HqBkZh><)za9ylT49(xZqH@$?p;_ZQV^o3z5?2i5l$9e8mZ; +vIvAhj2b`Wi%00po{t78Qq7-rKT?C10DD%)a=^%yxYxFZfjymb-+jqmXK}>GCWxW-k{C)xmWMnwr{Uz +`YW0v7)hnD=$g3`VFyl8CE}WC9QC2U1P55>th01Iip9+Fbu +{$a4JN!`;x=O>DHxF;?7l%<5h^ddh+TtJ6jZZhnbW4p~XzRBp2P3vXcJxyvCe0BxDI#%$4p_-Qxe^F9pn?H^>>N|0X5I<9)JPMI=B=j+2cb>CI2KFPJ=m{qM8}E5rrH~N4Q$nz!9~UjQ+xX*_Si4$ +e=nP=4uK|k_e&@Rz%$_6{pN?ndakoJ~x05`JYo3qGJ-<&^o +(TbF8|oR(|4s?JRzp$K-~N*bkL_*}Lw&_;xl%K47;84$fPsXhhy-7iVl_WqGM)jevRD-*+Yec!ilc{X +`b%VWvumn%KCOkE}`{5j0AScl)_+ +c@eHSpxc?!>m?=%m}c<9zDj(8gp}Vm~U@E$xOPamMJygeL*%kg&!n`m5Hqn59<0*){di=wrS_W9^Yw!{Nl7&v+KaGCI+ +mH4{miEV_T(3$B1+K$NLQ6(Z`LibCrR`FzT)XMPtO4~NK*MR&NW+qOCdfpSUCU?XP%vdVj`%sm!&xUI +(2L`IqA+^>mVDY=?=JX`Du%95HfH+5mU3O2m{#sJ`kOOCUf#Tm()k@x%`h%sXwtLtJJPiE0rbHZ$~A# +1a`zmhL42`_5Z_B~dz{ciOD5zLR&QHHr;+5_AZLv#=*TW4T9{6@P}DH4<;L2o8!B2<}poKem$wG~A%M +PzEprZX=EBjLnGxyWV0!kfC77?a>_EWY_XPfPRwDKmejrN$;r6mMZh&@#(}C{e(M5q*a9f`G|bi+q6ai +MxtyF%Y#4}hwZQ(z8TUEPY`BxWw3iwMsdjZd-4-s+%8V{-A{9$Vy9|Yx9K@R&>oYI;ie61O%#|zslnc)eLLKhtrydem)il_v>4el|yf`2LXdaC!Cuil>GkJi1(t`YmgP +7PQ2075S-Z*f;RW3L&@hZCq?D<|Ss^k9s2Tm`*YCAI=D0wt{pi4FfNXX#bILsai&k2eJLM*!ByC&sch +dj6ecXA|qGJJ@toT1qS=8%OalhA>-6D}TD?8PUPbJ26ee=S+k%-;KBsDTf|dT=J`ni5buS5OV6%J5NR +-SPo9ROKx0nv%1N!kRL!a4slEXtzbHsNiE~)i@H69%QxE3OM>GV2g=nM@M#2yM7i6JNM=?#tLrtqsZG*l5e;ROsE9U +oYg)A>BuDss544^i3Hu0v~Z5FIkL;EZ|o8}xg`v~uWxi8U7~C@ySmDv(oHz=jsGV6B3K3a0s*00SjDsO!?x$tCNHH+#*?XU3b``Cq8<845cTVzdn6b0F8>M|U@_8XhiOie$bHC$^Z$er +@=;#Q`Y!vId$uYk>2LCELWYaL9w1cjJBJZf|32;E%l$60QfqIZWPofx3``$%F^vS#O +|E?TIed+*Yi=6xfTGNoN&xQP~y(yNJ>SurOS->bgPLuyPJh%{81Hl?BtKahz?a^m!ac`hK&J8>ktH~(w)fA5R0w?=@eT+*(q!eMN*#v!Cyh!FvmZJ?h@KtYN +O$(kzJ#ZEY+2pI>FZ+!cbJ!3Y$8?)7pQz-zA9}DSOowvjRCCH!sO7p)93DSfDXUIbb3bIIC)b*t}Az& +$F+$g8E7Ab!4EEf+Cc445T8nrGVrDgYMG}(P7^AMx?GCXe4=f$}t_+KssI@;adjWc(Ak#GfcM{w_E9j&H`R|hkiPg>* +rWEG^jgsQ0U9MYJi}LO)gX1uc;u5!<^m?JIY{FN=C_Y6G%8Jd<>6()pT`Q@MQ?rg8+$VSOjuN=Mq4dj +%q6(UVIbA0-ba3&S;;>5a@a<-~uCB_s2%gjfbuLGlR%9mrquKa)2~bsYRwGBFr)$Qc6yX{jx&}4(BsEZ%EB0rP_4Wj^ +{$itGe(splX>L2m-uNRXKr+z&^5O4JOZzXH1Ht~6&H!e${iQR|9buet`_~vPV)~0ltC?PZ_HZfeJ#NlQ-o>b@n+D|dd5K|FLp!nfVZl&gG90m2l +B#wS~46az~Z8d!3}x{Kuhh!Nb>!sOxI6cJUkr9nByf5)PT8ibsQ?$h3qFe0{*6KE{au)R>%fTY4rwO& +on(Oh00ToQj=<&gd>}y8I7Q`A`Fw9T@=f63A2w7J|#5Qs;GJM_xFE!{c3{MW1l^J_Lmodsl|f4E}Dus +D5g87TxKj_GiDXv?WB{i-Vsp3C|^*{e4}=T6-9wI5?+y*5|w*{*K(B^qextQ6p(X5X2dq39EcU`c;P) +Cpi2!r4Ks~vFcJIV~*gks)hUP(v%hD6waQZ~tSpLZH7f4k +hehNf`iufA8l2azCShNJ$1EQ!}=8)PndZBNls89?c9PvBLU?+5Tn;41S;SIX@q?RyNmV>WQ9_z99{3D^a~F(a5=CXD4(V+bp#rAD$O$44lRre{IIEX` +~b@4C1TQuZAo*#Rev!seZ&1q{SBX$a(f%Ays$amhLa~X!FUaR=dO7u-%S_*1OUK%$M20r@#A*aHYV3d +AUYU#9qrf&@|^sJjw>k^}rWeMM5`)R%=W+O$Y1o;0A*No54w>$veP=Z{NYQ8uJOP%7!v+i}$(gW{eO6 +76Z7laSAw&EN29YQzVyHD;r?Sk#c|?$`o{#pK4egP9Wx=tYbL5!8j)m%r=%MOlXkZPghvDleRjNE>mN +U_DcBO&KtG+9~gVN&fiU5e)szQUox8W@aHezz6mGks>K4P!~IVvpR^qZWdwadqmlT6%>t)PL>4ByER; +!ULCJY2@jGdLi2jln+dO*)YeR+A3#JtzwFD?feVC7iVWR0d-n?4JDgj}anC3*YQI0Cskmun?7Ou_lk0 +DIq7`+^t@AzkPD}m!-EphfD;vfmJc%$PEnF|Q8;+HK`v(}v-y- +-fF$3eF}`Li*9)>RnHs5Ls*4V{wkHxb;-Nq>)rUdM7{4wqwcLeMH)0{Ez?zL8VL!v6G9aB5$Am`Ne`O +Er&p!KX1bpUU{X6&s5a7kx1vDIb%BRh61~^lauIt+@8sbU}kSWjxHy%6fM!`NoPp +W7y?VH-{+)rB%gf^3-pc1T2J%2bACUx?lZ0k4xH*O!$GLBF}h%X&oBa**Tkg +IoRjLg4alG90%-QUldmco^FOj(d6|1!6GG)#vN#f9~VF$Yob*4ABlDfx<~cEJQ6=F}B3GcH0TNStk!J +b|GajWPoRfzY8i!z{-@elxkk)IO=E1Lg(p=$3z@9#Dx3RN*(T-+yjYaQ|FvFykui_Y7sCMX8C6y6z>` +$2d&5!kGLa;sw>(211Y}RFXq+C5yslPl0>?hYG!H+Dv| +*4v&{G=FOB=z4MtuFLDZMJw{wyFJ5%KPSjmWSDb8+rJH@$_a44DKX3Q*0G&=Wq`%ma&+H&Zao|}8cC} +hTuWgQ4h&~Z*2k4Bgig6Fwl#>*>Gq)X3 +VF&9!oe&;g0zr_vK0Xn3S9PTobqn4G#_n$$4tZ9M00=;Q0SMJ^at&@W+RT|B;{EAB^#Zup}^zPkndg- +-s0MK2&w`c?_SwVV2i%eY{6RalDU1kA<@$2LQ@&12-oL3dnl`}D?u~a_5Ys=nge}IStj +wK(;V6uzDswEWysYEj1^LoWAIEv|Y^9J9(uit})4wj(Z}xN>IPu)I)2hz@yj_>=%hy8SDKF-Jc@RAo(9u@;MbOLhUx1M-uv18={}JDc68&&os +B)|j9=?%GVm{aEFrkT*gijw6jGh{6GM*+*PVuGU-{Vs4g2j9;_XDZ3z^%f?s!*y +x3H=isy0?w{Kp&?)BuQnz<;$52HAc4T5?B)o1GeuQtGEDN#1b(RjobpefN_F?MAltT!h(#B*~+!OY73 +DmsY=TzF*=g1pn=Y;=kGV`ra}kVc(hv7Vb?q$H)F;Jn=m%L_4c`#HxRE*fNgZV13sS*}6Mzb5zz1Llf +ML4HIY+A{R9RFpd!#<4voa4Z?Tvry&9`#AE5m3(1}E45>W7ETzyJ*D+^ry8u1>1iBP!Su1bIES$snG_WuqT#csL(9dJ6+;72sb^dB_US@g%$ajs2=p^^VrTLQTxxl;EIx8Z0IEW@5ImEL1;p(Ih&IJmxfFO@M|rw&c=N(&;>~KZYRa?f!_ZP(@F4QnKENaglnJ8D$dJ +bAoi~lYmZFvG6ob55&I^gYBQU;w80%%Zw(9X3#2R$x#4P`C$hChUXals@VV+4!AYm_v5}=Cj<>E=_pj +q!d^NxF7FXpjMg`KPE#ov%~Y$x^-Skz>*#QT0Zp8$rj*I6*3=Ay0p440QKqFrB=;5E662iue7!NH3!z +dU^T>WkNd9j`Zay;kE_+=!FB+Fy7kI*qwMGT?hmm>r12pOE)+He)yvH{{--@YXnVON4>ZW_0{KLW=J{ +uR?AnqD++MY3K100^pYM`@0VV2SJ-fum5t*0Lxr=y($2yG^c~nT^Ka!WC^;^7`}*FD@HTToavEDeAMD +kL=Lgfrt-_-Y++OQ3iq5*fH#KW^%>hHTBG6NGjm}0e#FxmUwb*BnM#T0_})4Y1jrcKS%@)?(W0wDs>#r?xP33v97$YZ194U>E&Z$8~ +$@Dmzq9>6VDhBQt#ryfy`qfjhnQJsd}Gfm?F@N8fZ_>EGL?<&jV@{r8dlz&Sr;vf&eRJBMXj$XemuWI +zK4(Qf?iPOS$ljdakU{X*^_=I(#oR^+56tRR)lua7aAV~9*`WG;!C(Aj+EbmLIrY$1hN?Y5jjLF;#wAwxI25Hgh+Mu$g!2xw39$)B8gQ-`cD-A%j)Gx2->x&CKl5?^?;)FHrj56r +M2?c4{1WK>;w}PsE{<6zJf;wulCpfq;q{BUErS~YX5|JT#Eb70%{l&a4--0^w>?COKI7|VGebMGjvYq +UnL#q!uHcYaHI=Pg7P+74g)*9NvIy}AdoGpH3&R-u&h%~Io;d8F$r40vCL%cgcFV%f@mkj$*BB6Ea~@ +uNys-{xptTp32{fEIh67KM+-r3Ai=sjCPWMFYAMS#>o8*En*RSlpoC2nQJa2*LPmBfbtd02Bfp>BVF2 +2P2hv@bum6U7xd4vIB=&7L`xZRuv7nlQ0;^t~_CQf}5hlm$ejzY@fizHS&Y2&aKI}>R_<9Ci1Dzm%BJ +_MPy7f;(3#_g2Uq2hwWJt$^T$B4qnCoSca;XcN}y4Wn-ehnz{PbQxl_D_E_r83hL1dQHf1;yXc69h_* +jky7|YRk>MK0Ir~8zrNvM58ox-yw5{>2^0;rLntByuOBs${#&Bkt?h~_!q5(>oZ=AKOtv>F1BuIWOwY +~-g&s?b0-Bvd+*n>e#gekg!b@mYB!p-E*c|tEOp7%X#-+UoM#$|BX;xk)ErePT_+nLH} +#~IFRX~of`O92O0yYfSv`_0lu(CkX?98t&)+CRDPIX_cF!m<}AgsGb_MqgcryLr&U^Jll<5<(mz@8a~<(3t%+I+0am(` +!fQj3u7Zm^?i?fI2p-GflOhyzAFkU^ukB#?7}go{i>z(FdkGo_u65BXAhD +yLVIy#7kMCarkhYfQ6YzCO;s-E3#l`mB?QxLuW_UWlibTD`H(NZ(YZ +-jXutg2P)KrYM0?AjmcEmO6*y3GG5Rt8uI+@xn|4h|p$d%tMfI5c?sQ{rXm{xOfcGAoDS~Wal)*TVlH +H@DTezxw%iEF6GCN~ZRQ8RUm_E*8?;)?SG0l#`_d@GdMkOGfe%~4(<;O#rz}A8uFs|TVn*^k5t$k3k$_2F0OXO`v?NtVbJsbmqUs3^y%qDH +rIHP7dcXI?9Y$I=<8ENA3Des(gXKLRNAldIhz&L;K?=hmTIuY?;*8^j<| +V5d8-OJUr&6Ct4?gf%n43PuEbdpWPL3O>aoX)Dws$D=b!Q+l4C!P2u0v3gge7IJ^zMqr>Z5tpmlMG*4 +~s)PiTM5>4NWdW`xVjAA892b*1xLvw#0Y_dcJAad`zo$8Wm=GlINi~2`64|mk6p@S%@pLVzpck~{=PS +3l2m($KuPBWXkzwq{H)aYKfj=J}+m2C$0XRlt@=h+1u>I*TUa7f<*Q{2D#D|^tep9xRNH<)AciMe<=@ +1>)#&;18Dwg>C_fr8l|nHVK!9dAl5Fi$055l#@Pqn-fDC&|bo@K_+`OmdhZK~mXa5Rs(m<>V!rd?1zd +lVw}hok+D0N)~6*yUAqr+6f|Zr`46+9SV7O4!v+vw2qXsMn#g8>*%8cE((^1JowaY{;%cMJA=FRkY#X +`QJE@@`$p6y38$)a?~22eUM^=fChj|uxC<$6-5%|WfqXwD0vQ_XNI$%-DB&5%+yaG)V(MGn7&UodmNf +Og=%f^iH3E1$BdyG*`D1ZFKmvV|87LEs^hCe?|L_0(e+CATPJ`3I_aDl$??0U4|L21^KE*Cz=k3amDV +#XTyt@BSw*)_h=@MAWj>X5QJE}(g&HFD7e;+EAIjL4p>dl~KCzDhUb^dBGG{W!Rz}Ot`iM*8(9M7>IQ +j4FT+k6x~jP4+NUS5}rdPQbwG(MV##uw2rKK9#th5jFC6v766UeRH2!d^(R4o9JlQd~9|sR9{i-FGmY +KlZC6`442|VaL(Zy+1mBcoM*X*KL&n>XW*(MZ=CUJI-X62$oB=kTFZtSuDtNv*{solt}d~nN7K$v{m??P +Kek5D1;jLu*5r|E*mAd@09QcIBGE3%ero35!mc)^9vYJ1Bf9SnBHj)HT#vm4MvjKDYsw=19~0X&8mon +5gz`Q8MW@d7R;WVwMO0G+eoqztMhPOzL6Tt|=o`IE-|JDHImxnWG$c_s0-^|X*gFw;b{DSHz{RpH1BS +qnk3QyeepH0ao6o5L@7Sz!XDY%v;nz5i0lA{zz}37$x&BS}S3RG?Cm +Nhp@CpvRa`94tm=H#`+e(+Vb9Tv`N1^%z6Il67o4U0t3V^#;|slsrq*siu=DKNM&Yb_JP|YkM3_BwkV +ztz_{N4NVKA_=Ag8vMYtA~kDm=Sa +sKjPhQ?*JcAS=GL3)l$v?IV$+3Dg@Gi+G{E-9BB7TsYtr&^2FVc!Wq#!#)`Uet+M5ioIRr+Bm^qE2LJ +`d&w27u3GBB%8e152dHkSo=(mp2ag2CcOR1m}!ypVO_+(X+Wa#pEpX`{$p3E=lCza&}r!aPe7P<3EyP>v8 +_O{Lw=ciJ~7L({B#S&aqId<2!=%C?G;7T|D2RsIacEueTfs9#Y7NZ$0-qY&&%j2G`Xd^NU3|dG_oId+dt +?>0V+EvUXN1{gn{s&8aZB#C04H6yS%h_LLa+sBc?G@qaw4-4hexY?*o^&`{&(qcv@Fw=Z +F3MGY(`|2=q9BM0;7S`khelgOX{r+?2hI`gAyEJ{_h>AiE8JeI|?DF#9&SS_;xz7C$i=jE&F^*Zvun! +jd5coq|0dNQ=+ed6-Cn~u{nWJO#8-M<7zY`uL<$^D8h +M1A|w`&ZmD3^EqspObEwUw{*}Ayu?873yW*tOYQc +NCf2-4DpEA!Snwf}xi&c5IH`ju&Da~I8XsiV6G)SocJB>&ID2RCwt~Blc6}4XisZi-hB|A}hVvRO9JN +=U)a;q|BQrf;Mq@qI@{DmLqt6iA)aB47wf`X7QFr+%1mRD}Nbe&1@L(EO`g^SmoQ>{teQ4Dn#Pke$@o +HrEEfm+83b2Kdlq~ykx{MBw2$Exbw+G=E0{`cWIf&vdan-K9%CO$*DMg*u*Niv0Fz02!jL5`~oDbKPm +0u`sB7nuNbK4x~+)s-&F$+C4TJPq}1i9OR*k#^ds#(}?1h+#QPlDWC~o$!Jan{!z<%73OAIJod!*@l5 +l{(draWjTDE%{yvLjS{iza3|~4O*!iHj>L6%`Rw={YitdrRcX^A3OCZ3b`3oMai=8SL-9vF;#eaH9isrv5DVQ7^`Py?W_1HRXjQZ7kdt3jjaNu`Wuo>8kJPw#oX|*! +;>8-sO!i00x2_Px87`L6tv2bqy16VGGCU#JgU=p6B+h>D*`rU>=?8j!P^Ht{cIwpt?AzmOk))$Wfh^X +;0bD(8!Ue3#L^hpj>4vte(x55Y0JDp=R#mY^)9SK&VLEk%ZKpE{l;-me?yk-{t1Uf^#8j3lGm_S#-Qc{)-k#ML +ck6LG}N{7u05iq1(HcPL8m4afrYKSi?rnUxOJ>Fk0MM=CP|>ls43xE;la!v*PTNGKX>p?r>Vcg;mH`f +R}ZrHSc*2gF?1wGQ5`$go8)pj%ksucw%n|kV^v=Rk3?M*i%-jJv%+W<@28!ZP%N-0m1Si9#vomcyyto +9$h!@UIr)xl5T*L-PxLN~U*hY92%cQHO=~$1+IZkid4~CM*jtahTJhd7j)1X9zr`dWi%?B_yC}?fpCM +niwpiM@c+o(wGugOm7WlAPB__ve8hAKSQ3We&ubT22YrHMChq7(viQA?M;T~OgKe!8D;e}9fKDnSQ?l +M6H)w=QH1-I@r22*HX^3qy&>-0{Yyy1kP(Z?@JaGkolgy~l2S$(y_lDDv@mhGWVn@$0jT=Pi?B@}^ts +ymKex0}s-c&cNm?lhYx?LdJTYqd_%;TW2DI$+pPbaZ683)jqtn}k|stj +5-%0+Q0MgMxPo;a?E=v25)gs-MVhicjms{jS=>KS@N%A*0^3$Tq{?0q%DO9bkR^Uu+x%je|wkWTdJ|qtcq9tGK@Buu;wxCX6c{!9pNWAQiWQ?}@U0)P5-)5hj`tkOlPD<9xrK +(yrO&PET?+e+mxN1FlssNdi8mY8w0o>E>*{GxE`*>m0P?ITIsFbk?Gzs%DT#yg@T#cDg8* +myF^ALAVXt;lb-luD3Q*(%>LvJ!11in_%yRvqQR@aD*NOQ{3)=zqj}G>*wEm^@8?MuDR@+{qJw?55Ld +hzoUEqwm-@_*ceL%zIys~)R^g8S77+ZH~$mK;Pd1Eb9i!pWGMa+A6=JC_X#~+ZSgrd)2CZF7?^|O^Zb +6~MexVH=ui0v5F5)D%)fo{_Rp{1y~zFxzr6hN)$6w}o;`i{V!Wp#bZ+aYk$3~-zZRD4Y4kNK#hVgKW| +vDYp}mAl0A}N=P+h=>1K9%jl;U4yZ3C2l?%jpW4; +n1oBPH=>_-*f8C!i`XY-3OmxgU~a(U&Je?Re>bq0S=N_^VI=!+iUt;x3LjEtGR(jVQ0KUg9KgTD +J|H3bV@v26r7j4xdJ0chq4b+(Vw+o+FbR)3|I1wf+>5O}L;u88j +L{v%yKPKB(Iw~ztK;BLSRH4a@f1CbQZU)sP#rN=3?^qrxWaE{t{mOiY~F6t%%rM`!+B>Z#>y8U=B&7b +pjlXNiWh}9QMtS(Ha_NHjs-~f3AS!oqLUhwv!!tOW_h`+Z6Q??`Zz%o4UC~=?X+cM^p%k25ZJ?3_BQue^so8_SIrOA2UpyJ&=)MgDw-|24Oq+zP)EcSqDz^$nX +Dg6g@jiwB>dG{P_Eu9Hfo7!4voaTOpBXo6#Q=V0cb$l;OvzE$M0^3EGJobdZ$k``R$}%~?+Zyxf(Y!pNzj5^B^4k=TL>_s3;$MC5x +Bvm5ka;gsh?03^c4 +2pmXk4nnR@eoDHy0R@uEG_dHRs0}iXJKj(1K_g%Rcv@Jyw{WXm<>yVkSy7gA%Wy>Y!J$luG&u8Li^(m +Ixu$VDFdBW8r|2<$8Jw6apOg~PCtOFco2UnRWB52+##UX%*hmLwAzt~TR$#Q!FhF@6wBnuw31yImV +cr}mhBKe78jSU`98chh|U0PkyZRbKu +c_FHs{IH8zny!v;F-NL0Foqmk?6APn~LZiOJR>3lBG0 +t2x;mSl7n)x_J7$@1i?6(ep@2Dq)QX2$|iaL(heJ)cijx$)y6^`Co!vbN59QVDe{w7R9zZHT4$@ISsPm6Q>hm3tJ`SnRcOX^%&(m;bnYX8lt8|5?BOMeMBtuo^fd4PNJl${w7hk8R88u@@aqStr)o9H+!|f4DR +&9m?H9$5TOLBO#yTV>xrwt3EVly4on{-5dKM2h%LUd(CC3^TiWXZ5yvVa`Smk9tCZ$>!bFRROEuoAOg +7|u?+@KpxHMfWcYWh@g>a9)#d;Q}w0mBPM5p}DRrF#jE2L5kHAWDWjOP|fIlEX^Ga_ZU@-Q~~+$wAje03#OJz+fEZ-4vHixj*s7O=T6)&6CJr>)_n_sE?~C@D2j4!wbESw6?(e?7EXD +EtimX}9K2+3=qN{ihN6$DfvnlqeC<+9WF;9_~vRgsg7zrj=)ZuQ$ZcC_P&}p95fEp%sPT%_+eLhp&VY +`7b#gNHyDFxmT<Id7nLW%O=5PpwQf>>Z^Yf&3&3FpF)OW~u_N-JST!yj+nE_@icC-} +;!TpI^C5>-swCYH8lGbDX8&AwU(^*qvRf%Uv(TBG-;HuY!+0AU%aU;2o=$wWj_)9D~Ji8ETI4g@a2CRJ2IHxsQie1^3bS=wOT!-b>TIYqAUN7Qe7ydXhwTuasp*dXBAeL=e|-#u)u>voKb(}8-?RNy3_nD5nXs`Gp=i4yM$+% +MBv_Vfg|M!vUG5L;5rb^+~+#F{U +e&p=5QFSX!~o}Y*4*AO(0H?hn6XA~r9r%&y+Ye+QUkjV@`X-9^c^pIHBF0FD=*Lk$Z<+j6Iy-a$p;RS +?(TGR#{DtqS;aStyz9sSQ{#rBUk%!2jDll^$EadND4a8my~3Ke-Y45zQcFCp1KFY%tW<{-<>5-&05ON +uF5ZB7@}j9wu@k{nd?PBQa|RblhM7}>3-&IOYL`IKC-I|qba1aHfcQQT&=aT|xMHa-?;x2?w80(K=c> +yI@W`Ameal7M;U3<&|aP~~q9p4N&*{XDD4rc)!{OsA|NAd3kuTg=Tc70qnD*!Fvhq?G*$-H}|OVr|!| +oH6G+I_f9aL>D{L$Qz&^3pHNdt^*hQY`KXivkIptBi|6&J>pvti4J}p$f*#YP6M|b5I(2$>J;~R$5+> +`0=YIhk%cj!BHy-ayJlsNr%cx)*!sGFv_^LY%HB>>8FVo2R(vj3Ts=IhUcwmarB!Aq;k0BX$j%I2JW) +)L=^=**@(kTbc9JbN*_p}1U0<0=eEelN2>{KSQEUQ@vLke)BpX9GBGWKk1}_Jz=vKEHJkI8ICb_)x2*is-(oF))>S)SD&-!Id>cRn!zRtBrzZ;;z +Q-3Nf$_>>0zsr-tk;TM@Ut-TM0_!|I +AO@Vj4#({y2`WzcA;DWHZc&b^w-w}ZDrlXb`Bg2E5|K6a@J%H`&&L^b+wnMeRksRS?!_7RODd23x>z5$d +<(D{@a8(Ez;Pru1ER+I7`R2!X{;I0H?O{W@$Q}4(s=Kmmgpxr7n6r`z2oB8hR>!}W@u)FGm#T1!m86+ +AFrOAq*oy^Qv!0g5<@>UfmF`eSsrHf@@x?XL+D5HgCRE(X3r9UG-lJk6hlrzW;4RRRbq3hN`Lb>}e6 +m`W*A?p|jma7T9co8ymOUBnT<&GNqDbf2nl8?OLDIU@tM;?m7H8cg8a+xNJT8D4t9>ff;ksT;C{Qz{U +PLye?@OjJqhriM=rF`2KM7kUw4@20W->;BGl(jn;UGu`i{>`7p7;%phLpZE3HvP2YMIO!(&Gtb0j0Dv +la888kUJy43uN43f|F(7evX_0<|H{)gote%uIrsAs%;v~h#jLmkq%N3Aw>a +dvh7VyOWVxV4sxwNDwc2*oO;oO_U03T3Ilxf1ebDmsBHyDChLw%hr7y3 +2`|Yz6_RpdiwU>j_Jml{mx7<&8B~a*TGU3+CTwfA~oZUmGa*8K^Jg%GINeW;b+o9MY8bIS5EZW7=Q!c +wVwD1^;!dP_6qFX0u$K*m9UJmuGblWMRJu{5yCVhxLJ6Mmi3)o@2EsBn8aT)q<#;pXXS03aA9{EwgI1 +HT#7tS8v*qgw-1J!kBP_u{iMfO+$`~VJ)kc(jCHrWmg48D$gldqI(6H$u)}{RKQW{W-(sl>{0&cQT{N +Wm)8&PKmPRbf0RXO-Nek}i98nbI)AvuA8NK-5FaCF&&AY2CIj=RGbjX%gNa+6PzY(e9`=rnS7nqPW}RUe2eG|Q7#or-wdBNxPr|?v|AecWJxR$&+ +R7I{dy+g~xZO_@a2yKdCLfZlINeMEJI<_*xj@br^(n~VsZ_lO?A6SNa?`FkQ4>%CO2%9UrOoaE1>S?{ +nd2qWyh^%jd!fv<`hzLhf{kKFa#p?I8HmR?bv7ilNBP-Au*HtgLo(oz-PfV*xV&IpYWfm-GMg+^0xNq +Ir287VbKV$q>6l=Pr|-*(vuRfljb+b*L}`?>iWf4$L{d2;V?#Wf&N$r|70yIUb9Gj!8D*JG5sW0w;lE +uX0?jZw>}HQ#}BfZmY_%Za78WYm37^4Ch^i%&H4UNF586<4$_!$3IgvW%+ +$Qt#@{Z=%W#lAhch?RT$I`2Az*_sRVEh{r?W<8P5@?;-|OlV8_`U(X7^d%U~TR?FI~i=eTx@5dGk@rGEc?tcMBkI(&SR%o9P4?n{`xiN41VvwlNN +)F4UnL+_Yj=`%M?f(;PFx0^R6Ol^^W(Ch5g>-X8Sr(b=Qz5mP0ciA_up1*$f&DSqpy?^mM1JU*`ub=; +c_(#{PV)UDxf@Zq`VQgq#6W{sVp_o7}mbrSyE?H;{a7vt(a*{|h4@#hBPAXyuo284eSE(q-G1(iA@0! +NJ@?GZ@4rU7&HMenPxnE1RqeYgl?lz%GBvk>9SLBUjn$cFzui^6|*1hpn(r@JApc5epZU +)`y*k*M&4LET{Vvtv^Ebtz-kIv`O|-_SdZ(~KwX(Y86XAzJ>;kz4JA@3~bxh9J1SF@XsJXYg~7J*CR7 +aEXva|ET4?DYh*aa=~aG48fud1tj=LB?TW1R-YMYbR%LX!W?74*avCNg&5Err%t|E3#7E>SRu(}r_o& +o97PBgv)M+{a3+<0j?QzPe3@4>D6KT@7iwqBx*_3ScUDVp>BvDV5 +kv6Y`L9psCSI)5}s{mTT0-!0%F1At;(y&G=uFY&(i0CznrrXJpa~^0|pw9_Vq9Q${}|ipJPdHatXfGC +6+qgn484kq#&*e8wsEu{=P1YAZ{!+a{XMsa~|}GCEnAbly}sU7wNxM-<5e9 +zOg!8im_<&9_&Eo78dW!{fCULZZrH<-|D$M7im0$rA4&WBhE;0g@vf$`4ra)RmrRFOq~`i7#BCwQqxh +(9+C|44z*VmnA%C-BVqW(=9IRmjUsIqX**@+n#Ma1{r+n4WOOx}I-=FRK3#tlQFm +Y`FDH`34J +V~!kkXriTu7Xl1Izhg7|k9_5+8Yfw?9<(9*x_{G!mOwI0cg=hQ-8e>gqsJ8=3S +&AEyQ_&UD-cAMXD{;OIZ+lJi;85i4-Ur6C)XRzHrj*}a7u0#7LaT95#Xi*6eLT8uSD<+Fh +Q$I?&W<7esx#YU{tmOFhllJE5&ueK(49H@i^QP@`U6-z%=M3ND@X0}jA@kX0l>ysETA&O#dpqVpSlZP +k))!hO6iPKLBv$%nriy>1^ho$}-4sm)WXo&-E-S?Utma1m5U7a*MbjgG!T^TKey8wZDvPT#9cU3=to= +fDdr#p8m+Ddm0z*E?-XT+)@xBSd*vY`iX4kPxo`QFGxRExkxa*-c>;ik*LVp0Q0Tk*h82Ue0(K0LW{z +|E1@Q<(tZ}uIk#FpfqY4ifkW>EqtefdTjl|{1vnU1ZP^_k?_Q^gj!c%tDh_PwM0pqR0t%=erYEPQvk& +n`PaaOfI!4xIWZn2NEWr$QsZBPrq^MN`b`+~pw89_61h6=80TNzqpGa(LF4NdGLI#9gDmpqoD#I8w?6 +ZtoR2hz!qB5ejIlsk<6c6?7=Z17l=G=Ea& +K|#d)ra%Tm%=yF}~LDZTyl&C9H~E-I=Ao-@mNk75SV0x>blCXe2BuszDNGtyPod;yXLqSr0YpU{xhO3cH!fz*+T4Cw8S;Xu%GctU7VPW~FPYsdLw6o28eTaPV_I-dOak;9hqF5 +^U98h6kdVVpy&3_!|&nK9N$pG`B)MamjhUDS$|Apd6XMg_&#pg*XvC{mPOWuC|R1iQ0Ca^U&sSpWqPW +iZXBls!Jk%`!2fJ%-}lCJvE!<1i!A@>^)sTv4_biSCXfU^mbE>*fRr<1C8mX)GjyWVlmbO88MBc6ox +h|Vw8($PPJVqf2$t^{fg$*5>7tJFo2$+^!sVKsBat-;-*WxJf6K!*#j4N9)`ZiC7gloB9Wn_i=|=>Js +@dBW4@RH7PbpZH(Dy%iBAWjUGcS``-&+rMUNdZh>p;m3ptl2r3}GzPVD{vP)h>@6aWAK2mm&gW=Z;5a +g34#007Sm001BW003}la4%nWWo~3|axZXlZ)b94b8|0WUukY>bYEXCaCxm(TXUjF6n^(toSHm{S>l*H +Zf&N9C@NJ5S-?!q6Gfmky#bo-ZjJu?J>4LpiP@d1^&!H!eCIn?a|L5o?Kxe)NHEd?+>LJUU`82VGXYN +o70D|V@W-}({Jt&{nh#S}eCu8HuHcdIf(k)d36jA^5ED|wGofG^UEz09W{^=KIep$p0`djH1Y60sgcD +dXjs|i +0iF-`lkG(i&J|3D*MkkNV?DSwO#J|nEbk|TkM`KHToXwL_Bb*T;qZhWW8VwyKbMGxHZZXk)=bd|v}^O +KvYJ~_=ws9Xa|@Slq;i-B{sLS-RJ36k+8Dx$Eai;#L&Bknem2qz6l=>OkH?Y3uK}>*Z~${VQJjyX(NWc-iosV;&`=@8&2XFXi ++gPadx*<%}isEvOFiLM1g26$ln`MYqLZWNegmNsppL3GO5)?g2UaYQbO}uD)udukQw2;7N6tvdc8QtE +mUNX-aYhhhj)FHrg%Z$CD{C3pS!i=mib>$z&h9LRM +gzJQ_1%6$>zNx1MPa~jyhzMkd2%}T6kO`Nu6sS?0jlrq9)|^d~0x-NXeVr4qk(9_G|1My0!&CqYemNDM8IzsN-bxdr&NVx%w(mlQ`Y?4=cJfopvr}6`QIAW>wfNdN(rw97OA-fxOPS#C4Cc5-RSb@>Y2Q>2kKJ +SD~4MM*L4_9@c*Eamg~W1sK34pGP#I{Zz(C?4gKLRDEF$V8M4HDF9IE!^f6LFOXJq;&e_+tv=_;>^|% +C@?2NWQHyv;jMuUG@>kFg3W|AF7TOoC~w@f)sLCwA!?G#gww6gsV3nTgd{3oTIHg$t(XP3z?C6$C|Ul +E&g#!nrO7f5~n=SBPnP)h>@6aWAK2mm&gW=RjjMguei004ao000{R003}la4%nWWo~3|axZXlZ)b94b +8|0ZVR9~Td9_vBZrer>edkvUVi=YLN_E_qB4~or)Jh^ikuFKu2m-^P#ig_@MKVj$wt#$q(<|Bn3HsW8 +K>w*<(%I#by2MFS6cJ#Lc6QF0v$Hd+1L*hqFwY{EE}lSD#{DmZN7D|#%vo43B{2!Yr +al<94T$m#C$NZ*R2Nn-0gsFg4-qbckZwcmnD%UFIb(^lrf0T=Nj7+JM@TUxo;g8>acbFC@LVPzS%E`* +e}EL=xIoT{6M#PvG+Vk(3D}l#Y7-c_9x@rubMViIX&JVTqCH{;Ix;lh5MjEGPrjZZ8^*xUm>Odt!;?_ +86sMXPf$w5g56|Y$>_D7h*X~;X<8+uF9eWC$=ZdruQ{S-bwk;@hCgbRv}qa*1ksyJqMV +tv?QX+-b3(PxL9Rfx6@xDNSM&Z!E5R~zpJ`U+|T1dkO)ss3!dp +jiJh;u%w-WCb5#=5YXr%g{7qo8PsR%fn4Oxxm#SVriE=m`n#N33)z%MMmNhtxoo5G@J)m~TyKw +VM?e#~Rh!<9v^Ko0r;Jytz0?Uy>&qK_ld-h(LMha1%;v6iAyTjNY;D%0dP}$esrN58HLQzPH&{m`@3y +UHE~2fh%3w!|r6`; +2e?c!%-NcNk5^=gG%1zWr;T@$Kskqm|A%U12%GWVd4ZGAw9;fKG*{*QJu5mHkQCAC>(<+3%J8PTAMW- +XC@UZJN?HAGTjTN3~~baPD&a0oxzB2H1m-8NN?Hv<*Va!q9!yedz3p=rw2W{*QsL8D8`sU%q$j@p0pL +&wB`IE`h~L@H03Dn&21p5P$f=zz4Z=tnXH*FKvlioJED>_56b)BkG+THKRqb^GK|(@Hg-ql17q@ +wvcD?(+twKT15ir?1QY-O00;m!mS#yRfAKI60{{Tt1poja0001RX>c!Jc4cm4Z*nhia&KpHWpi^cV{d +hCbY*fbaCxm%&5qkP5Wedv2HAt{Kx;HP6+sh}E7LXsS#n8v7eP@JT8pxY*rGsEyV+yfq%F`xQ6N9>mn +Z2^rq@{@=%J_%9&tF|&x|Ra!TIBJSnEnPn`h9u`utm;iJ~(|bbDviX6sLRZo;-z_(q^MATuR(1U +nvXU-5g%O-|S1Z8?W{LMRbPXr8IkGt`|)5ST+?@$~vR2J143OFQ|A=uE)kg1O3~JwMs@Ireoq}9QZqbl#rJfhXA$7DN4|0+;W-QjePWA;`R8?KEFS&mP?%0eeZG=4bZu2SIka ++D2e^Oya(wG0hWK&yyJOW<^7Ux+&`G6ln+INw4F$6QN7_id7aF`=zK|ELT)+A^>2_OMX;F394PX#MH~ +9SVO^CmQ_-lx7LwpzFZz293;va+2e{83@x3QDWp_@ZybYG%ybFZ4=vGg3C#CUDEP#wC0$49Qw=&QpzQ +U9oZI?ZXR<>=+0{{Rf3jhEg0001R +X>c!Jc4cm4Z*nhia&KpHWpi^cXk~10WpZ;aaCyB}QE%c#5PtWs7?B4cwNNfnUrwd%1{Sbt?9^)#oq7^ +7W(|91Y~)>s@b5djHel|!l&Dqx0Je9&Z@&3<#`X;i^6kD5tF?ko+=ctQ5BD$@d9lhRJaJrzz6uGyyi} +*ZuQriLdvU(`)w;26;E@*_A*IMOP&t&6+Ylq44V!!^68w*{B`k$hg;!+C5N3*YrwnuKQ9#|oC6}(yx@yHtcoa8d}+hB$X~>gFOe@&_`@Mu3 +6@HH-p(3a-zzY?v{MDM&~(82v-R%tjnVd4X0x3Wt-_;Y*BMi9KsD4i@u44J;EdG(8% +W?VoztI%l}WxKMHY`%oW^+V1u8KbXn-b6iQyfcZ$!_sk|N*0e4do5Eckp5VzbQ)g`Flcg?F=9Vdq$uH +NifZ4`u;F%09F|zkXQ!_1pc=Y1?8G|M|kox{atfjiiLk_p}K+ZD+j$O|!44bYYrd(T3Zm&u1YqhR9y}rIfYoD&|sE3-}4*ca(G7)lKx;7ZO~-&KQgG$Ky%WtV1G?ck+s?azgIr2WypB +H6C;uQoju8Gm0&vwl!~X$~~yznc!Jc4cm4Z*nhia&KpHWpi^cb8u;HZe?;VaCwbW&5qkP5Wedv23Ztd2U_Rn6a-08u1wnmWX +U1vT?9!`Xf4VnVv7PP?Ph^KL(n9LyhxG)P5Ux^k`8IDciU5R;D|Hx{mfWCf|L6vurj5t*H58qtCJ@_6 +GcamnC9B*^`?d6)es&(eDoNm+Ss*maHgzH9j(mn=jaH*3uSlOIc;ia4RlV$DAHWV +utTW|V^Nn-YS&tQ(X|TN4U#!iwO55zP#KF2*T~a!wlPk@m2NkHSszW;LZuWSVxz3OxQ4YY>QrXd+8F%Q=jhNK(S)0!W$yqBzMUqXMbUnVbQqQ^FCEBM9kksk0UU+zxm_AU>I69_?7><>a4^6#B-3gQ&Gs5s)DX5i&h;wwXJ#u|7h&^|K}e2{(B$)>f_)4yMIUSe*sWS0|XQR000O8HkM{dX({S?U<3dF76||VAOHXWaA|NaUv_0~WN&gW +a%FLKWpi|MFJE72ZfSI1UoLQYbyZt$+cp$_=dU<$9xQJ%9ecnw7)yYzOV?m&62u<*sM6B0&6N^4l8U1 +Z-EZHaM9EIl8iGZh>vyg?gXwou$aNvB-4bfQo&FpsjGX~MmW9_W%O-SgAL#xw$Y$Y1>=`6?kZ9i0YY23I{8_#|mTx_l@7{Duu1Ku&+xJ-5 +`bIIQ%M{%;EQ|HLIQ2;gT_ea(Q_PvNYOyu+c+Lws0}f_zrzC-g|G{ayC004&1bUxVF3TWYFNw3tzj8Q +iy@LI6v=s;|^F0AB@#IE6S39ffCiOCOqSS-tt^m6p0UNYg;2@oO7U9?(bIXBV;2QrA0vq3z_@mGdA;! +@uN^R&c`XxbrG+N6LhEX80}&}6i;|vU)I)>Aa;ilWxX6NdpZ# +U6e5f|Fr)O8F&`N7QAhuhJ~Q}*vGpE7`#svO;w4fN3re9yaJ30_!vdz@5aH7hoG|hehj+D7Q0TlaDWA +eiU9pgS55L5)yAn9|7g9Oic0J27FTKJnqk4>c=VKy2qIHC_V=VZ5&gX%=sii7f;`!70Vm?2g6H(NJ- +FBkSfCY_+tm7Wh1=bK-$9&sgyC`2+qM3a|b5$A-UISKQqY!GVXzqR(J6PRb_eDrSZh>0INfIHoTkR<^ +_rjCwA|%g96KoiZk5mn)U1)u(E6wYj!D_X-p;Q&MLJoHoe3Vt84~_(+8x}{@bx<1`p0J}Jw~g^(l+3> +2B6?#g@6aWAK2mm&gW=VDXxhYT+0010K001BW003}la4%nWWo~3|axZdaadl;LbaO9ZWMOc0WpZ;aa +Cz-qZFAd5a{kU=F_AtH+)y~}ZdG!{TDnS>wOLhc$+6^1ReUaZNDRd}fdGRS(cG=gZ%=p63ub@;O*y+s +-Q`$inFM-zdV0E_>FH_Ul%0KZ#+F4Y^M@I0>ebmF@ycj)a&j^%#eX)Us;ii%d|QjM8vR%IGaB8mWyLl +{+GGOwP2lx?6jazIYGSk|)0tC(aN$qn%;s(8 +!mwfR{U%STa +$-$V)`ZB$Dk^$)_2b3+*Z0ZgMe_3f&8yc}$=i$jpQh|V)QQNIbtpxw1y5lnry~~lY)i2fd74zqwb+P6 +u994cRHTX#Z|b$x<`jj4i7)vBUJvuDLuS$z`xfV=6}t +WTEEaXKe736Jffat8p6~8nw-TEl&*@k>w%cr36pyksKJgiV53E*SPQYyc!VPVoW7JXqv|~q8cd%0{f7 +oH@)6T<`wI(rT*ZC9AWO|3r$&K@%^BGYRKnb~2ehN-C8bR9`^)sL!g!@u1Vg%th109H5^E0|#7%&KOKy~Zb#(a50O ++uPgMFJHrLHfKNb3}D*5b9en8S8(Iob9?pO)&0Bct2?-O?olT9*Ke+F-`~THn*tWF(P)|Rs$wqzelFC +K7Zr=Yz+CDH67&|sqEz%xCZG9e3v=e=urIL`8Lv#d;_;#Do7iVr`*JL};a#Pd*QW?Z9F#V~*cCX8$Q#UFRrN5vKtf2uK{{i2F{nAUa_GukJpG45oR5x=Htcm`7hG +rj~n24x`M+Hw3lB@+8Ve*v>rJQ@Id@-t$zEWjiyJ!)es5W*$SK0+Z%-fR}ouvi&YIa>{CqDIeQd5L@6 +HvDrXe-?@p{E(Yw<8X93Be&;IsA?JyHuv~J>jcAivgR;5eVYjo#^K#A2J529QpRgAvn@a@m=$6=>KQE +`n-;lpfEAY+DEHOP9bi@Q*lb~i)mtZv@s9Ag6?4>LFlEYep&`v|4cQJLK`205^U8ADz%~Kw-#DMb!kE +3>qc8C$qqs)1NDGiOFKVW?HA>cyTrs;|v3=1n+*Ys$u(l@SC7EhjWUP2n7J(O1sYXI(VtMV>5>&Ypx+ +mVQi|vjHZDL%pPoF4u`ef`4RkDRImKW`1VXs>Q{`M_pk%4w+EoLgITst$+4$Ka63qnixc)|C0plu&j~< +I{7em7y;=RMz)d<_$}#rWqVOO*EkT`Y6?=-_~SsBH0^o(yc^dASi4>K>0LLScjCbzW+dgj7i>DKhFrO +P*?i7AtY;o;99--*P;q^9KBd)PMROC|M!>J*IK;Fa2atAWzGXzs)Z9UfUw-v(sPu?QpwRtJoa&g?P@H +PH^$Y_zb}xlm=&3W*`e%qzIojNrq>czAnUfTXy8TbRKBmfb=Pkd9YnczCu4-7)`ayh2p)kcNQG{MY`4 +Rl0?O0u-2zx@vfENI3hLR*OLgRg&2$e4aM*r~3k>r$J@_bwaa_4C#aP8$O=6cxJo7}MqV%>gV$zF1Z< +Q!JYD4d)c<@Y$t_-2tpT-)TN#i>SNSz*sxxqO5GYT*W|L)JBDmiCU(73^hr*3jZhLyjpDizZ#K=qsJt +b#1d}7-5T@2JG^{KAk?wgt}Jh%wn+bDf7DR7-SE6a5qiNds}Ki?`!Bl!jAf9nk*9(If+nbi>7kDu%s2 +KS-x=H#_$c|I9QV@QGfwHrj$V-Ts5T%Lt1$Hyu}Qg3RfW*g$M$ssaeoEt3$~)?$>dk110Q-gNxXUPyI +dR|2ztGnEe((puYN6vga%zAU_(zkAUwGa=WNAcWpOV3)&^y{M&3>waHR_wqdCNV6 +DWnJxLy^h9|x*c~GMl_6^Z!p^jlS+D<_m6NQ;yQV*WN@#a^zHeda*y6+BiY=F*l(#to|`Xyk`@#O7V= +&TgBQmv@ZlxBPv^V7cl%H*uNvudIA78F;@3}%f8u%cta!c8yRB_bcg|D-adyqo8YpMlX%Dx`ze|5ve;g6Kf#q>}m!x+#{D@_7g|D*XY2??E-NP`tDl(BS>M*F7?mj +W+3&ov_KTWvx<(Iwfs-GHMQIq_M|9;#u(s2SJiT#UO@aP6RNNCPqs-@(hk_2kg)u6uCD~*+m9i$uG}z +>KN33Z5XuSsMpwQ0ix*9N|iUm2xQhXai>>BKI(G8wub6p`*3~0Gx@39_mw#TjZQAD(XS+^j)URK8sl4 +T +G-ZJIzgq1OGD1H-wwy}23(2wTa>uD;N}Z+lW<+AO3XSz%(6=SxA_aqCA0wS@hwWG3`LKb(II6G9~B(S +7^zXl-`7Xu%oJL(;@l;;);9R=+G^MCf44|U-dA^ff|_on8K;Wz7|ynXe= +L~Q0ExY{8>(p?^KN&h@b8eXpR!vtAtkguXcdg2cLHKxU@Vfw9ET~G_4(sRfrcW +CAJ7r9C@6b3A2}?3*GZA^%jG7oWQBfFp+)h0uPQ9S{PaOb%k{D;OOe;vUY7(A!^)<7O#%&F4*39{AuP +FBnReH#PHZ#>q{ab?)IYHf8Dd`>nE<40HAi{m;k;L@(#_qI8htcwj9dJu7q&G^V`eM6y>gE|iVBv!W_oURhZB25r;lQt+&NJ?YSJpWdFS32qp8QkX+Ce}SOT962H5{(+O-PM~^BS#UH7FPv0rW{u5H?>h&GLjk%Ec +-UzxHjM)R17kEUg8=Fng;~4QI;*A_M)O#ybgl{iH~c{^krixH)d3pEl~3&PxZ25DLm;xOF&?9pQB?%$ +6|v;HK91)Y0dQ6~;0RW18EWo2$$FcCDoq^RL(z?HZ-iBxbf0T()D>+p9wx2AuMsDYZ!jr-tT +vM|@ruT(`6pk=WQrR^8)=F-4PS7r?S8<cWgua$S8+6f7%y}Q-xZSwrC+(=E6I?^oHP5wxme_SxE?296$<26bjgH +?<#l@FY~7WqTH9^+zVXl;gcAg^icRGC(1D{G&zb3a;{s=OCO(;Rwq`Z`d!j}99LnR{&J_{R^>^@DkT! +acTqDl%~Ta;lb|4d3fSJkHc%5IXmU*Yp60Kn8KIEnLPe%87n#&x-uZ`L8j1OO^F3@&ui*lc8nc#Iz<& +YE;0bITPA}30~?092NzhM{88Dk0;=IMyZCASPjWc+GNt>q*Tx%-J0pcr!I&dD|&<3NNJ#A^J64@$u}*1V!)A_c3uk{fey-7 ++up(NInX(^8Lmw6ModT-wCozHyd$=;_!=pHUF=+#cd>Q|m!T$Czj6Gia`%PxUCb311={+Ve09_5#x52 +ZI`AzfP%n$FRdi=R?C)jUtcfK4ObUArxNSZHxAv0O;Rc64B^PlW6X`hIv@y{ +1}V5;;2=e}q~J;;Pvz)UW}s~xo*Mg)XB3YdmT+7Nec#67_8_yq?)p+zT1+@Cr%ZQ;o}#Z!u%U~5^cbD +OeQWPnNxt05q~#%GuD(dAAGa)1|XEhtb|5l~gAgwGC>EV+4x2sx>uJZ4{Z5$0#7Tpe|VZIZfb%|M%I< +h?h!8|dD=SE~dEzIWy|<$TdQ`o&y8QZ{oR`fE_S2Glxt{^ +^IKntOuL}y8$Jg_AMmfmW9c71p8`LYpD+qdHkD%cPN$KsOHGYCHS?i+j#Sc@e*qMuMm+<_ +3C5u}*CQ#WW6394l0zX4E70|XQR000O8HkM{d$g9t&!UX^Tq80!E8vp(SCbpNJ@#ET +esK(-NpJr79`Gv=bRaiUc>g*Hl!+(YR4vz9&KEX@ZrX#LH(%|*bPYdZS)yIga%q1bL~$-tEDgqRuoUS6cluxu;q3H +ibUq%zOlbt-eN-1OoI=to|T$in +I>rHn9R6LRj6#X4O&1BM>3dA=;J!H}6~oorvkx|OS3 +{VprKL@aya&fJb+>vA@LuU#%sWT>BpYX&Ei$t9flWlflsB!#}{JXPvO;zQ>Q%8`5bgV39x{4>{# +>2p~pNv9MAcH%qqw|yX!BxI&(#UHIDwxVkNGf8^BrmEaZ3S|LH-vxl)E0Osu_?IMicH}b^B`Zq6j(C4K0ms&jzH1dp(vC=O1!Tles|whW@P0*>NzY>~$R;+)g5Eau$T3<%5S3lDbZ +}6yejGkzOV~{5?ob$+4v*!Wgfu*I$$4S(>Xtt%3sjYDxja!T$QAEj!AeNmWMfd@qHd(imDnUc#ToZyg +2s!d4}zhck%(;H^B8NK#YvZdC|w2k(0yvqBD({?KkdP8xHJ2S-(Sev5z(aW{Ih$vq=i(TtJSr}OlmHJ +)(#Jq%2AX97^ADiiLU7Un!)A8crv`anhcLeXQRmoYHLD(z46XiFno{M{d^t-n^J^Uo7U>L$9h93;X*8 +z?46cbm8zVRV#N7G2%=*T>lSy!g`BNhE=lLK*0VJppFxUL(kq$gT&r%qq{QI>jt;I5ug;IpMs$FXfVi +4PZrmY3fo^5S%Z_m-s4=)cm?R8R(r!ysI4Fu%29lf6cjODX?l=#PW=Uu3T`AT1$f6*?gvERfnOc?HZy +H!bOQrlb-H%*}&QSYpu|!08Motc*T%JN%Z~L+1w9ogSG>9b##;m8PTSt_6pTc +k8?T`s@t`OnMB>U{o*j6Ty`cbByCCXnKEtzn)BLgL`l25$xT0s)v=%_oE5ty0CT`4~P6WmE}O``EZW5 +(+eJ&1mWkMH*bE~uZI~Q`!yV{p)z$V>+o6AA<_u)!Vy8jrJ6MrU3`7J!HG4V=E`8k1XhOD1$W|B$qcA +;T#*}<-XN(%EvXx>7BclZB6{X?t)CCtL*U-MS#YmC4~C(UK<>I1e!ki}S0z3+HIBoWNOaXCw&%i6VX +%9*^)75IhKmr5lrgXBX`Whal7#Ki>1M?ZnvY&PE$RAn1_o{Bn^3p2(PODPxFh*W2y8di!!;5n{Xn4qd +q}iL*L0uwDyaFrxSX6`oR2>;$DbeY0nX0mXI4O)$DNm;J{cVxf5F+|?9S20fo3G1LV2l7=w3Xch2F&< +PcODH9)LbF_MgF5YW5%+caYr(p91`k9}Dn=pEG9-eG}15ir?1QY-O00;m!mS#y@P(3GF2><}^9{>Ox0001RX>c +!Jc4cm4Z*nhkWpQ<7b98erVRdw9E^v9}8EbFb$nm>=#lnU`GAA*ykuw6L!ohWX7b6!Zuzf&^G$1H(C2 +dTR%}v1OUnIS2egr=n0yFE~SBUT85*wI~a=NQ*4zQn6Vn*^Q$}^ao;Dl~S`(xi`t(n-u(T(U{3_~~nAPba6Zc>w}(dm2y6WtD1oT+6&lrQ$=Tv}_>Cd%=|h;g4FTQ=Qn)i7u0 +Gse`Sx$Qwwalw<;c7r+viLk7SF2>!qmppQHnG^JBrs|5LKu<4J%;Ns);-R1RNa`(4Sm&vamZ$2b{-28 +rdeev<_xSO +SU@(**5>%!ak%vPhSpnkrRlRmvjci(InECNbDfM)b6zl;1B +`8z53Vj@6BZ;u-MU@wPK!!Uz(2_E*`Tv2LplM5``fP+*vRL#TPspuA{eXt)sg$hu&a+jeOP%zK`{y)N +~tOLLkrcnAoHc^@Tj7l;TgaV(=Ao*bmi?E{0v%qCP*e<5Qnx`S?UW)$y=xjz!=b94md6TRlfwx?%Jmm +HDlh1CP%NBm??C9!U=1kiF-;Vpv=_69ucd9GU9K@)C3pC#6j1J&K6|Nesxit*0@42|afwVSuVbp_@oH +PmV)&S*Tia$A=;`k>=u0p0RJ3ws7zlGGYrYQ@{6Z%M@dTw +R*auFKP`c{^FL<>Ne7Yd5{^Otf0IN~~9Ojz69MsF?^{ZnFrv|4n(xeu723-g`uI)pt`z<*HRW`(?$5S +9Wtb0F``l;e))C~FOUOc7w60Y1L=$C*1g0BsN)9Y3Q0`L&Nm(_Og7_xL207%e=c$&{4Q|QGGwhUSW=p +mO?3emd{(?EG>*n%d|9>3{m-@0(i5cocxcAYix84f@EH_8?93IjLn+KZ0*xaIK!ehE^XmmWIXymQtA&`tXtF5lJR?@1zvjzIKee|ZrEzmQk>AJUwXb#V0R%_HhyH+I|SU@&ZKD17i}Yb+|1f*^N;;Fcnu;=kb@ +Vx@{}nHE{O4BvPrn7VQqcH&)i;{D6n@#)vdH{0{lbKfz#t_Y_?BjeDr5%qmTV{z`sy{b$Ezkh2;cxl8 +^1E-53&jo-M6?t4{KwnJ-#=b%1!cnZMTtL|!_WL{{IHAVwz%hT;-nW)JEd$nZoLobD8*#RV6YY`D@eu +8BYLocPs*83ABT?vhf5P0?oYMdO{AzO>mULX~K%;G|zoJ}cmO@bN%U{}63$8lG?T9=EZ64V4W8dj2`w +qF)z6I>>eT4<6qOwp1ct=*Vy2orabb9T0vFWn9nj}s!vkvWXbBpE`d6pj*pb{%2s_nca8k+o17-FQ>l$yr0xxA#_bZxGa+Fhb<_5cy?AlIO66R2d;c4* +xMtmvg3=+EFsCs`M#cV|07A-GsOFOWIlVWs9Ix>Ur~6oK-tW?TuDlW4xgY~lOiNte8Y7KR(?iN$oI@D +ItuEcD(`>bGERoHF50Kb0vq2Mrsd2q0I%GF|B?=RoGXbdpzy&Q3;4AJDAn}zmI-Zo-6Rs6j3odz&3go +*LboOuxa&k-0vfWE6vHOhlV#WFWrkV$Ac;$#zDqxak2V-U)+$?*$dt9RhLAN3VM#+@64VgGES2&oEA@ +;h#U)agn;Kw|t(@o%myL{lC(_SBR97@X-2HPx8=V}axSHE34`@o`iE4{uBZlBz;Jpb4&ziK1e!qQNT?AP(T2IQ}ig{QY{B{va*)oy(?#N;|H~+qi|OQ +p4aySdvE`1UP3F~RY4_rMb>w&GcBv99?a&SKte=~-N#`|f?m_r`aLoJ1GA{Z=~Cz^k7cbnjFCqCdD*Ck5-$X9)SluL#&Lj_YXHt>W4g90pH1e8+*$wE6K4c!Jc4cm4Z*nhkWpQ< +7b98erV_{=ua&#_mWo_)eS+k=^m#%rwuLwKmrjDtr#5~BXE|`S`NFe5$HfD)Q5`#ee`gXL3jELNk@nz +OI)@9b6mKnLj9UO;^{8{f>%a@@4`AzA%A#FF`4*x0Mhf5Yt-wyWYkEb*q+VmTrw*4i$#9^O)V~75HZ7 +=;3`k&uULsX=3|IbcV!zisb-~PwXhqM1<898k)A?RgbjD~RpK|q@(5Z|Orlc(*iy)@veB(;g74U=qQc +!OXY6yMO{hDJ9`w29CSLT!+AlOP);+NAL&!IxpTEb`+R3A(}14a{u9WP@Ux1lu6^@&k%&D14LR8#vie +*>VvQT`s~<8=BmZ*ai#V#zP76#}Q$AgEAW`+~DvAr#4Bn3BfhU4GnK%YJ(w53z;rIP~?WdHgUM2=nYP +9Qe+dQnFun+&wj(7!MLaH6c}-+0lq6iMM(OMJCLnxY7b!1L_2&e>7n*jy +3ygo5Xp)w#U9pUaEPj4;O`ZB*+8rzN-VfoVX$NFmwfJv?C7AAE60jIka>N9GhRkbNxt~}nOdQ_`4DmQqQplt)5r|sQXXe +B?w}v$%jIT^!G4}XM9;YBs0KK{HuC*p-NPK8&S#c0kL%-O6m&!ws;P*YN6wyqX7OOuyFx|WVuK2aqPv7^Yc;elt3a?Ep4(zfjKFq7?Q-ZVKLgODq(vR +ryIm;C$=EUy6cUwH?XR{;9*9WdaLA757z#L*P&a-1~o`kI-@8kWY%oG>e+X5}Mv5R|88`LJf$lUuOr@ +;lxdw8*gC|81`roeZewzEW?-G`^BS)pZpNbQ|x*7dp+6QVe~qz_T|V(oT?z +1aT)%70kw`s}{6ujy1R#(NgT7W_YD0iknA$MeCPFqewJhj# +_$5C;e-v*Ru)IeAF`Ep3M+F*gLVCjh9wD3T?Fz_psSw{F$qQ2PFZhwZ214M4AAmnmv;p%3x{SLF7cTIK0F>wr@tR5sxCnXyTELOnhFsvc!N4h?m-#I}5)1I7LO=MSa_s9LPO|%OB#cooK0X +eyzATj-SSFqMZNY{#EH;%!m^cV5p$X!o73>IU0vCeDCujr>`Kxhh)1-LfXLk2CsBf|5PSVVBl-?Gky*P2(N +Mfd +@eB7Yv37?*17h79)d$r)brom2OuW>9nX*Ora6kyH7Q`q`Yo#>my;42nChyla{iM@@L@tHIxoX+2iYiT%uRXVL>NVGJsRTjs&fT{qiU*X)o-N>^OA +|Kei8}PHl>5z5CTXsZqu64>R;Ekh7KOG9PKHkrWCau_L-|AFb7#4XVViEB|r1_!LEQhVy7-{sH52Y^b +p$+ZB$9a3M@%tqCQZ`XOdw%@=ZRfqVjhp7h|l<`dB>gEW +ga+#m0OJ?iNbCf%U&BT8D~uYNO=$UPKH@Td8CQZRWE%`#L(?9)j`1r;!$86ZlwNs>(hu0X$NL@hE41(!;HfiECu0I8DK1b~8C&Ij +|M7hXlo27XDQMawXo1W+s6P{=~e5LxC7l-hzdfGK=KW*Z{f;0v-As)AEMFO&WjUqb=#b>II9UjpveL= +Jz6FG~=?>VUuD3z)W^iB1o{mO2})n&`rPuK5ZN=XRk?;>?;KXyd=569n+|U8nX#C+Hiu=UCSSA5aO%A +0Y>1Vn=srE5uhD^x0T&ns#Ex?FV_LZ+zFfv>}T=)7S7uKhg*2>T>1bNf9eCz>!f@>7wG-L +027uK0Gf{Mq9=_j4}Rv@eRSNhPZlddoM3SpZus@g +&ttZVns{nL>4L6)ipcMUSHtnN^6Rp~{ry2m!x_}xW}_Jw|;PI+cbgq88Q8h7Vs?{qGPov(Z?UbDuk#7 +5o8ds9*81mYPln2*hUH(uMA*vgGLbWiPZ#rFcN61-|FGhsO;S(0MDmy9u#l4&dc#;R`@N1=KHEev +h>b}xBQXJfyXez?C6AUZ#(YJ^+eF`u06(#!TExZdj1+9<9K>pv@^K>e24p0xHaKexIR==e?~m +fK<{tcyu58{O;icbJeSXb>M2jP1_ud1<1SY{X`(E!ZVo;sc%FE{G^V3`l_9LE;rfDQ7+1?`@r488osG +3GS?6iGR(NPq2W~%zhI+^44%)$McZ~Abz%H|}Yk|fc>8KVX%kFMWKugYE04e% +-0~89yH<Ct)YdJ^1$;Xvo?eBf>@G5esRb7!+@8*Fp{f?jOmtFY_7Vc(8JR9)h4$M#YK%kn!n-sRf-;m89BlQ96pkJJCJZ%P +yY#{$I90j+lE`fqyLgAY@={rDbN +t>MKw*-kagrfXioq!qLtvD^QHr7|7@=W?BtaXFd}$oS$)X1V)kA6#k1@VT!Z+Fj{fPs(0!0ZZ`_jBH^ +QCdH_*9d{0lKJUY=cJ|l35&}VC)DWp4i0L1_P25-4Mj$%p~E(^$Ij-O#WKi0CEKvWYOl6aXE@zM@V2P)c7D7c;983&@gz;0A{(cq&j4|dm +?xD1Iml;U~Xr;PWN8%I;N`^85F{p2L`G|v9;ksX}cd4|r5@tq=8ga5>*?fbI4Xj`cYDk!e2cXpf4#M6 +OA0an#*@`&qhIutDaajQ$=vEbeJiz7oLI0Hp_{S~$!w0xLKj^>m0AIg_|H=bgo*(q~0Dm;Q{?h8w2C|V< +I_2naThkGwV+UrXRc*y7qqSyHbL|5&!#$y8#pTIt2YKT>V%-j%?`tf4sH72w7j3e3gm)`og1G36D+K|5AS$g)xIW#QJIkfxj +==TZVR8rPQeOy%h~LaE>(}OqXrA0L98UZ(UaNHdTn}d0pjHZ@Pw9BRm2gr79+t3+=3{R) +9*uh}(;=(NBWi1Q=S@Ubpd`i5*xfyADJ00;qmOw+c`5@pKGeHssV3DWW0F=OJwD)4Wljm&Tw=x=`YY> +RF6+Esb?%q=h(Lowv4SyCrsTe_mDNsXN!0~gz=d$Sg +xZ-197fG*rTvl5OA8i)_L7I(r`!G!MKrD$*AW8q0-=qiN-%SPw@Xv*#8UjU1l +0RyD*hK?5pJuqT`Z2~L?V5Ef6%PL_ubh5ZcfT2TDi>ZO&i|IfCnDbtM#rhe!Ga+hJl&w^Vzz*b0Sg7pHiQ>z1zZMnfolU31|}8@i(+2>fAVjbCqj4Kr)tzVcQ#&&nKn +KuiTeMTd1Czk=E;A}Jo)<%@Sm9{drZBV(rv2hmiAW&BpZx7cTZ&d6w2n}SEm&>2YwY`JueVP``AZAPk +ZxK$>x$|=OGjAi|mD`o;zTQ)a{^EEf4qOeu>xf`#ws8B0ANh3g36TJljpTUZKlv&&&41e>S4zZ!ddhw +w+65oCjEr638Z1jpl^d*&bAGFUi`h#}dpFO^I1FML7BDGF^Nk%yxHIxv|uR_nvTdP}qD_)1z8L`jn`e +=x+&y>u>$VRfoJ=aq@g%k@|Lf+@B{sLUHOsPltnCmHj7@2tshj)=>FGJ!;f`Yn~MAYZbywMC{GO4sl!M>;y;cjzD +~G?oslQTph-mLe4wH>cM;tt3!8oAG8|mCYJ0Bn;y6EG|a8Vd3|4>$FWcZwIsAVl#`ug`(TOUq$XS+6y +HuVmN+`@h~;#0I%|b1bwwL>%D#o;ZvPNhnoBz>D|FfZy04+E2qkQb)4|9igwUVxeF1LXBc>V~TN6HlIFb?n&}+20Toj*gz7eJoMCS?cZq2g!r^$N&nHqa%gYmaa#>k~M*=I4wL}KwQ7~@m +1FO?^P`etxZ&>kA-Oy!wU_OqHcdXw-M3cDczJ^k85Wesxw&d9a5sYP^5*<^yeDG +QFL?fsChdQT&woQ=+uGDu21HzBv_#f#XO>6#m`oEV$zg?R6+TQ--TlDTj>%-}AwMvGGXTpVPu{5+)fGhrhBd(sVH+uvcInLl ++Z(2{$RZN$E{QY%*#I^hfvx!(Xw7uj3-b5-|bDUh)EvWN~^d!F^(}2LSG~SK?XvGCQbb`IjUXR|yyrL +w;dfkjdhN0av8ZmlGylrWe6W2!uoz+XC1e!1y4t#h((5JTU~GF&P58dZ(GKV+oc#i7IN|sQ2z +G7Hmn+w1R~XJa+?B(;soe4vM@ZlcdzsR;(Yw?0jVr&bt~KHH;iNpHCX7K=fz#wBab+5 +wwEhBea|#r!>aVCT@_It~x`g|K!0hQo}#?3}|zK(it?HME;wxO>F2UWf +yv^ZZ6TV%kt-MZRwMhbPld@DQ@2jWv@*CH?I&-P}sCA($dYA+`|U(Xlzft;~4abm0-G0F?;Q+qZ~a^( +yjq*dJG7+=UBpNqAM;-^?bFLoKMWB&T^>mqor<%XIj+2wIHExTvHp+Pg)_#FtG+OZ(dn%zcKk9*@tsH +AChy{XK({dD}6>1tCGhLg`>UX(E_f|s29Y_YeM*DE)Qc?Tf?3Y{`e#gC%z1P +F}CX%xVIM9}PmsP`aLJ%~#xAZD4|n#OxNr4MkuLmb=2rXb68lP6T}fik$Ss!KTbU`pa%GE`^rW=N((R +gU5aqCly}So-jmEfrOEENUYkM$TUp!iird8no-<&z1Ofw_VJY)TrASyy7P{1>$o{Stu;Q?83ta~=?d9 +&$mZvRziPuCtzd?ZiGexWW~C?^RjizLl3Rg^AJ~}|3MB5fT}{>Jn^>itZ;^fm%^u>3{3_zuDm<&sfO0 +U2Ct(V^6X7*wENNZ=i%;u-+BB8W%;O$amDvit*$5AZh@fFj7ZjQY&uMS%kWo-w8obOTD&ObSePrhSo; +SA#LFBPX)RyiI=lyt3IX>DQ_fAi(pvX5=Ug=jw+Ils=mFZPXrza+DbV-wZ>`d_rHt%i%Ph@evH%k +e{c{0{g0Cf^%bQ7-y(7e^oPWTiI;3`K*aayg~s0y8yu1E(JT+$dQ{1=o)z~x@Ckq}UxT;dYZD?I{1U(pR<0EDmDMYvozd!_kB*aks12(w +AZC8Dx$n^;05c(h@#<-!@Z97%!;N54Iy)f=%iAoLXWP5pvTXT|&O1OvJFcxCir)g|zD_8TwWQX$@wxfe-oFIfw?F8HG+T +|G#!6y&W@nRTmN8b|l1WbTt~Ph!CupZOE^?i_6am|f-x1=bIK2WAFeKl7qGZ}WHAKa-yXm`;RB5h +Id6b{%Mld*j)>L7;kj?2T0lIK51w`F5D4E~@bu#3syyPzaM(ZVFwj?LFGazVcY5@h4|Bc0_zx1k=+_f +D7cHa&7;Bt5&Ta-JVYIlQQ*!VxNSHTGyvj{upP93EyA&s^D#oF<_5Ib>v@7{=+nt~8q59^>cQ?h4Lfnbyv#UbeB_TKr|!9K2=Sx=3+)X<9z{1~($y4qipZ$!cs~u0R|~8D?n`UcN;stC5vlZR`H0-yV_ +vco<3);`J`NH&JZzRE(z8Hh>&ffGXa;sf@Pv|>!R!*7p8?wq7FGeZYaJ)Lta&Nsi1PM`eUdsP!@0P%6 +=oJ1gls&P_P{Wx#i&U<;-q0 +nt4Fv$)o5xlD8!sgOQCXue^mZWH_x#Oi@tk3UCx=qx0v)0I2svBZRex1A+Ec5udfc8kBRoW$J~5^igG +@6qXbhefp~eM$PF{DryxFS9C40vY3;36fhiXP&GP;6eA4GqM8a}P&zJR;Z(&HhHP{sfX2?9HOn|0+d` +UB&Qf@l}*wm&PWyl!0UFcItNt{>M{1BealcZ!Sd)mr*hRRO8;8UpAg~H!)+{e<=5L05MhlA11_*iXQL +z~eiFxJRgAydC&wkAJvUeqPMrJf*@QE;^vR(Uc$!!uaOi`iKpQf><%x)asAKi9W^nOJO+yiwxK>x?Y< +Z|}JI>|(hEIG=yDtmB8n`zLt)mk0ac*k`wT9sk`4tKm&?UgEU-6VAT$WCH<)qsx-Nq_$x%M|89(G$7< ++c-cCXgbNuWbOAyZf9=VR7skNp;z7pa#RCo_%Sj}>n89Tyy{xz@ao+Qt(o2VdpPB*>t?itG40F+viZRg5BxrsTLSo{xkI+$nO~>rmYe1$@x3@_EE~zPwfE$cIN>VWuM)D9+U2yJS*>>RC +aFvhv%mAV$`|5acvtq&=(Q$6m6M; +G^eqQ0BE;yS@CN|yEg7}Q{m^LE2U)+R*3Pb+e@(=|*!$Pa;sR$81~@32rkXMBEoGSlXz7DdsTn;rb2J8>S=Kb{90A=Qy*|$HXB$n7+bQcHCQXp+d3pYh{}+sbPr||X^0(IfM^^TJQO`zpm+6p>BdRR*h +x%7w&@LYxJ4;9OZAtp6M;|fhHX7Wknj|nh&Ky;;E~A=FlwLc1gRxIcR%jyz5$k?e=uD$Kr^KYb&h|>N +@ITr-+{Gc8?NXNFk?P1>NTL3U3^{qsI}$W?4}8DIFDe)Re0%ufwEra;)pBJX^b`NxafgMTSj$b +q_4$UZhls8Ou5HWP~@-eSddm{87a5n95I1fS@{Dh%6^=aFL)xUt% +&qMzOSpV0D{S&r7kNekP4Nyufq=WG#*BuB$An&kjA^7rdvUp>GoTLDNL(u*utO4heWAqYL1_Nc;CW9A0FVMjN#B{P;DR~3&D?gu17o# +GIm&kd9FWLK9w4uQ<%;Jp(h$oXJI-Q}vg|+^24U@lv_2X~DdRMUJr#ILBj(VblC$jU5fP#bmyso^d(R +VTW{kkHhTeFI5U_LLqzfNyr6#7n$E^f}nQ#l``WoxnWbK4lrKZ;QswkJpu*wd#Pg}P`=Ji# +(5%9CS7|x-Qy^+D2;Km+Vvh%}RDk-bNq&XaikkQ+ipby#yQ;Q?}z#to_xRD_gW +{?#eKdV&w7!~xAi%6R}=!P9u&e>Ig!{9*-{o)w}}_hId$FA4S8E%$E-SHeA%cWES#U{bh?_cnd}=B>- +9*a?z0Yw@CkdK9*Hrs)vA_>(7pM}BxASvaC90cU}E@&z#+z8`l|1BKAPO;uzgU}s!D9ehQS&eeFLy5NnM$KKv-juiijMGL7%k6d;p$`2(b(N2 +B#jeKQFYtWja<_eA1eX}~O(IXq)SZm2G6z*b34THio#9Sf$X9f;I|B1C&1mN0TNBQ@w}=VXN_I@Q^-c +-ei^azKbK%l-PneUwcY9`9SpzYy&5?k}apY~&=!+J1ac!HKjo0k!V4u!+APAct~$?OGrb;#|R=N5eFK9YZ5`OhojMhD&iA(RG^8kCWx!1JQ$GJ +YPHKZaQ!mI5t+{9OsATiVyNi)@tRbZs+Y}inGjZ^<7f4$7y|GB%Ev2p#ds`2%)+uj|zJokbo$5XTm9O +mY<)KFlBgp!kNQ4H~sLj +e{P{J;7tbxZIE8U~QN;^!U#{9P*)ZuVWeZ-UFA(!dw(LOzavFWxT}}L|@W;z}9fwQ74scxnXYd1>H_6UtH_p+qaQ_GcrApwMYoG!o*qhi9VZ8i5skuKltO +0Z<-^0>K++7#C+9&f8;T3OPQnQdHfD37YG3nOZ=IxKhk2Xy<=KcMmT*MH2(gyq%cZ5jh7U +`z||G(a=2gfe{+@8dVRvp$N~9Yd^r_)j{oU*DbEZb~$sRc4WFbZrUvy#9L|Ic#zDGV`dQKwpP-qe6VW +|xg?A(ZZ8>ngnO~0VjQ)~%-0>WY&4-~xf{OLY-^xQjBSokGMlok3b>f5tHZXzxVc%`!QSJMPVwfG%!a +5^t@?U)D09tB41Kl2p-Fp8VU>wYw-8dfSp~$=latC}h=aXFn;mvB&OCPl%ljkMd4cI2rPRT@qOI7KE3 +DG=q|iOgl7uNiBNnjz#8|Et@3-6 +ZiXmz7H9y%j{$IMJ17+L#5DLtQ4R*e=jkj$THC1LjG3+-=*tK_QyaFRp@66^Dhld6CUO9!@x9u!1&Kb +gMquf2y^**E3h{4wE6_UkboZ8uV%qO<$cKgmn4->&j*oA3Y(H5^*8#{rzGttPGuk)4)rb9ijr- +5?rmSUYD{G{mTkt^5NiSdi7x(y89U)f5mMefcUR?M>Iu3D42BS_rUp|5BDcNe>c=0b-eyX +OrzA2pp7w0&UBnCj&LGe!mEpL4i}g6k~M`ap;kQJMA4U+#$RQ*s8^~tpesWx<3+>cIBz_5Qc!T^t$$R@s@(zE8>E{0=rnOP|tXy*Y9@A#xN&wTrZAmx&3f0g%mfK==U*j73RmKv*k>R=@ckVSU8#rBw&gyX%tjI4WB2}}Srh1*gjdy6`q +BVY)CK7KE(WQE8L{0dt_^MqxK$(=v`M4EbYptC3;ouXoIu^&+z0biY1+;_65KVFTE%OgX(-ztE(BLDF +?T_%CypeOKmg4<^p%ZnQ2L7I}kYbWU?h*6O>R4C%Y@{y`dRX;5Cx`o>Ip0fDs?WRhctd*oF*jEMxvFb +Ujklw9*rT*`@+PDs+iS;8$Yqt`N7{zm>?xK^z0JhQ7FRaBqD>Tb2hmxaX1cGBl(B>dYPC;)x#8U|Cj}s=_tHMYqQy-pJZe8nb)oT}H5bAka +P2wg=&eecQ~s5j{sGxs-6m;^Ur^^wM~_LPW|lqrlU3^hk;|&Bv5f1J-t;QMWi#O$?E=e;QkuJT$}?t`M71oBR|d&$3t@QtY%otUou330QC$Dkw0PaG57EM` +tkPaL&|j?}y%9?1Sob$j-h2eDc?>}WoaSae5B!bqmsg$c7O=9uxJi^1{!%n*l!6FX%$7-nT3(An +!IOHr)}EA=_`L4g<z#CU@;&hPLeQ1_I +`-U$hTT-*J>{r=g5%!)P9Z|1ZYS<#Bf!2o6S4=*BWl-bqzIyNj`I7Afy2+Sdm=4sdq#8vo${f#@f;2I +?_~gT6F#?EJ2%mb@Ut6}d(HkmW{PyX~X^)W0xl0;4xoikJ6r|+Z) +a=a=1I;$At}AifBp&Yk#b4g8i9}{JEuRNp$|)rL_GquN(R!v0KYS5B%p61u!Q@@ZUL+!9wLmaDut<^At+mB;)94pxglic7LfammmA&+0oB^j#UxKjm@1M*&dH5}*1~M6%Fet$IZPK +HDJOdNq!D#QtQYIF@Gmqr`sr6Ocdhx!-rSX;uja_)uyyhb34%1V3g{KMaJk6uFu|^SQz7mZGD;Cb^_1 +?g<6%vQ^6go%W9#$S$vB_r;t-zsq(1{LOrnIej@Pc7Gi3Sqv}mcJN}j`KSc`&kR46IsFVTK);VKgic@ +T{HhE3ea$EsVQL2_mZ(lAL|eK-`ha!o+m$Ow5#JwYOcaA!E#Xvd#n9>^6BtlRr!{NM?`D=6upH}Fiej +czv~&0S42N*FVq+_lo^X7qp114B?;Zc_MJCfAF#lNRN$fq4ftW~`sm~JZhk{G)_eHcV_P(&%d9nhv5lI*1bgIhXZu?j%&SF4{g +x)Yi*P*TR5Gp&4Z)Do649tU*T(7wSDeLjPT@knA1!8ca46+W^NBov=IlY}PvU(%d4!KGtl4`eFcU7Df +y48#3nj4o@atu+e`wTBY9r%d0f3L<*`<58MiaUY5KsiglUX~x<_xoD`)xw`NOTn~avCWOATl`$A$Gk% +2!EA2(z{<5$4(`^(z`d}-PfYYv)Fa%1TP07mjSJgz9hP*KsK$B_p@$1Ei4H&3M&;O1ICqLu#NY#Sh1G +%;*!*PtqCV;?EyY3vendts-}eIHuP&y*+WFm~gJ;t}t^PEj4DYTGGn7xG#vjw?LvgQ-$Mnzv+0Xm_(I +Co6^Vk0I`SiKc;W|d5ZTzOgBX>wO;b!2JnNQ|CD&sbO_NMb)!>LC{o2Vh5NdtP{C;Q(}lcKw`X&N7}tpT5;GtBd)GW$V~sIuw88FO3Xi*37SX~wx!6T; +hG(pIT8*E#XaJWam8>fs{`7#K@0)=p}^WJkIhx=sZDJmi1ms3IQo>dO5nboln9=lU8Ah(@$VAJcWcXcXzMv +R(2S1uLFEpe`7e>pnHxJ#BX?2c?lOLZ#T +6No;fw7T}{QE(WIpNftAy$)20iI4P)(r0r@`S0&cHj1e$ZGeFl#YUPOU*WBgoguDyEF35G$iX{+#KXxr5OV~siDSt9J58Z^JAF>eiwKi^T(%bs-%{qX4RAqfgZmG4!FUW^j6?P +;ZoI-#6_mm7T9OMyb +OdM2PR7m16U`OYzA_dLdw;C&(l8|wxv$UoJdr$q;o&WbRp)4T54X+%YEL#+DemeKZf&xSwbT4eNKRpC +Y1Ij-+{Lm!GZ;fOvr-w2A?5sK{fNb~s&c0@<1!TyEa?o +)e3_nAjxO2TzVXJ(?ier$22ngK`3e3v>b0iVH!t*C>D2c!;UA4($l-tKgwJ}ce>(UF6yZ2deW^{eSJH +GCExU{XBZyZikR_A)m0q1?i&q(Y)hz|8E+f9)xs)y>0HQI(mooquB4)|f3SR+ju+S&S@-zPW0*H)R;? +C&nyDgAkp$3dX6R#2~uY7HwjN@e4|CC@0RS5E>P~q1`CTj6r1Hge>2wxkSfI6m_1(i#XJ6ZD95_EC0C +(%+21Z|_LR&f0H4tD6h=!dIu#)pGlH&N&D;j(+zsFB8%9~$-aeLwV3Q}tCE{BPg}?MC091qNccxR9%0`SE6*#4WEBq02M%;Z!r6cTpRwxN=c)hq6X4iO$S#t?-L~6Wt9V(k?IuKh^QH_I-A-rt$VoTHQyt*}T}~*QR%uTUL>4j%TSTS3;tWSm8rHn)RNP(62VFUP8Z +)YyjCZxAVKgbo-ga*dkqsf`8%Og65x&5%zR%W%UotqO8cJnb6@nMY7v%HVf^y)&|(ac8vagE(a +x%%)rBid;H3O7F#_qJFly`8Ux-%$6_DFseq05PjUYc=an2(s9(j)mS2{$;%mJ=JdEU_U(Pbl5w*-4JC +c9ZtuTzg?=m(m(-08S?~~ylS}aZXGdO3;~Iw(~8(fh;!SdnSR*#hGnv9cTd$h6>)El +njw{?wOOGa-xJb^D>yZ7_rN!Cwe=DS-Zv08Qz9r2$`m%)N-wC(c#p(cyln4{{E<|y~j=Xp-0zt1D!`)jC5~}g{rPu4*!antBk`@lEPe))g0oyWUukoYS +#=lbu{Li33|2|v3I_1}N`G)>BVhX?3VzA&Y-`SA94E|S1Z$JY$d#%gJB0m5SzyaacRXf91?JJ62;+qJ +*I5`P=0YQc?U|JN?TWWB$2qy67D{8r@9_m+{iQ*SjmP{si`SK&`^_4^bR`e@{YH^3Ya+NXSrF7zD`|V +pjatvMmgkOpbpe4x`Z|$qz=rRL+4{U7T&^oq{_q` +aX8;A3WCO|bt!%d*e)`?li8nf$A0`Q=Q0K+7_dzww0m0AHLi?p&YWY0SAr}N^LYW?H69$gy{VLH-G%#hRZp7EI*ag0Zt +c3gWw+|+~>#XzvL3R%ydKSW@iviZE@1nVH4<;z~whWR@0>%G4k`9wsjbu{h5DRg9zj~9t`9`}60U{YKiJBLnZ%wRCWcC*KK4io)S>!xx4q*>Wgu2JC6uqH6hgPB^epEWS>CdaiY3*m$tj^k +X1VFS_ID>3FJzmU2anzd+pPS#}vDXwko%#b8GLz_Cqdj+N@jR16u2OV(M6)d#i->ALn2vUHG|Fiv0vP +P7|b6b*d(rkedEsCI=U_B!(^gVL!`#?rnRjLLYYS(iWc)rCqi2^*BTLMY**NDj53<8U +3wqpZFkx-CQ1N+x;y;^P6-2M4j)C|1EZwO{>HU6R$6;L&Dd$)4j54-@a5RdX;IQ-cnoXFR_!7FTWeMU +;xJ!JppLLgs-a6^vhM2EWiNRpzy^7h7d~_F9n+8SJAd*Gc2(ng2|S>rxCj78iHA(by>K85szOO!4@87 +FCt~g;*rDAS4z-pe^2(>%@e&sg-En)Y>i*rbCKU}i;==b(ICIw!z%p~?4%kuek}IR_x+Ab+>)h`L5#j +@iMO~Gz>7BOORmjQ%J6M>3-MFiXj*^7{Gg97&igUumsAn*kSSgwuv+`%R?uQw`DkquWGHQtgmJ=7`Z-t6=eMR~B=#*c +Uf)5w%S&h~cWgUCgvEmwH%wby9ksp0g4H)*0)_jrUbHwy6r<58|JOA)}*!1z2gTbSD>ya)BE>>p?r3& +5|ZI^Zgv+1EDj-3KPC%Cq8%Yb2eJ9ffY?c8gz~TQLZ3pZKh^l`U}_KpAu90&IWT>r9@Lb^6>sXdBa?Z +suC)IYEVv!U$&$c*KUU_gmDvH=CG_duR3ZqRdPo?!rhHq_CAKJP}+l>}5UBbjDzVskoT;44qOtZ&+-6 +p3=I^T(`R&?sC10&nq+1`xVrjhklxv89Pl!+4Y!=&{>hEPV@n$n+twD)@7~H4)rUhL%)K$q~9s^ejf$ +(qUzCHL*AgXo*&Tfa! +4S_N<{uH!s@tK0n5By36RDjk$d)lmiY(FbLj5cTx$xlZWqtsxaaEv0-)FowKFuY&n&y)ohGU~CR%(Po +S_$sM%|X*H+V|C=rMM1f=OuWN5I7LL0Pn^3Yuq_YG4?(N6IxP_8|x#RxE;mVxlG61VQNvanGFu>Z&-+ +5ox3%e_<^wU_GJL)N0`5(=0R6rN}tYDb*jhI*?mAw;<+GJJWd1k?DCen +|kJOctj8@VUp*A4emydx%urvqlwuAf`n@!n_ts|&ZOEII+LRFq(S7G3?Vu#V%&r3J47Vz=7jAq$w4^} +m(%&wX3!;l4>b^K(>e2=uv7Nra%ws8ER|&EgLclmPAAO;H6UYj#!|4{J$kje>+D +1%f0@TF#U~49m6-RsgT~iwa6_~$|PI3y|R%A-D2(a6?zZZ8T>yH^(ke-c5M!17x}=EEq%N4ot3t1)k< +=sFeI}Rs%VqQ4$`fS8vmG2{u9cC?yX7KuCGm?TMN?4+{mrwxvOO(TeH&2oz_Fsd--vDcNd?GcBM;X|4 +{3hsC1Jv*~BO5UCt!@5B!(%RZ_T9rpsSZCgtByrXPkM{**HPX|!JaAzD{HQ-A)eX#LZx0lvSS@2_U1M +8AsI`HzTQ-6HmFf{0&S>B!ACHKXx7IqL&`NRnxUorZ{0i;Aw&g_K{h(qCJ+sUf34uCMql$2}~FGy-^w +dSsJxNMcXSNM0}Ry>-7x*Xqoh4Q6?jXpZbeM0Wm`w8w={vI%WuW)mOk8_tmdNdi~4f=~r=zZ=H*;?L! +K9OYUq&B$gGo~VWsEIw(@&~MS4j<4q(I=+|_iAQV99KV2T7&ad4k(hqEa~|Ur4Q*;KR~u*QYWh)*i=a +H$JVL&tVr1p3sMHKAjF<4zxm_?FfiA)Qw?lfEF`>}%1{Z`D#`8##M?#h%C@^*H!a!7U8sb;HTurpW+U +x!P(xWJO7h?zNa&)U`}yUH65CF-4FP)^Uizz5HADR6s59YD=Ov +jW#`qnnGXVtY_^5*#c_bwzflRD9`>ItdCmbHf}~b(OtIQc$e2Jns3!}9J~|9;2}wI%#?D97U{MvP!iqa0#c +Uzv4)cw2aY{*Yy0|cP>f^5)1sH4&T;EU@2VAN@6jx|=IrIn>)4>Y`NzU8@aL&^3#F0k9ekN62=VDv)+ +WkcU~9?D!}5`72fpi8`m>Gy*h1y|f9Q1kQrTTsBst`!{JfwE`wlCpSx9p1c-J^U8Rcm`s|j&1lbv@-! +3Bt~<O@KwS;GN%pE-WriX|5*2YEJE_1sBf1rkF`DFv7O$S87eg_Dl^wk&&I+)1cEfE- +UJmAym`U-K`D3EooM_H{&n_~SMRFL{81)9e&-P14(kCWZSqn%Rks5D>KD5rL>Cn2{M0s2b*5Q*ETiIf +islmIVY3JoNU&;4-ZWzJ3Muz60vT|vFAcK_tY}(Vw3MsR_JhfOqyx}3_4%#^tAJO6YViEQJfcfTz2s4 +c|DaOzR(@(hl4t&5y9MS>L13g^Q30r*cKtI)Ig5yWjI<_3TF}($(pVs;OykDQ04_dK~msix5UuYjLfG +oK4f=BHU)r-4?iiN;j8?~V8o7iY|eM406Y8}ZF;^fnl&z`j9!Fb{&Sel=oHC+S9SkkBaXbG=dXFy4Bs +Zn>(Q$JP@3oJ7Sm+FwiCCPFyyFc-`G%8F-xuBaU^O)|~fp&>keZ +q=IwNrSU>z;KQlcsA%j-%|iGI7Tgo`(kru+JHtXcRooM^=11O^cm+(I)efi2F(~gg3ND80UZ-g&o=raK&t9yr7&&<55-4OiEBpkund-q+XdaQ+w!r-I_ia +-0F8D3so4QWgDET`3<*FBU_Y&FORUf-z%GQ~^lASMu*T1n{*F^dL>d%fQ|1*dDWyo1AUcyLsXA*R4#7f}Z<>Oan`HjK_8@F0FC5WwG01mcUa5~TL+kk`-pA95H}n-&~qf@#zy|99bjD +hvv$XxV*o-AsiNAbepG2wN25^D_4{-Zbo5(&zff0N$4*8e&MU2JKXXO-N0+~AyZql={&w}i_m +}_oD>wY$GK8npQ44qQP9^>E8x~hUA4O@99!ZdP +(3B86V792Strp05%WNYR^T2ej6~b>AybeH63bh5R?$1IU}ty17iH)bI%wQ#j9uXN@{r?&@-wNPpCgJ{ +@A2+KH1Z-Hewka?KCchu&5G|L+R!zBMn}9lYs?Zwpo78f3qToWKB>!6wb&$4%jI44lGg`?1BEf&ld7N3^9V(Po-9rXa`>3xMk@5nA0H^-Yc +=KyNnCoJBK}ymxZzza==r!F9D5w~dp-Ah?u2L0!8GXQvVDCvu&dZqUSt6af9YV@>Y@PWRJjwHhW7ipB +-6z4e96GiIzLGM87mNV(T*#XBhq&crJ;Pd_fdGpfFqZhG4DPZh-lB+1+<->D?}=f7@;V6Z82$Vp}^;| +l-{8`+%yQDn8#ICC&iCTsfz(>z;p(r82{i+$^ACLR%oW2N{4cNMM)w(-JaudbZFV}#rndcu*|)EGoYm +MphxFu1VB&-Z!eu?L##d;FY8KjatB`U}fEu=;309~zDuwPmmb`QIQQf(ToR2-QQj_JOLq! +{`gh8ch8<7X;dCab7UlIOE1Hd++^sYaODQoDzBz^PS<@w*gEx$GY-Ta(Z_{)vIg4>r3zu0?!k89+LT= +b_y($SVD*h(Da9)HtYDLzED5F91$t +B!17f^4|}A-j0Vh3^3+;Fo`x?01!gpbFZBUPDxhco`23bk( +Y&h8U|gcnW#O#4f-aY+YlhzEmI0%FBXaOVg2bzl1<(7)Pf96GKd`eNXG +$2knS2TR%)irp&fm2A81Qk@K7 +56^}t#o%tr(InoAtjSTeRo>9+DSKDyY+M$%@1HRPXNx3VP?D*Jr9)NZ)rIKOrvSzMDqXE_s^q^K%=u; +E9eAtQi2@_%-9hh8yj;SgNt|B?F?^x8dQC5glJIxX&rDx=<3nck=-HB%1eC9Ssjy}M*r$$p)$wqQZ3C +*EDbk(rnW=|&%~7FS@OAkB{Y58nKN5X7YICha#v*{k%v +-!<+^*2cuT8Ry37i(Zm4`wR$_W-`VggQ3s#?%Wl&0$}x}=~yC)#;Y4BI!CmsCAu<4s2f8g|~J&va5V#rsPru7`u?yXwvC +08(aOHSQkFv(e_c-Enuni~h-4&$8_I>J`6>O`ZPF8izD-v#so(8z=q4UBBVL$9vn}-}Y$#j%3EBSH*1 +Vlp(wYD>SvGhl6NCgUu^w4{_GjdyP=2bwT~yyJ!szHjQX(i(S_BcMWJ_a&IDIwgNhd?+I#T`$O*G4!J +MQ$<}TBD>R_Cp0oho+nsk)MU>iF1lHFnWa~D=>AeSfZ(7>`DBi|n;E&Op-P94^^T_C)mEOV^c=vl`c5 +M1<+h%0%krH&23ZS2eRe>FuNUD#F%}ScvAAqM`_J8R1b&<_CD=!5z47FU-lxg1oXcq_Lp2 ++Nc)YZr%z-C@J(4up$Bx=~y7>+Ot{0@0GaHu+;`sE8hV@P9c> +mJeRL{NhIRP*o8Ztb{3(Yz|&|)KIw75&kT=Nn +?MAcshP;EPGOuG{D)rM2M%)E_qlTpB#6Db#q$wnDU3#{gA9M^-8B(z7SNvRgi$iGi0Cuwtg8k)w?~3L +u`x9~h)Sa`SlTLL0w3XHq#D&(N79LR4K!b&!hPZONAe!Bj9Uzlzbpz$|>d;6)fHeL1w7_94HnX3C(asjXC +6r;^TQ?3jebG9Ug$~;rP*R%KiN&nu#K+$I*DPa3dUKUB1Jy!ji|C*p|E^4a6IyPf6q(RK}S)gk>QwpNxE +2;(QShBbQ!f3HA6dP&b++(E_yTspd3s +?$SD$mnQ@gCUUaTmYv|S4i;`%h6fgk=8(unWQ#rgs +t{VZ(U|7t$y|g{MSGYq(Au_{ZpXc-TD3vP;YVoU!@^*88Ip!bLZQ?0Bhj$=#ra +s{BVF3p^fl_Hw`By^g$EKg9*ks{0?MNOwH<^o^>Fqu{j~)wj0wao-fvQ_Rh@1WC&H@L18rLmG+ZEsye ++ihajZBU>Of{{Car0PeI2nfbz7c!UUtVq7z?lp#g%5gMNBXDW4XY| +mY2G7Jgu5{kXg8Y|D;<53BxYwhv5IwdfS>&d%O%g{$(dC!Aj%QwrTLT4Xu{q8{Bt74kQ62L|SN8jOVb +fSPCdzp`69x|xo9f7X8Y&1Zh(!{{WWQjJfG?-lj2&NR +oVz&13U8Pa82JS%;BR0(Ej%{~Ke_Xrjoi-lBb#LpoxPQEISbFngVlWakLk(p!5a93RbP4usiv7M<-LW}YcoFHLrSGOD +A6QjUu7Wyub4QuVj{KkqFCX%SApy>L=PdsRm(aGSCOGqeF=N%t>440)*~-R>e@JTk~^a|LpJuzs5ah4 +?-Px*4i{-aAdrYwrSJaDqgYrzGo@k*@;pBIyp*Dg#PF#TP*8O}Srz-ZIsHk;Zn*z5A&O;T9HlHBbomE95qrnfkCKr81hxOg?mxly*CYHh++Oi;g*z;m~O%BHu#Ed;tc5LJzFcTuaLiDB%EyB@-)8J29pgY*PtBPRVXO*KLNeX@rJ>6Dg@sKp2 +A;ESFP6rZ>rMUjP45HF}@A^rt8kTRnvOt6}qv#D!BeZ_pY*(+-jKH$>Ij1@`nsr6STf#MrW=LsXlST(JI^rh8p6=^e^_pRpd|l9&=SL>!Km)GH>jv9CG4b_s(OO`bZ%mz@B$_Gy2r`$fb^kV8qV +cWqeda`?R{3d9r>8c|CBxq?%36e8Z+*Cn)#5^l +#y5-0wa~v{%V%H1&F}2Kd*|$J@9Fu~j8{w6mR3H5;&<4Jbw7)$l;$LC+dcXsV-V3V%Ht_xxcK@9N0{a +m^sndK&Jqc=wi&P$7hPP^7Y!$oEMnAr*M3!vRd|wy{P*z%&d;C4`G)$1VLp}0GR2^V5Ihq;%JSdzgcL +$^4uIroQ;As%A4p2AYTz;dN4X)^ +v4$=dxATu7ogxGs1ic(8VW3@ME3h^x`<8Vi)NB;%&(EJN3s%>-S0J*@N_dOl)Z@Rfe8q+F+>oUUeZJf +V5X{5eQIjB=xx7q;K~B=A=h&RH(hBw;!YG3B;*rR>cDFCaxM|X_Hz+EfS6Msw*E#d@NsLid+!w$iACuSzDJ#ineT_Gk%F8|xuZN3{fi1Y5RBqP6V_XUJ^b*Des{jzr(--e~*J$?_v?HZV9o0wY}2eB)2Bp;5F=!W+(xt(&G)!T(e$aG63Y}ZVEF`!^}V +zP-??MDgIi1GrW5%YlyBDc-zygazm_f( +-#Y(oR<8Q~z<=`q--M^uc)i>@h8BJK5T5#YE!tlLwio}%1vKL)87wRI7|-{tXEgr^<$(H42W$E!S^1} +ml^1+Gel@z9T?_c`$batuKXC!z&vZrxR7NWIM7q#I(sgt^-P=_3xv~mvYtRvLf&3>><#_3eY%A{gI1)x1WYt+iZKy49sdin3++Q$V#qcQ0OMS +qlN#VshLItecq77*7csWfq;>2Rlf&vP}v<9R=Q^=bNqo=Ayx8FqP2=;Bj(b+}&|Svpq^(Vv6c3JCrZT +@Xg-#&t8(xfE3N&HxFNrdx!^w?e_>S6RZ>{HgCzPR3 +Ldz%@*Nt|vu@P*~>xwJ>i(Xzq#8iHf&J6dmVAl~n9W4P6~W&2&!^XTg}Iy8GBj(E{?z&DI5 +Fmev6{Ft6*i&V_9ycD%ASra9P%J*%nntJX`SGG`+Y<(yCCdHhNnDs=Pi#iq)*7+WL#Tvf5=|W$B$si-JG +BY1#);FsC@m^mWZaIfUsMD$PAD@v((e5h~u|Dbm{KoxUbN|N=dR5M=%zWw?# +(UatRsrg23V1_a5(eb?h#Xo5$t>J& +;4$MQ6#4ObafDM$Ie)Th}*&lxD%a`c^ +lcf4&uAI75sqd;%yAbZ_WhIc +BuKh3|5p>E53~QF}`swz0&OmIlO@5sL6Vwe**sB2vGh00DmGZaim}pJ^NZAP}(CD9jR`fK6)iccsnmS +IFOM48IpLbX%;x+vdY;=))^SFTSK*3USg4bEQ=(_9gAI>@9O2ukG|p7oBhG8Ssy&){jzf`!>K&YtuiP +xnoT}0A&4ntXP;m2DEVS+fl$3wJpcn-GbEz**z`wx*T!2*YBihwP112{XiKAP~kH2s!c2Hm>V)yS8Ay +scb8L+R4`;jf5_9pZNn+Y_^j)pqy(w4mAgrJV!9?v&^?9%JAepcB|guk)YPrr_PeVXi;1XNWx+v?XM4qdg)0<6tMZ%M5QgJ6jN`j@K2&yFnU +#|#Ib|(w*Un;B#9VTN*9%)r{3yy+$W*$c-lwR`%1zRw=&OJ#&nA8p7a&cP1f~fil<$x27q%%$`k&(#hXjtPKf(MU)DXnM{Y +3L%hI#taEHU^<4QOR(9DrV-F-8mCh1bnGiMyuU)z-tB<1ADjjE@$g=X{lCarXCc^y@Oc^6*9oca(<-M +0$NE=4V}66K45!LT_SW|ecA>a8C>(cqLi%}N2Dy4d?hJLPd@75y)(Kl}%4{N0%J$0qjRE+6QNI4+uLJ +5(>A085)UtCyW%;l6Q|%}PA`WaDq!l9KimqkVw^eqLez=>h}%yuy52V47bpZ6CvZ0)CK6GzGZo-LwxW +K90_C1AW`_&!Vy3Y$NaMLg*?t3B!Bks97&ZkonlnuXiSXzdS=_ud1;;fDFnFh)r;`VvJ**%=a^Pv(6L +ds7jq4ZA~!y*@5mTH^!Vr_&Nyky!JHQ;*96Ydfx)61U= +srQ37xk>4ND^_$(C2U3+3nbLz$=P(JaAyvtC(UmGYrox+T-1A%(Dg9j(Wq+cf@mp0u1h2lIDZZmR6(8 +Sn!5n_~_Sukp=g0!O1iHh6xVh2=S%FH}I-@0#Ju6&I{1hMk@NlDH|H|Lu2=2BP)__)hh(w840ddrBJ|$q8f{_*EAb+B${6fN +Ov3HOZFrB`{z*`~$=g2HKm=RnZF7-}w{eEe-96m1g2=|qw(i>Tv+v7ZK-SHY}*M1Qc;qcOLe$~=SFHW7#)#Yd9}}Fn~CND<}Zuf4k~ +H|MwSWph6C{Xld|t|j5jarOq9Wr^!FF7RnI$!^%RN~(85G2eQe|eWCQKCU`j2_6$(+3mpD!fCO(C; +9(!{wB{GN3s!op_rTUre;-d}Jw~?gkJ_x9j(XYhrp&wRc=mx2klR)U?kR+G~R3wx>KA%KhXpTNmkd$g +~S+&!90)%~flVtp+qxIv2U$m08Y}Y#7o$H+ikA>E(k?gzD_>90E%5*PYRe4V$r5`qZIK)K+*o1fzsU@ +ibJI#q2Y_)F5Pau*7^vaDjdp?H>^^BZOcj-hrs~e7KOfn)T +0Eq2k|8*cE|f1T`$VP|su&i)^P}1ytaTNh(l1!o{Krze8KTqE$I9$De_}l(akK9k@K%afB?I2BBJ|uh5cBwW{5~_9iJt2HDz#=jHfe +9)`)Eu$qQ(eBpZEd(kbB!k@mDHlE)+%O%tL?r$klk`^Lkoc{^+rb)zNzBvd8|}#*I^#*765!zrS7R_( +3Q9`)z=)MGN!7F6&w+O~1;9Wg=^nXm%7Aay)ATgWlZNtiu5Hj-F^|gni2kXe^j3;iPDkf1D5`bLJ$kA +zxMV_A!v$Ox(sYDCDVBng@!TR(?rpAVwM-p}_7wEbps-qPZ@#VzfJl7jw8^&+a)U-uym^4-!@L32mhY +32*mx2^cQN%s9pXc+}7l8gY?qbga~#2b5aQr#GuH1M)0Q**Xexeivk&bO-DR6NwP?+}nrjdnKu_R&`_S3hXbKiA2=Z +RRe#SfVtY*XW^6)~B4_fk;TwhPRY)WT{VJLi_h*uV~H8}x-&xvC|+3FIfZ``F1g!(2GvdY&VGak~9a7 +N=)mrhrV{RD_lY;O1j +a*xG-YBW1Yh(v3%JrQ=-sl&Pb10>`Z5%9qB#;C54h9GgOh`GzP)8N0j0cy@GczlR_$E^0{EUZi0eCY4 +o7(Z_Po)tt$a9c2WjJy0fjYKnNN_TBWv$M;t6iVko!FE;?!SBIbvSlbJ|!zIXjN88W3eF3qeAfG8s6E +)gj0bXwyzs;SGF;WW{plBCYX$6iDnXJ(I&On7rjoe2LQjgcb(F1GN`?gCBF6<`V{--Z>AYf|K}p|C;g ++BYcnC-O26OCfi{7N_v35%cjKZwi~Q(6^lx_m%5wi?!=Eb2pIbm6TXA=#xMZ;L!<9yc#MW_@61!b6wK +ZLD168|+Fdlra{zdLyMd3zzQ)cVnVv;R+h(~+VSF|;K!Rh8ONbKWVn^sq}B`ANHg-mt>img%{Z@pscZ +tyPpwO&JrZ|O{U7efv3t#ln>8xuzM?B>dNF=qEA+H2Jmy)o~V!{fWx@yfi(t+4%hRKLmA6cc=XJbWHE2^^2>>&uMx-8Rdz^sl3RA96v4vg-0QK)5uZ-ghSvC@LLzoPq!8ZpX +3ks3nt=8Fkj2MUh*sTS_2xn<}Tiy(e6e&^%@c+E=aMX6f%I`fhFowyviiT>wNaLbw@&Bapvfgy#`a&d +=nZ{rY~+a+q^#BN6BYO5>({7cY8qwV7i#v!SKsvRg1TR?zr4ik4l14b}Mj@>LDuys*qqeO#9;g6ms +g%#w#*i+aummjD@^8kLLiw~dK^UF-@({`oo%rHvp&H+qOf8JP$UGEi1n2FJz=8s1=yqR=$Dy|<#Ha^^ +9#v3#~ZlNT-=Y|=S0@XMzQFp)__3DEP27tE~IaKiTd +ZtbDi4Z|G-mf__@n3b0)Xo7fh7G}&!?(oHuAr?>SOPd48=BHI2*ZoYKCQj<)nt=%Ufx12DoLobqXBGE4llXv-H{JOkUp`eoIYovnG`s@=a!W +C-HK*&#|)Q7vXBI^82opTE=Fo;L5e(I{9IH1kuIldwPWd-|lYxoQo*YIpX(3mevu +!2Ehe>lr)$YAkyGMPK{7u^iw}MISWwdMUhk9$2I5ViCOi7$oM*a0S_;?NGP}Ho%RnA$FRKLZ)Ynak=1 +N+MF&Tg7y+kXo{2+)H*P`$~tOYp|^&EFUYPCTAo8YzCL<@XzaoTz5Wo{@F_1I&+A(>Rv3U>0v!Uquj7 ++x=X#S`_kwm!N_!%xN5p(LfNxr)Ismh4*KW3OJJw9Skl0XjyxNb?=|Yh9cz8529-Ub(2hGA&7PTF6Q^ +|NQ>MdtM#R3>kE%h)DE*u6#WIvz0K%e`Q#7}sEoQb@7QcZ*_(nKNmYvyv~RqkOcBiFm45Q^9R4bTsN4 +)a79ALj+*il*1juh_9#PG+;nO_WD^0vnAj&VEzkadSs${j27~vh|JwzYu+}z7E#%nWI#prE#G`T-gn(@FGzlV#Fb#ZnCtKFxiI9A~A)6Z|Y3L^9 +%&=i^Li4~`oIKr&jKfXlLs**F-U_fx{O#4I6Pmil6A-c^O;BVP&5T7wR+TPS$XuD*j-0zC){K9GQ2lF +71$Yn8FwtlN}O;>wsv3cf~{N$i)yiOk*)%L=%whfzjc;BABS>kqa}ir{fuP~g@&e#^dUm-k_vQNuB|A +h~#*c(R$pexU8yOHuo%RMm5A4MzX_%YPpP{cmy7{$?cW|Eu5;C*J~rZH@oz{hy)XUmoKdZ2Z~&KcwH` +?LXwxn1qD4X_R%@U)g+=Z2H4+v`v#l;WoyZ>}>^G5}n+pQlrnMBi6+oi8tWE_J-1Rp^x@vR3_X4ob?R +rA-8ye*n)@^Pf~o>qg$7I{8!Qu`*`abS8R<8(bil+Fxx-TU<-P-I3(G-Hqs3}HdnmeO(@#+B)p9O;m8TFh2M=DRvd91%)0wmGrR4hAVjr&5B +H8W_pM+2QTy7>IU#l|OLrjVxpJTPtljmy*7+V$Zf$Shl0e^thQwL7qZLoo#SnI(p~}unH +IF>|af$!9c)DPYA0K{qVw2>e?wDFbW?e6vNoe!a;O{q)LDBZUA +=@1hQjo{Qt?$3-GNlHzcQ(u+-GHXo><+T>BngtI7nYkWcbh?N$ger50{np22=0`Au&7eH~eK%6BOgR$ +f&;1Q+CNj`D3dt*pydaPlNt~rS=l=fvy%^~bb^G3vs(er4f#Of^cpCW?-r8^~a$${2&=ypo7 +fpx-e4G21Xt8(TVt%XkTe>QrbawnA%{_*rJ)OH{=97sb7 +rs2|A`9NV%KWOlECB>=UF5_n@zUVrEBG{@B8Fg +gQMo>6z8$Fw4=L}JosNJpW-+j@~&wyiB0Ha}!jg@r*lMBWTgH&z@&@mWUB7}D}HD$Y7o!JagaR*=LX) +OiALfHcOdQZ^WoS6Acpr^F6fLu$_^oShaJnP*?&%ld;iwe-G>{Pjib%JWAyM#lKAp7okv1t7< +3X1){d!jR!|0F7MY~#28`b}VMmT%hUZx@+gam>Cazd4t6N6Wd`D^~Sm)0SJ_?cVp#|3J_bc2mK11+W~(#+-IX82u9&3gA+JP(>O^pG(jLFMNkyEDa#_8)GYjIR2E`eAKoTvM{V9l6VH^_5|DJdK7FkBk3Lot^dS{Ev#E%Z_~+(Hu#On6}f-iYq +*{oO?P>RcsnS%*Q~cdk=P9RFmjWYT@Sa?ffexa{cxKN`7SV#?BOLz@1}jbR^W$2;1;A|o4M0p&5K?)M +1_NIin7)b*K>qr)zGxy`Pp!KryL<7KAcTzO_H!e;;v+*JbbcaF?xk^Z2r;J=&UiJwBz=-*S7Bq7p%**{h1%&x1R&gZ9fNdk`~teGD~U;m2nRhGh3Ixc9U +}0yRyGvJ@5tWoj`Un*EJ-kvM%d)XQL#s5)V<`eW%{k*|PlOS`Wn6y+pX%JndtC_KyWC*R@V64`-GrIi +_O_(Syw#I2OKg0pRbD0SqL3@u0S0brp-2ep}h&fwS59nD-{pk7Ym%bH +aL^Vhk#=>MY*NwK5`_+8;Kbnp61Pm4z*~utpn%LFsRSd6gKjU)1Tb~mZhp06=8Np +fxT8d|8#GIF;oWt7cX)nA}6Gb-xsGn-k7AGSdS>~6bzjqgIL1s!Ma^n=(!a0Fs_f+@pxpJGd`c^@ +a!KYvGNkA;RF;TV~OJPiz2y@Bc+|KVoOb)?|nC3e;9ol3C^r3*L#7|t_dTDQ??*&|PadFQyLpbz?+?s&<9rcgdVRDLI-vWGO5BFV~ddKQ#)u$O7~HoJ7*^inlJc`l(@O-_hRo>&j{ +~KNmp3&^&SCrqdw9Dt5?TnUZ2e21*j2>6d^xoT@2MWev6h%o2#uyYu5E>^i1YxL8g&d=;{8P+)&K9ggR*=``0Q4SJ9j`_2X-%3UCj|@_P|A!=9?1VquSZ)k|(RWR>&)U>Qx}f$?cDN +e|#?MBZUruV|d*E+H)(s(i43ku7Z +YelAe)Ni!bqI4+5{VVQ4keej*o#*F{#UMNY^lPNonM8K>u{eyPa*`?G>8`Pu=!FR)aI?*yQP63V-Uz| +PV3n8P)?7m8cq-(v5d)1%&aYRC7Im$1-IdHQ%ED{N^O%)OJ(q@+f%+nra3@#Rke2e|<^8Rk>GNy459U +h+gsw=>2|;t>9P<^?mT~x=K)5M_-niq{0?T9xbGVmJ_B}35Aw^Fep(ENu_b$w#n}No;hhHn7Sy+x)=> +L?tR{o&=_`Lxl@U7+QAkEj=4-eX1s9abv7*DF6$Pw-gNf*s8!c!)r3*C4MSga8|Sx4_M@V)ZX9|-A%a +a|GbcXnIep3!4{-MO#NjfMGFt=jkmuo8;tE1@_PZ1dez>&7R3Pj`&Y?{l}KE`Qw)*f!+;q&{m+*sPQqZhtPS<4KHHkQaJGg}7z#ZN{Hv`YR&mhi?U`|CwN@8}IhWFz%y$r$ESPslYfYk&!_0icS3I*;Y~-(1x^BCB#dx(c#uGVKp^z#hfSK!s?PdV_c{MF)6tcoBr$s<*pFM!T9kKV +t?bFpH;$xkSy6ZYMmCu*!a7Rt{U1&C$ImJ>EdK`|E?ctlUWb2J>>s?m`-7!X3dc~I`pF%L-%nKLxBqJ +H`Oh5x|9hADB(M7G9KXEUZ=pvK3?lt>rIkt;09i+wRW$$y>=Jak@;WoXWkAC}>F>!a7MqTRA6b0nBdH +&QA~B5v6n_kZ`T>QmG>`}o(jgJRND=*td~!JjN`SgAg06~!D|YCOWHLinS!wD$wUNeP@F7Sw0N)6BNG +sh{9D|hq@)?Uj&G?Oki-ZBfD*kPnUmQX0lyrXwJ^GorVljT=4bu4YhfPe4v$hz^-LROqI`j^MZ*evtK +DN$&ZrJ&(zl@i5$uZ5+CixwX1c}eK`N21+^~QIRayiK>bd!e)*c@Mr$>Z6N7&|b~qKMqXvg~O&1R%I8 +y`$^Q0Ft}b2ZZ<90PqD~tE|mS7v5m|`VZU8??|i`58*Gwlp;O}&X_sDU-fjB1+_*Bc?WnT^@CY*90Yn +bbwQhtLi~J-&faqeKjn%2&tdCrfZ~tESGZ}GJVEkj?V}RH{ciAq1matx{tALx?!_gr-U$4b-rdV`H85wiUUaqr9!*2CU4`5&`z`C5YL-z?9M?mY}4SVT+9&bTUJM7&Ea=W!ZgbA<$2J(5#mY+6h@$q`tmr +RH&$<7njNJ-9&tP2CBqU&{HmO8*|IP%?+Llw@G}r5+AYRiegi+f+k07KePHjGZ(&-d^3FpAbTgMHui- +bj>ihSfd8nYz?;fpgQAvz(9gklgni+im@9BUaxT$f%M*1_>LMSP=E|RLY=kJq;v@D9vFNzJ~o_G1Z#q +ReT5%`L0_Jf5MlYV>4UWnrIl%=`(ynK!dTj6)?w~sL&zjsjP#^M=~oV5SzHD1dfB6s;_dXvk(7hZPaW +WP9&9_!yQ{Qh22^9E$7H<~bg@j_&7cj3O|Qn=UGH3RxwG=P63Y2Vzy0*>727mbkO@-i*1QANvP(X(ZC +*izS%7Q)8yNj*=5?9k#(zaLs3zD0*nx<&+dWq0#+6Q`N8MawuypcZBir|@|&&t9xH@D!@@;W3VaO3x( +E(AxwX_L<#S2bpv)uW85ETdU&pBr;yC+T6MZJ +K*YY!hG1{}S`l!32pI5fFTXB647HX%XbQM1^y(9(Fes127$EZm$`-$3+ybQAF~GMW)SAvn!SKioAfK1 +hkt+^+@k!#9aw16qzt-a0WGP_fW{@?9f`AIk;@(gRsHA`fMHKjB^y1_szja!ktJ8x1&S_!(KXqDu5;} +g4e!c1%H_+Fef7IuD2UgquQx`;hO=`U2AGcjN=4W}qbzc8wTF`g%`Zv>pzMI!~(^}TlzsXO5d7EQ +~c_A-^Xq%2-j28>~FsXC|Q%cG}4&+NSGbcpk@cNYhhpDA#7low0)45#cCB +;k!%*1_Ynb(0!9e(n%5JbRZaXB_4c4N2Noq;PPraCqo=R|$; +h5mF2Rag6XB$nBttsP&-v#v_wkX4v!2D5m>Cb(hbJ$2Dj}-m9DE{qU4wq4S8CuK2syxdrrs3!_c9*33 +2b=FV+nv8Y1`R%&^k(I +=^vviH32}_&q0~KR${7$^TIDw|tDn@ymPQi`kFf4Y9fm#{RqafQ#NTD69xM0%vJEcF)hiNin$Gk01Op +L`@W@)AS>H1SD`i^EZ;VMg`E%{uJogi+^!57q@ZvS)Bv=ntM43!*tEAqQj>qo?^qcF1EgdRfg-Fv{Cf +A!0aR)&tkpbq%WD*)w2dg%3jG7558=-XHU&i3Z2!gX_D2l5ct&dWU{2j6 +E3uY~Ti5jeTb_xI+sJKpzY9dX4HN|h98jqQBpwB&F)P>tes2V_f*Tl9joW@?P#axWEk4>?nHGl$XL^@ +ly3TJ8Ddp5Q=sV1(X0bMA1g3BMmC^Dx2HEU3%FEa{mozpTa4vUMzm(%6`8o5%67a}fkD;-}kOPmyYKh +HgIdYkkYQ%w5-O|}s0H#@gIZkkxyZjSLWAWg~gf+Pvpkg>uO{cmzFdOE00 +eEmadUY9hVUrqVP|L+al&i-G2*x~Kbm%|v|=4%-y&Ej!<>@S5?^9qNkd=1U55A*U5B^&+=cpN_;bp6S +j`G4n%AFj>E(Rwq4_xa0}zL6#V&aa`#71o}tH5g`X2#Wy`0uh7!$+A6(L1HGNfXkD8&nO-OUjaZI7ax +eg04f9}fX}fwHOof8O1}01U=c`#08)euWJW0Z&zSrbZhxh_txr0!6&X+#DHO3_|a*A?An3t{j%)Lob0>LF|Bv7Usq(ZXC5)SyM-2~1~=mY=*QpL +#}}tzclKQZS(Ydm&@VnxcW8ar9K)BmSP$dF0UExXT#c}{3*3ZAYo?X?LWuUeS3GkZq*&bN*}k6at+n7 +vXo5WJfCtMqU>yOS1tPJE8QX8$pk?E?H|L+;8|YUz=bzpi=vO!ApWYkjS2yRE_vT-5nM#%>P=m$@aoQ +O!j~=5Ul7uc*od;|eq7aq>^r|om8C>p}m@0uh&M_ZFM*`{Wy^6(|eno1LI;F#_d1b+C(`nbss54U*2R +F-O#B&K@nHl3MGtd-KX&b{i-nUVG;GCmo4{haKc#6ZhlYNPLaeEn`X3A}>TXW*KLp^nIO+#)jY`d`Zl +hcT*0`43Q6yg&gh-~VbNzN2t;dXWJu9ovE$x_P&y*viJt3-Q#X*62=L +ma)N}*|c-YRs(fbn;?IpOB{UDsof?uPpF}xVqZc!|A@5lAWOui;2V>~du6Cz=n;t}!s&E_j6--Mzs8;&Yz#VD`9 +2o7HSByG0)jhQ7%^bmrma7)B6jZ_f`T!RR_SG%)z*H(g($M>EwTw*5!3pXJO^RTd&vHMCWvKOEQ#$9q +*W}CZ%A>s?|r#x&8n +2U-;rOZvbg9v3l5Cd5v-K-d9b|T%S{3#uq_~%Sf+Ha9qx3lOwO*1Lf)+uwk=?z1rHKPK>tMs`!jFG{% +78dWt*fUe%)3+X5>(^r{50z@?9GUXD>rV!6@E2Y{B#J7q9O!_hcQd*+UVk-`}O{uFL1;ip>1Ro_ii5c +h^Szdhp^=|81%d5Pd>FAfVXKE+Y9LM%beY#!a6$EX*B=#h@%6>HWOKc^I>O#Wq||oN@zLKWLVyBloib8R>!J-B-D9Ti3#3p6U3gE>nrzo!dB8mcZG;_Yctt1k4 +bIGEdsgi<9UTLq>FaD#g)cz`>Z8*8GG^6Xvg{$P5Yx!%i2++`CPi&lNU54vW>!j4uJB^ux>xoW4~m(f7|VoeBe{QM!v350+dl0g|7Mo=8ZFbXGN1ZRkEkx?N6`ik&3 +xx5hclP*pv3I&OpVI!2irJz@|W~6#qb +A=Rf$&@hSn+g^k<5KepotQvDh(~MGUWWuPdu8ocxKQU`$yIyyy +`9y~HiZX*@rBU5)d>>?!WjA;D8ef^1CuO@99sGAh6P9T_EE*!ZJ}xAWFj2w#@@VOd;OO)r2be#ib^p$ +}!e#YbEgqC*jRZ2qp*)h5z4|Dy4cTgy7CS@5KMG}6wd51ql8c}{v~?8$!=_^QUmCUA*oHp@~DPWYZDG +@hEhc#d}bgmi(0-x7uAY27HCU;0ZV0Q%{lOb_}`^ZO^$gZ|U}{>k*9uk-sC04M*zk<2c#NC=}-t+i70 +$PO({1;>t`9}v5Mbur^Z65`1n7Rx)Ugm0LsGDfdo-(FVw75 +{GhEZ2S;O83|FyVdy;%%`+B81uE4HJ_hXHjd0}`IglSm|)jqXDFXcO0Pyh-+hCbcab&M=%E53+C0M;h +IUul**sy87IUSV)jpIK9a@)QOUIIv8e_j&j?~SkaG)_8NneovItG*%amL7BjKpkk4!Vyxkd=7J0er*= +HOCCo_Z&mZIzYJTrBkh&5)H1%5_*>(oBvOOZIF5Fs6Yye;oWN*Tp)>q>7heXZDP(jn8G5;~3d`DtPHH +ZiMDfKxzEc`!}l^vQ?M>raDU;;NKmIe`_$Pw*4;=B@7kBl_tR{GHkdYs0 +g8zYj0^I+TLb7ecr~AWCvU{lno=EQXK^p?4?-D+)mtwCH|0uGJaqZwr +tFM_YRs7YGALRI3h({2cUxY{lInBZ%q5chbi6nOCRo>In|&=@5${uEFlp|@~fqg~}*Ew$lMh6vQcS>h +%H7w4SSCZ^=upzEApiM>2V)65;sO+!=B{m)uLpG87FIoO +0s?u$4$5&SSAc^kB%=dxIMpURW@%LLmS5^Az+>wdLpVhLv;z2sQrVbM6ug$$Rszp7{WJYlTU5 +MamjF{Ix&oG0%8SLnAaT$iwYUKw0Y-xUXe0$-BVz4_#@D{%FkVZA6rh4f7|>q~)csbvPr&{ef~)?{fU +o2XkMeiLyvt8TFVG28Kp*n)i-Gc2RIZqevS=;=pGhpA=LmBqmFEsotvxhboYW6w?p#RG%!z<$^SaUvt +!Wl^{;k5pr?Ra-A8iqXz=t=M3+;2``?ksd26+8fe^F!amoN)jBA<0A?<0}onn7ZITFt2nm`8c~L;0sM +Q93vGyKAu6-goYe90C*=e`6B-LC6QtW3a!HnAhJW=JPjt44q7nP3!H&x^Oq6=fUNkyi>_`V~@e}wFJQ +B%fa@!cS|WM7!IVzv(U-$eSa!ObW}B1V76>!lny8OeIuPG>C9NzR!V4XlPZ14Qs+FJnNFdkT`5uG<4I +1?loY!Iy6JS}f)#V*p*)6mW{OFejM|;=olw`m4t*C@Xt`}JInNMV!e1hubX1RnS3+VZ+iFrC?+9(3LR +RLC67>|PI>=iujgU&XZ?`TaSI5IQvOIDdBC<;~W7C>)fHAPl6=R@sh`j6BGTU +e4?u&)a#0gh?5yddNIGyVmqKsIM^3$iLXDEPyF+g`w9yV_<4WmNl7HH= +M(~deGE-l_&1Kw2*UqidL7z6G@+TJP1WRO+W%!S|N8sCGQ$5SPy2-faWoZA?H(=72iMS?9M31Gw_1GcqQjM@8z|9dAk2=@bw(7ZOQ +8q|vxy9JHxs|_P!@n1%9#Gn6gS_jEEV*rP*-R%;QIh**}#2X<(*miXz_^9=NO<>70;ixZPo<#!?v~14 ++p)|JIR9lPebAf(l0Wx#Kf<~1fy>uF(94#vhDKy&_6~F{db4{aSZfthyF7>=0_sKAK@{W)?YTHx34+b +9RzN7#b`pO=v>&#@wN#^>ZF7jL~F+a9c(`;2m5;JudP6e^nq%;&8s@VHlis0Hf5+>83p-{XydJKc5I- +f7u1iBfFX9XEN$^*RKa7wvP}{^uU&93%`-Vi5{=OTVsq1l+)QS9-`>-{rIIx3a!YC$n<&FG40+5TTzw +f`Og7y|C6SM4e7xYsEQ}*pJ9XOj!Ct_&u_MwNPh{f-!D8x=aP>=&kuZc5{9Ip)`NrN)*VBZKyj1fK!D +qI +!rz_3gUwz(oI+`*!;2+7EDw#-2RwIP!rLaQnLa`jz$ns#@_|3&Pwm1^ADJ8lu+sc>i~#*pfA&}A`PV} +7tec$hGJ)f3=!E+|%uX*i=_1yTLmNrk#=9PrVZcNzZP<=gU|A(4 +u2j5#Tg`CM>WH3E3Ug#a@cai;apTv#lW_87nyJv^;dbaZ~ABxNUVrHIJ5 +4%^sr-GL#Vp(87UDlmIv+!4&ch1iMy;fI`;3c;2odN*$kbgb-*JGex+xV5z3)Ac?tY5Tu6aUk;Z{V@( +y#CF!pzr4OZ>9x(H?QyQ|M!|6&^MwUT&eemasS+BQkhlW1JMX!j%(GOY=1e8nZ6zsMqf3h$%8A@YV%P +abDStoQ&gkRla9;{evX?&TkNxThv&_>eRPxIRJWlw_LTN0DXl9u9<7S9V3B3UQ +_*{>36yx!p?5_CeXUA;ziua%ARlIl0&wOZnHJSj3ix4&{~{Oh1k<4mMw&3DMt+L(_-)Er{7?)%^*#wr?KJ?-)^Ki_%@_;CDC>d!7{Omerywh-5>XCck&UXSvcVDJotGh0 +wR0;RI+|k`VZb^pp5DQj+UJl#+X-hMwyB@VtqhIR{w7(W@Nh_{xHdbF>y~*edWNZofT5cb=q1{M=w7E +4Hs^>a<3r@~soJ_K=2za(!Awum_h*!#?8sM0`3Q@`=;ATDX!tYX&%KRN4=v$z%bH{X`YQ1Y6 +n=%brXTwYCFqZg&>{Xqas=9mxJo^{tFe1jJG7QGt${=FWEdeeYx|EzX*1Dw{iG^v*YM^3@K^WU1%Q-c +^|m@l@T!RM23CFrH~r#U$XZKSLCX9iS3>qyl+Mp=E&t$PS?0V?SrVCZKvK;CZ}3k0+Si2W%bZz|lCyh +|UHMVd;|o0a>!_hGSNa5ORTjF$JI2Or0boPDao6C&b1? +gLH1d?k+H`pOA4{6?rPH!1BA#u&ETpY0KH-4Jr`70~9aq7hYD+-hqk#On>et#L&&`3myS~dLgX+y&%9 +3xjz)hADe~2UP-bIU>RcQr!lUjMZAz&oGb8Y_;CgzHy-nGCdF5gf;M*gM!ZaInZh~K6H%13V)Z0zG;V +hZ+e_;ctx0JzZ*=bc4}^OWWkZDWbaRuKo+iV_bsdrzPB7*{oWrJ+kP7MLAM3jCl#T_b`EnjiXXJ_cfP4j+7qQO>K +nU-4Y`;(hJ$rz&+7U%~KcUtiBIw7cYrS7oT*CnTGD^~jM3-BNI8)xt)V&p3)V1#Amf?w%f%D}5JrJrK +PkW|ggXI=rBCvhm%fy!V;*@b=~-eu<=bFX{d%T{C~P#5)aj@o%sl=ym#<1S&a(QgD9-j({{ehd{T*bk +WC-H;4-!2J<0}P2qA4W*jw8vD;z?6UWPd!?Iq#hxeN>!=`$dN~7FllFAV(B%W@W6w4uWMR +(k#Ygl3wDk(Yu8`YhSD%-d7RK^q#)=@Q=5SdZ&FNMP)6PAd`fQvCqI2@cBQ_4KM>^1>hFR +`H&g8W*j>*MPw(gda+-)_fJKpSNYhFaw;@P|gAir$^`i__2*WiG +$>6KrP%4>u&pjww^AkHAx(%v$*1SB+9mI89EMTQ_83DcEccx9k +pu9~a`Mf{BhdF{*V2F4!gK2bT+^8C0%JWhEawmvI|sh%?5vI(=>pZ)i<^AabGe`} +`W^XX=y47#kM4}e@u_`eIQe_MxmFWk+VEl;{FzO;+>(pC()_Vcz0I{jR@+r>{!U?1-}8tnilV^RYICs +IX=Vf>&a{#e_gU)JGD`4@FK`HiJM2Q2k~p6$?7kK;>gZf=uqv!jdD$`VTK#k@FEhu2KN5n7&fnhd?n7 +Gt#KdQOt))WJJ_qCFFm(^Gg57+KjqGPT>EiFt~z%znF{_R^WS9oy|$k-Y%hk~Q|c9nUr#VWN1&HeC@| +4$?unk+^hoC%8etV*ao!K?(P;6}->*=R{1~_=MP)zwgk!jx$4HN8P>;8{-;R*8VvtGc*^|G4&;PSXNk +`6(9DMJ|gCR?80qT-?#BgPKLw7J~*UGRpU*=ZN|RrpIX)qHqQ<{wA&81SyP5SM%m$z#mV9!?b514NV` +bI>{tvQrDZ2li*UFrFH|f}i4~`#dO(Jt3sLCenw!Dmx|{vrhK6C;eWI3rh`;vUX6Kw*PLo{kiHOM5j0 +d9KXQ8MkA#yGXFShLQ2~|CQs!5@5ur?WobC;aeDrLxO0HK63_g7`Y2gYf1D%ex@z~>R +c~76<(`~x*%KbQ&r9Sj&$ec*bJO#d5_?RBfDK$)PM5zz6Ga3mJ7jtcwyg{F6U3wh2Bcrp&N2+^CTNA7 +@afsr3EP2$37vHuX<(SpOmdS@TZJ5a}bjWKqqU1*U)8*Y^cL+JZK2~1mPk~5R)^Qd_lNhv$p3Y72fg1 +`zrv1I;4|>a_+S=>5)fAV%9;v-GTwbJBE2leuc8)JrduLtzi*Zr7?iatQ<0e*wG@AuDpd|=q!MdOi;^mwRyTMr&y*7u@^xg)2FC9OdYH3;qc!YOY@FAHzNCkfm(Lm0y+&(`x!z3L +mteYViI{bVbIxVyjo?Q*BHXqevApOs73KWRT%UhJvm9;XXQZSnyHzvG8^>n* +sB_B0yC3;@NotMhjo}(_-A@m(MJv&}=GNPRb9Zn~1TeSBPzc5o6g;$hI^K%!-ho>AAHNr~OS)lS>g&% +b1AdxR^w1V`OrA_O`A*Z0?%sShGL<4)fvzT@>cnzY2+9Pd?T<%VAW+g{8?chXswE}6pgePl`oW>!K^A +V;t2qboDVOl5l#TE}gN)H`=x*RyF_KfT%&FtodW->ueQ)DG-xF=Mlns{EYqm2|@gXL*~Zo;P2`h)WHM +PD;Hw`=TCHSXI7$6)Y%Q@ILP5_+OuJy$P%-p^`GJ;OwL--dIAyB_pNT8Fz|uhfw3j~uZqHZoPEJO6%C +vqE>W+M;#G8SA6oKTeq1TC%4;=Bs^q;z`+er?T(krv6k_KtS5|W8?Ase}9{*eMde2oDlvWp6fI3`?vG_km*HH45ulEps>Xsqc +Mi2DU2i+7Y#;n3Z)o^CMg{KR$h(ZAZb9z6r&)eN~|!ai2gJCo-TpNK$bR(0g4)sK +jWZzj|TmFAfZg*;H*>%(z_uFfKC|$>a*11H~os^2}OXr1**X)$m5dmiuFo?bA{0F`pO{!;8iKLrkYn; +hh?bIDnUmOplBSfR|N`l45;re*CxqT4k-PtGll}kgZ|718y@@EdF*&|&r;^l(>5c}M*m*g;rg>Pb_oU +1d`EbKWU73|63`~HQW^eL#_Db9J$DLypFI79MgPPbtz)65zd*X4S*0^>&=%=KSi7hJ3*^gjIJo>&-yR_)ME3amFQ=0F0eRz*?9QK$5;dys#TDS +d*ztzXkV=WA~szxL)W@ja~8Q^&r7$BQmD+~{b;af$iQc@oJCRHNKr_NAt|v^QzyXF7r+oio%LS_Qv>R>@a#16WJrYT}zMY +&f{IFw`$yFbyA<>Eo7HfHYlO)dA(Yj;^L=MHPDOQgc-2&e8 +I8@LtSxkE<2kLro%%rsoE5uSDmq`l5uZaocNW>~^CbQY3}k1CsnHOkPgBEAadINy8$j)Fjl=H9J; +mI*dldb7EM7vAZN05-ha@f$Phn%VzH`=h(0GXSn5F1B)$7NV)Q`BN?p%|41a{-ux>b0Kmy44nSM1C=J +*kb0Kl#0(O@mA`cGN%!!yZ#!%dheEs?_J!omEVZNx|#v7j_-(P-gatGYheIb(Yb0PS4c`8Qu4 +A=IWr#7)MbhJ6F{F^Yc5t)vML#jW;Kv5OCL(HM-{yuc7+ZbPANTI0$kp`9pzF-&naH`CcfYqRlfS(CY +wWe#CD%5s4qFt4rwQxRrp7Sllx@D;3!G?MIf{eP0#%6ma?9q +MZ2(;Tf}a;I4q0~-yNj97HVneIH=G1GmqS#H%4(D7s}W(z9WUl%@Ptt0?i!)wSSzsN`*@s$4p#u1{QA +)&Lm5rhA?mnVJ-7~@~1I>>Txq0j%`)!X@3{Hq{P~*RSB7$-@G_AB(~n__dtJ`1fia{<6)@Adv7kG(Kd +RPIdRM{M-v%rw|9eWg|=AAXowb8cSEf&Y-~w2Ex_(3Z?;-HnyPeGlqti@7OK58>|?$6dVos +M=_+_@KwBUJfjQ$6NRCh%9Zb&<4s)=gFiNQg<@NJ$bDkpg__>|WpPq6_Z}v9iMuL$sWUMbP<_3Qg108 +Tu6WjJkd0gD>L!?Ks?q5IIoSK7;PcmJ$Lk3~Fxj!n>a8#+B*|t~o4=d;9Ee<4hbh_qFp6o3SGuW%GDW +`u)PXtm@Tu4;8zh7;mDt1qshBwJ%_=-CmS@pTl;0Fr7F&yCrp3%7~wz+xdj@&+diB +jC&}UgqK|0@rPI+M*S!fMdUK5`om@+CH}&02nM%0BZocl`$CG;t8f9X!Aop{6qll3s-qa0$iA8z&;rQ +E=e+gLVei{2&|AGD@pubgLnYgzjpKKBnrnYC(O(@NAg6t0=?g|)A4&CLG`nf2vBv7#(m-ewbiRSua%a +!HnG3-BvtXrVGv-*T)Vj4w{i?{05!{)Wld +n$e{Vnm@yBf!uKG?~!_js&agj54Z7a`CU^LYwzokjydxnVSx?0c>k&rS1Sy3H)j=UU2cv +*1Y^<%wpvALz2>B3r`ca%2=Uy|E)A#J1;N$T!erj>1Ja1t?GZ+cH1(WGW#2Vmmah&;#GyR&`ur!GLV{ +r8U9#?KI42OXRRj8hRYykmJXB6K|`?xXYF|J!?Vl9f|yk)BzCd)l<-)%^YFC`+@3<`YJ+y|mdBo9zOBs2*phpfoQiBOB`1)*fT +|pp>`L8YaUJ>E!vrKI%A?qfGm_j==YGsy8h%#Pt6rg8EMA{Jp=(SIS3CC*Bca(f=B9O@xB4y)#Vz;k4 +9cb}T^&RGP)_-1qc26iVcwQ5@irBuO;u5NmSgnpW<`2JQu0B0^fl#`o6M%~G!@s7?jl)f>`}{kWUS#v +-3zX!ct$f?eMWe+-_&M9;^I&p2Y%RgnlvCK9T7%ACHl8`rhyTKR2HLofG}daQ=9bAG^;Pd@-5~!O#qW!Z?gkI71*bhB73!m`EGP1qkP3g|;cQwMEkHv4WI*R0BGF_u4 +U)Ar(zv`Up@Lz;O8y}|EUmFL&1fexbQ-e$dzgpeq$z4TYG&pR~b0)ea%pc?)Zz<}4R(VBXZ#iWnW14z +Yus%ri#wj=y97NV!7onqS!l6FhzapJMmm_wza3iVi3JqPiYps~U6W?y*hyiJ7X{>nN8R$eSMDW-sBW% +2Op@hGRZ*~=cD=0kOZKHl}1f7>+-1>FkL$x;%t6ir5la7^=w;A&@URd6Rq@em +SyLljxfc7Kor6;ew#dbkjF=h1guh=uXPo&*FCej6B1q~9dl@28}Tap@_6m)!Y$;xIx#GA-i{mIVmxs9aWRbFCWe=GKPXfgQ1Bk`o|Xmb*BQ6GCWPH*i`RLU>)@zeJ)!I-Iv(3&yG2h9!6rEblgI7N=?`?`9&zLZU+NQiBC}}NN10zoF6S@x3eZp^Xr1|Agou!Byw>U=Fje{uQbPRK@D4+x)&()%$#zFe|5IZzwCh4}frQSMjtOw;6R^x#IS}`nEGSG-P_G$+?jTZ$~W#|7d_tY`f_Bh4==8qm%#34>w+h*7K0Odh>R-)$U!L{Wq69 +&jR;S4+38-hqIHi;`Pt^Mhr`NAi&`XbohbRI*p9FEO)B%^EwBr3ar%eo{2#EH|HE_s&3yjyd|xdoMi3 +Yd!!SkS2)qQM48l+-PGK;G;TS~&y=nSe7MJ9$hL8e)IuQecWMKZVm5PM`vQ;qwEb3w(m#FlkQ|#|03P +8-V_L5`RTGU{GB?}YKNWNG>X6+AO&bq{qNC;>T<5fliC4Pk$!B=bt0febz3^26Bt2h?G&r`r=F5&WWm +ULx@S!^`D@+yKF2n+&EAc+-$9yQR`PW?%*q%_Or7YmLo208n!Azc}ryH7@EgYBO2p>9;;@K~1Y+kC(J +Rq~xbEO7n*mLcsY#rR+{Ieay3^76Tn#oa5$oEflVfgbLi^F{pm9c+TGM)W=6d~Xte{4ZV1} +hto_jtB#2*aV)gJ}VxV#HN6Er?rwLnkdP9xAvA29;+S#X8{%{Y#=g(+#_W;5fkm>ke)U`p!_^*&E;u} +)MXxuhd@XN9}?uesbmTa-359kths0mK@jnWC_ov&?vM1!R +AZLYD-X@S7uneB5(?4R5N#nrQ2;uhV%XV>-1;(dKXC-`@+73f>C6;<3!=vCOLjKn6Ee<&K6eK41RABF +dZ@I;;rU*kd+`j0#RLQHb;1>$`kdYGQZ(CszLLGH`WEJgA;!<9Pi#%De!SJrUoy+UL6Ky=-so^|O~bd +lRoY1;XLU(-TRW%3238WrJ)PQ*!6$$`P4l`GYyd1acme(7Ya(`cisySAQB^6i$F3dRXI;z*h+1{8AHL +50N}wNsdDrhl1_Ss9rAYo_RMPqNHLYt!hW_a|9AU-Y8b +q4`s42h{Fseh{)17NhH-*f3?mK%qH&U@NEoM=@RA}J0$y{Ue^1BKph!=@(T%NzZ7c@R$&3QoR2Tz^&o +EsTq|wF7d}|P?H=raAP?8i1Z0Qm~GAPhYS_0R_vMqrhiUG2*B_NDZ0CZ$lFhCUjN|z}Ex!7eS^eV>$T +Cqb=gC|HJae&|;ZJZFm&?X4bc0?i&UoJZ=;{=V`A@~zPgKTcHN-ZpQdN~!gYBj{sZw=xV04Q&t07{dU +UB=p;eDtBWOly0~LRgvn-{^sX-#bAk`$zbqS;0}i^9KwC8tPoUYglY`wu(!JgmeH(Aqh=$W@kJ2ypVEl3?-5(MVLBlCpc +iOnvX&l*y2N68j(f1_e^*h3QKsz)jjT=y{@lwi2ZqZmKhL?cRUW{5Q1Y|gaVZ|445OtI^;T~{*IfYn= +PQ&ndelJ-eEopwA9r~Q`CGrl$;d~$(nmrN2jd>WDp27YQs__oH5r!#uZb3tHw&Q8^xqW&qEjfGnG +002wnj~0>nD(IA!TxqtA19k2`a>N?c@>Pu{g7c*> +kRHrb+YNQ*>zltA{pc1;&DllEYgCjP3(e8vkkuqxa`?DY4dI~Vb2J@8bDpLV@YupKA9G`8=q1S+`oxi +zyWJwPHr)$MaXILE7<9~A=0vHwrxjh5l@-%qqUYuEc*6Zfg#VhOtkpUKF2;{Ms1&jsHnRXR8g +DqayQTaJYux$&oIuz-Xl2xEdyP|;Q)G!ZJ<#62jBeH&w=5;JM=UD`{A%3#f(vgp_Yh`A~1|$mLC|g#C +s@7G9*F67`4QE1o5qyF#-(OV%V10Yq2PcNh4rjDv*`U1JHA&z^;%P=o^TMZ*5x=0s{Fr$}M6|VPj57ozPM7eJ`NGHvQ2)s)9fSe0 +&iD;_27`<(Xj_Ou_I3#rVG2kx|IW5qz_wkKzr>7{&6Mlmz~`VWl7qMWRMuVtb2p@EQ2gG^2 +bYB{LQj%+14(h%vGfO$9g5Df1 +7u-_|Dv@<2f}UlkbTi4s3bx~)O?8#b`RNT^_p)70zHJFNw^PJWXFYsSyDq*KI1{Kx?Ky0=^LaNx6c@~ +h74^s6nJ^fE-kL>hoc12cxM7XM$zy1$M;!SWEjsL_yQ4MrJe3sUv1NSHLjej?!>FIvZYV1c-<+A6*iL +Nq0cg^BZ82QG$YHJ^C+KI1njiTsty>?OlqyLiy4k5$$=g0TColdV=H6t*MlU)EAqf!Aa;?rQ)S1`p{`b9#4|k7@i1f&aJpV1LYnB-qi39q;5o_(e*IqlQtq>o6o;x|f_WeefW=0>!wrCtK#hE6wO?4w2Nd_wGXOVK-y{PVzl)I*RS43EHKRT3A*n7t&lbOz= +Qye`{8)CqU;{(N5;f5q)JJ8Ql53z${v)6n0A}sP$SE9@jf$Y&4+w`MwkSCA<^Mgo_pRLUV@ov*MtwDC +7Pg7+#g)?N+_kPye(S)l5j)Xds&<8QLT1y4K%99+nrK6$i+_fDfQ|e&6>K1o|(W;#(y8|eU#6_Nn^Nqh~u-UhKO__l;w +zzaHF=cFL(P?i{^5RvrfZE6cpF{^@wT6^5kwSc(9Q6vo(vm6|)$;;*J1Odb_c?z1~NEnpumQTu7Bkbi +sa&_a1NsvNCau84A@GlLoco0<#e<-5`j|}-ols>TPj<8)`x-B6Td-&kX& +fpmB!#_Ns`mxK9YF34i%R^P3Zfs#5&5D3W_v-c*rzO6pu+!#n=EXGGa&jnD^QOGkK}lH1j)DqZ^2*>o +Z5}+9_5^o0@=?dDjf5Sp%2Pk~{EhMF;*2<*jvyX`&z(1<=_4AoQ?v;cC}%6R==-e06XxopxFN;-ecW- +U7lz>7b(HxM4<84e4a0%Fc9NII#U*DhyD8zj8jqmpEb4imQUp=?l@bo)afn^b+z=_hSLO^K;$FU>OUN +o5UPd*x_V#+wSY6A{NL-5Q5sE60&X1=~ZzDVD4xUlQVtVk7SISJ=A<$l5r;{kEp(@f(vxa|8F)H#$hE +TND3?U~eTpu~e0ER83>!WPfP=dW@&E+=%ugco7A=RTd2D>$u^IZ_aaqN-P3^Dm(pzGrbeK&dVeV~1)d +>v|EecLr3o{S-pnS11$gbuGy;sc6&q7F~R$AGl&qD}s!%E$9r5H=@&Hq2W&OH`(At_4+mC0x*-Du=s6 +P(7j-O5+kS>&wM1j9}xTgcS4_t+hzD7-N%R4jI)9lv_iVYHN5ZUi;cbmexK^Jj~xZ9~ycZd`gOh>2amduP-x$TQF2+gD#pQvWyeA(lusa_6ttDTUJDyzW|%+7}Td! +jS1=V*?n`yeG1UR6$uR^zBuDjeMPS@FNd$KL>zh5~#{`dc8?~b;+K%&@W^`pOD${OGy=r5|HFG@ML+2e~7{qsMX==IP4O#b13~+SqYynejvDL*h2SN5iFEa9%)ZqXEvX}DLI>c?$FZlb>#oh-Fr$(pl0p|6%s3Km_>6|6b6wuBDCCeW_w#mDd +cmT1*n)Mw=+46}#IB93YgGc{eq$5bSI}(!vIf(6e9zb%fi{-Ra4QE_d0!N9TM?PGn3sJFvW6S&h+w`7 +JTkjdmmt`e&0XcF*#y*&}wu+Q!n^mlI9XZH*GJ2&jJ`vv{%hW+jo3}^`%JM%&bwQCyV)CRm!DZcVJNY__0*E +OeL#=ckFV>jF~ofk4xTZq>~>fkb`ZkH^FG(>Ii`y)loQgFGHDSMwkjL!aHo<=81>&JvYPcJ@k74Oh*W +W=(MaI5XqX>)2qF+D>zc409c1RdkShhr(1hGVwTYL%lAx-J-?UWqij5)T +N*c0q#72VF%c(v%L=Z;L*vWJguc5C +Li?+4f(Lz6Q1T#kh^K|7FiBhk{?_S*5LD#Ck8{3APH83H#3?9ZlR0R91es$5dEqUm!DGmGw2?xhp8oA +pynm1c6pigXDCD7Sf)k19k&e51_qdOGoLoVF-qe?xd5z2scj;4UhKdnwk5`jK@p(yD{tVEWa=FJYWWhH)>OUEEwJC#+Cex;_->DT!LO@0d9_zn0)@zUS=D-qQ! +hsIHKMsPX>X>JIe6LM9KYKuHQo@kzSbHEpG&)3m+Wo073F&zf-i_`- +?m-!R$)t;!&5{~}+3#Wefn-@eG`N89uI16Ka5P5L*E`K}%MPy2s|%NWj}AjwQ3G)yuKg3_Ow(JVpy0& +gj^!rnS%9g9Jm2&l2Hh0i<(^GTN=9SnuXKF>GPK!SwPpj-*2HoYaR<97l;t;!;t05kwwGXcyhF+wSzm +;D^7L3d0F1VR}D5PAV!I07kfECcePWj)y{g@OsNS}mtvA(x41CK~ +3E;%JeS6^sO)jzsa1QjuaVm1T=dAGCtep|&!Kjs+(NBCae^xl2E<`|a1Truo-`Nvw(4Uf>bOSM +sEH3+sG_MwW&>!U^auR4^Wj~3;AbA0C4do7%`=gnguQf*OnrzNlcoSrp}7hg9z^fKNOh?8a@R{3&o4| +GdI6scPyNAsF^JvLXm5;wusXZgye6S>2!YDYbprhII@c7)U-2x0x +~6$P+(Z;n@AQaY((%y`lQ<-oGS?r)hBz0PUv{re+Lg7o^Iqpo0+F#n@91G>?furjZ@Gun6+?<5t#2Qn +JKn#e+fut^cD3h9kzJw{c2gsvI=d;ksp6XmWi3lbk7vHy%o$dQ+qlLWSB>?@Zu_uBL3%Ye1AVA{zN?< +YEpGVRb>F45=p)vlW}#~kJR5E9?rRFUYvhfyDIYgC +^QbdSp(+hG}NJOS5#-p<2+tT)1-;l^Oi^}kMW$b*g +Dkg;Zg=~^3;!p!~X2&!}Q98LO`8IDUUp{**C?U%zMZU7EUQhPu%S`GS75=95A6O_Bg&5iE^h@7p$O)T +^Phg#^^;~a?5jMs8crC18|i7)^s%C+|4pbojC?W1g~uy>2I?U0hK{3M@x{!r5?-#j<30g?~y&COZ +jtYuy--lbGOUGPZ{l}s?MaS+GZskTfS#}PO4ZJ_py +Zdg!!#NPU4$@Py$;?DX+gs+$1hy~Pqgp5nAuqE4<$BYF_2tETJ|z4RSLo`F_>W}yF51Jzk)E3o3JsCF +JTJSed<%s8HV6*t;KU34e2Tbf$M8!g4h$~&q<*W0azFF~GO!z#-_IPnIX@ndmC)QhYw?#KFE6Ng-rsD +PuIt*T+Yy#>Zc`B?9_HGAfv!1aGi3eWC2YSs>d%zz`y;+3Z3G3w7>&UMh9DHdFa-Ij{w;%nj2l!r7|> +Rgyv>VGK;b=sL3)KE)Yb2cUhinELWWNbMi%RqZ@5`$hQ(3G43w#HyUH4srid4R)!8zL!CqJ +7TUmSe~SG%QD}oBBfA;s~hBWDKK#Di0@D(Krk!98k^WYok~WGBWTwL?uhXA{P3%aLR?hr +N8EE1E|c9{s(7MkJI4lh(qb{{Zq}G{f%QE1T=3JTzs#hmj2*mz=qrYW*QPZ8Ns(K3IcVISP7e?{Dvug +)pWCOmNT;oo6V}}{&Cv~**_Qv{@v9;-;uh{R`Uzq27PNSGaY0lXH4A46a1A|LhJ77X`9jJCfz4-r&pv +mE8g^Mcevn@IBvqm07)~PzYO9k8WP^0YhgDDq^`6A^DK!-Z#=rN#csY3Th`H)K`xI@P6VeX`PlfSNX0 +!A94RX{m3Fi3GRj8b%Z){RQg&WjZh7mG5?{C*;!*2(y`eD8#kNZzZ&Ypx+cbGBGYPuHtk(#76j+FI^f +|uoG=)^n$d#(DygrFjq$F6_?36jYJmIP?r~o73g6v1;QcZ~hk?e6tq1Wlm9NEXvy2S5FB@RxTwSTU!NM?P<3;(TKx +@#&n&(_DozS>t!r+(HSh2z$7=6$O26smizsC*jOJh5JlyI?e0Y<4t3gLPV1b+}dsLU5L2E140VrTI5F +!GOk>4Cl2hc4+5S*HkEsMiDI|iq@Ju#t#e(doOXLrl`ywLKPenD&2BD@Ay2ED*j6Cr$ldMzwKH+wiR6 +eb=4zA8^%F*fQQ1DSK##g^xL&MWj%7uEF@X&`_vSK5&eM^PIaHa_^Uh&s4yRS6Ym+2v40LzG>`Bd2Q? +f7Dcph(RWwDPLg`X{f8FFRF1(`@;FUBN9lv{kpLG=Cw@;VduO+V_VB?M4_Fd4s +y<*h?-oy6o2AvpY02M?EDwJP53L`2CY`p{{nA=SmhuW +8GC_C_<(Efh<6>ABkcWzFl7+6a@5v=px7GHpdwjIjw~}l?{U5=_wwMJJIL3Rq_#!mcD$wocWVNT3KWc +yYX1`E{R2<#qAa}neT91q`*;f9~%LH1U0iOw5ZK2>a@2-2Ei-!F1#A@~%HMiK8%E9Xt +8UT||gl9b;S)TC7qwt@0R8q;Em!4#U|#9AH#Pt%bZzNA$73+;aKcDfOwIpI1FG+FEE@Ja@L-w0)YFQjs_iWCE9_on02=61dy@ST(fEsknKP|90ignl(jksy~e6xq%41 +Tvdu^tV%1*RDsoi2FEFX^=qD8%~R{5!$~{Wa->kj>>pFhhEn!%+ZK0WyE8oxzigcQ^XX5C^g8TJb(W5MQ+-6 +$hJOaI8VzY?o$Tj0NgIwFyFe4S(B9}yB8xHxzg4;{SI<4~v&4MwN|Yy_zs=j^?E0pN`PyFa(~&b@cLhV^ejsxH!fCz^cKyv$e +Af(!QVflvBtakxkzz;;LvakjXqdz?lA)31hs%FIBYz7+LRa$iX88isAm0W^6$U6&3coYLWlKi>BhEh` +V6%2iAPCUQAnPQXm|h3Ip`bRFt$hv%447C-0!qfLpRlk%=4Wm7%a2oHJ%$9iKm=WTFk(PJ!BkiTXhgH +MX9EnIM*!hlcFSpCr;{;Y9Sao&jfpX!h6n=|lxAxKKD^M%UkXHXP+M!i*48X}_d=op=^kg74A9qr4!w +B&T$U4jCd>J5`iqTv!-q8U#~G^&^}0ge?(l63!Y_>bzjo3?MwNWmN^e%6>=nF>*(JI5Rl^xec@%>t(z;zr4P(HqtCqi! +gA(nsj95_3pu-8M9c0s47v@y&D@IP6I&S0xMLvJk9XABH)B#9FFJZYhork7OuuB=X=bWt)CD}6!9sO- +AaR!8o|5Zxb`&vtF1rU63x%qeNG_^QR7T>;sp~D5xg?q9?0ITu6as$akD)|3qtuLQ<(*2kpBn2XAk;V +|qXh#=_3W)clJUKyJvz;_Yxm-G>nhU9Ud%;yKs|fy~ +}Z6b+m+^Sjw>Y`y9G&{AYgbqR`FdX$TXq-0}yrm11Xj^k{g|3_|^jx{}n5`D;!evwdKK(7rj*#-Yj^e +G*MfR+Q`h3M-cm6GjVxNIpBn8o#aWptdVwcf8}h^l)|ejL{03m2B-!N1B>9#r~3o$T50cqG0av!px6t +CN~fsQ?7TC1M_&>)SKJ0cXzK^-WFS4GELu@OZVcpFtwYOP=vPx487+=>+iypiafO;chGe=z)z(NUR4p +cN%Oi~D$^lfgB)?QSYq^8%VZHMk@t$Wzik#p +6voukn`9W%$J4;8Z8=C{}7EF*nsZ==B6O;;CUk0eWryP~nuEKV@PA#JIO?hdIRGXLop`Mx-)XCxxM`u +FQfk8?CWvacZXN5}fx5B?a5`aS%76>$jVP~MjV!Wj6MAW0NB*kBY*Q3%T5Fav)IuM0vY(b{~mPJl}?P<#S2UeUFm5CN4d +WEF{|^a69A=T?xl-C@nDU>V3@ybX+{ae#6-4a#Z^v(8#bK(2;NK#BuQo%>lmj84G<&>ZZypnQUWA#e! +{RI^A5uoWXg+J#vSabgslky&eI3lG#fi}=>=Ja@UWvFNd_8d3$w +mkC5n$qavEc4G#q8!|RP|a|YnhiSf5l`HOdd*4W~0i?b0P6xD|FCWqPu)7^Beg5#*ytCA35xMAGu(J% +vt=V-4O(*fA5|^Ki-tTdrzPrZ_3}jC(w^K<#+DMx2hEA7cO=8>p`Fj>Ed3Dtey$q;fDsRaxK<&$ajWlp|>6*>0a?j_mo@1vy+7Mw!dW5`ZQ7wXGp?rv!=bnpZ@ksD5_TmNlQ=GsUQ$cD= +ja6XlC^sE*s8%QJ)bFEibb?o=xe>~Ka(5_0P8E@Bg)g56CI7g#LQ$w^J7gu9Tl&b&e`Y0R56YR|2U!9 +AZl#w8T<2JM^|gKLm^voTb8Dz13+4lUkA`JHf_AmbyS&0zLHZi>q}xomv!l +0OM~MfrOPi%t3P=>YXKrDp>?)#vW^7)+T&Qq}!z?DM%Ziu2u7;%lg=Mz_06Pj&E->k`DzdSfjoN||>xDD|>Mq3vyAv&_GXGR;)egGjG~Xi~;mR*#KY2z~J4!)JEc7^6d3$#UC=MqIXKMMCf}6Ko+}iH +`v>g;=m@af>YUTEXcIoX3}hf=2d$VHP}&gG+I5Km29Pg&CHcHLXKj7~UIR4H(=st +o*aCTM4r~aJ444BEBp^Rn3VynL4vqt1Z}u}!ASMFGFJV8Gt)_S@NuuF3hF>lAmS~?@t&A3Cl&$`HtfarDDKKb>q@I6d0nFaMlp#avkDcmO<}BZ-&&~A~n)0eXf#k2vDh +nhxVY6V|T3`79%x{DIB2cpv9Is}hFMH}H35xeNapwB?cAovsLUX<6g;O!YlXCAmJ +*w*8`Z8)37vbiy0UDpXxh+n%OADW=kcOOn6cx_UQP+mi6&Y=R!}bKYK=4Tt1+3O>YPt9n7g6hd?iu%R +kOR8y=S=w4mnQG>jPvS`OuJ=KJ +idY?si2lna-H&n+^ieO0t#4+WTB8^ox%}#(g+FtlAtj?{2O4la2~l?l(WW){B^H=j1>y>~7Yc)y3(Ku +Gr=xt0?o~kaBfVjxhpo!|M9B_5YIaclF1`Qr9+i +XtDlQQ$?hA!kA&vgnmT!>uLB3`ZwA+0yDkJExr1rSk0w#Aji##ksY^Wbhz-dBx_8FDUOB&|!`cH+*uA +7h+~1ru)A$FnY{MucmL`N38fiF8e8Fevy7!2pIsrGS5=tLtu_{{#71vSc9;39_2vuL757m6R+*1jc{`6 +OhV~z<&a?FQb6kq!^$!G4Z~BAX&kIz!+H#4D$pOC~^u^K#24o)GsGl3Qv$Mx$%Fr2p{E6XJrRQ +rChg)c9@z!Y{iZc{G+YKJQoaPJTFh2r +i72-7pWqPZEzwB(v*=g?L%nxfN#W;6656QawZu22oC}AH#W%?48QBr%@vG#u%CoP)(hJ_H7pK^ERr70w-N6-$HU +`pX1nVWD??iFEijs|m?!4<2MB(9fCw-^Yj6=;up9ymR$ne+d5{2Fvoa5vlgquqIQtWw#Bv3K@HoQ#*% +vw|X`V=TGaGpqQSR}9L1c*CV1h|-(QC31+xZ)9boHIf+0N5RGSjjWCn4;Oz#HdnJX$%*TK+{xT9&+1d +b5SFQ#YJaBVi63b-^?KW_i;~&+gi@cs|tWw#Ag>sVjLKPqgY;Jt39l6G^(hBfINVw~#>8PhJ;>t$#VR +_EoF0{pIo+G_$fPO*iqQ=AJq>Xq7&!-73rjIS(&}E2Zpk310^X;twyCj7UA-h$ADUn{5)j&=Sq;h04c +!T)`eHyfyW$bqIAv4rQ)!TDnqq!7CUeVz41heJIbTOd!5)U2g&$jvl`AjVKBK6D{-4l$}tJ&tSc +dYAN%ul*uy+kiGQPMW<{qDANs$Igui*<_gMJHLEl+7QNZ1v1cPBP1SSxIz)=iEmXMrYf^m|eXoC6Frg +y=t90y%30Bvv}U|isF32zY+MAr*E0;q{V$0+EF`P}awivYw?s|Is{E?_zcuhXINb)F!y7RNJykW2!6@ +Rv|MU%P6MpQ$o|10uXO(BNRdB_v<)ZGpi!2G#xrQc)O8c?RAaFi;YJ7FS?5xQ-f3fXEa8DG7@A%cU*Q +x~wc+u{c_;?$^#u!wQCf6y}#$s_gcaTV5NJ;SMT&sBYcoh56mT4u*fY$uFoTyq@cSryO-UeJaJfcb2a328QgS36Q15{{JDt5uF-V-tS|9q37-y^3hRWgL1PGyP!V21FV|OSF(-> +(J~`u9PGCiGD&3<)`nnxI2S$){ysvxh`n5SUslnt)`bA@p2_ +SCFxDXmmbWS)V|ktmM3&7;@6#cs)^I)a@s=*TQOT9-Nm1!D47&5Qb&f +K5-6v2q2;Fjc#c>S>+sO^OP0G03t#p^!B(Hzj-X@P+U43oowiZD8*_WFq$+l{eLC@f-;K#5;gf#pQ>T|0@k^~v>1ydIc%U9cZX3c6ZQC>;_dwDon?Go3Ph6Ut+)GY<}y +wp!^d=ua(m68Ci^EYGq{2vhpveXNtXKQ4OARwO&V#OF}*r+vuov#-B2$&KKj-nF)*)RdZPGl{$gOv8K +T_O|^5shEl7_8$}T<*Ts;Ou>&R5-%cadY@tslE8o#urwy!Z?*+9<`K3JYip`Fb+O;Tp>Ivv%r;*uhhf7*qGKp3(|tV2NT%rNAeOS$llAa*|!3xWhvsA9s_@BV@#_J`#Q?(hc +%=m9AV@D*&+>KxH!tqV|lYQ%RRUly!#>d%f7h>f1O4DUF{sGlENadmzZAF_JBcdBE}x;1Tfid$1K{Nj +!$JnJ=M9uDt)HqX5h=6$A|snPF=lhOeJZWGlZ{QgxlU0z(nPnoWc&}`_ajjNEqR#(Kfb`NqBs89LGtK +XLn%F$4CjDRYNNpS!o*fDyAs7okJS3h`Z-g+0)dN4I-ro)xH$V(J*Rv4@LMm6+2 +N&1un58w~4D9kfByhn2PTK89bYukv&(Uk^TxUH0mLKlY_|9ptCv3FTg_4!4t|3C+zW?<}&D=bLldK*D +izQR4o%+zY)kZ}3rzNjPPGK5OCU?D32CFncWb`0y^wi@?4#-A5K*Oj#t^f&(tw$p +5L9S)~C)EnLmA3pl^kk%g(R(FUstPuFTqP5R+*_Jh1YqoYVkv(!D~6`-SUmwcFrd9~tB2yyS%W#S=2= +&IqJYV|!aKbn#fEQ%v)Ry)3FXj^y||J3uPWa3!H6j_A{L5@*j#*c)`g>I?cG_t@oSMbr|IFf2EBmr5&|bMs6;QQ +iKJ_W6#Q5%XQ8+-@1%DF^z;;HhrcbNR9FKu>BhaQNKw(betH&b@0_QaUN0R*n;1L2 +q^+F1kxOh4562<~6s`W4Q>URlK!0!@)SDoML{n#Pq~j0DwHbqA0czaPT!S2Q?>W=N2wKuhDqn*vMq`+ZX3yx%Sgjg?|iZ^iCEAN +{-y~hJGV?tEy&B^0PXov){2HqhMaT-9Ur^HF^be`uH|XoA3bG`?Xv3eNP~6Lw|9#{P#UPK2GWP^C@9$Xr_50v1+tZcQ5%c$2OYghy!mlO+P<=gI9!TEjtBUndUTE1!xKIt6wSW;OPfh}r6p~)>Aedb1TkL3LRk>6R5H{!^c(tF2jXk=BEDGe*z30;+ +0UBh{+{xE7izsp#(#pN>;7M)s4uQxzCCvDe)l6Ty3}7x_6NBB|NO%~p!{!r&@UYu7f@XAFCtcHIts9v +TE~Mg@h+8vbTCP+j?L)WTSk5g)c~7uP+Vowb@E#Ru$f%P%u(5gZzBxUTwq)ezSeVrbM!y5pF#C<0J0_ +qz%-v|WdZ8}%a&zT%Rhh%Nhcfa~kV>ho*-)g?l|y2f8!B +J`_k{M98wzc0WNo-ySxS++ayyqxV>o71vQ5Bbw{tZ&of^1%3sC!~foka7vGz0D!7^zxEk7ye6DBKm47 +p_8uW^>(VR-4wC4LhLIS66!6Eln$)~3g(H-3%ds?TdBOPnrS!wbUr;4uv(Fo#dR?tl4dVt?;yhk +!}8<|w-y>_~D7hAn^szY1MyC-+@y&-Ts^wlLTjz0yx8Za`;}iP+fM!=>n%Sz{ +qpw2g{|}gnyELLR5~Y$Rt4|n;15+h^u0gzcNu`Tv1<#>%5y^~Ta3Ge56jxX7h@MKkNy4a1Qo=o^371? +OYv6+++?mK9j^T3odEsL7v`_NFVOFNVgBm-0{!|6)2?1pKP#0(tX_L}*RdB`r|w_`!?$IWy%KXi?Woo +gcDWpct`U3f9_@$Gj0hKNl>7ORgqe(FMhb01K|3fO=3yPPF)0`^Pgs+MaD0a8{<5&iQ5866nw*!r;Wl +R04&L(1ZB@A{^O@|H72wV(A`CpcUq_p}*S2u52vbRRLIp367GgS0byHsDBZBd6k3P0Z6e-)yDcMrgef +BR*$I@tDX0JJm3{?6|dfO>|W%bcG! +E?Mj+!p2?wI@bD1g5<^V>=xWjOzurbZ2m-&eb{c`jj+Hd%T(fLS=Z$^AmlwS>;UQgP)EY-~1Z}*YC-B +k>~&Q^1$Ce$qyxhzc|6Sqyt9?ibiRSCMlRENicna29571vWng*2BTr-Q>8nwa9mv|DI5?BY#kCoWI$t +vNAK$Og&QClr~;rrF*{n1#xp<`me3wgLHM7o1D3FLfCK@r?e8S0tkc<=npiUqKh>BatHOR^N>l_=5eN +=C>KJOBM3I87LC~w0uS&JGaXwx<^T6jVAB+Je6VqTF=*p9jbuh)UriBlI!>L~}6TSq@q}Y5-A}DY++* +*}QB+fmua@L~za96QAt|%6^Qtc0*=r_N;m7ss6Lh$C6^k1kD09DV|iAw4p6#~hEjpCDTwojN!F&bcM; +9Hg8Lx{d?Jc{_YLi8Wsyq{en^s8(9)g?l|y2f8!BJ|@mrWI>(Me_dZQaK@omi01Mf9)=iPOKxRm3JE*O5jQp6%K{_APco9A_g*lq?w1(w7jsS#F*$xTU7V<(U13{SN +ev`1<=tbu_Q6z%^_oveanC+3kg8Z1;NLRlcP>Sz_zm<|edIZdLLUxia$ZJP%I13)ojWcWpi+J`T4$dIzyEetWqu1(N +C#u<$bz{J?BN|p{o(!l7rTADVb@*0eTkwtfxswD;S}|$92ZVNOq8ae+zF&e5ins(XwXg*uR@XGR+L28D1I@q +-kX-HLq8Pk3fm28dHUi_31ms?q*L%FW+YxV~+;w6&7zKcW$P_d{uVa5O^p`;#3-YbcuX9nQy)8+iW_{ +`jR|M{NJ{u5QhmK*bE=z!4sp1&Q?*p(Wp<2ET>yF8h^SFh?HS;%x#+^8(7Ibu&qYc}8!@@`5qjzQWL< +=#G&QaVO?D$bwl$_;jrNiQ+&g}Uk%!ELk$y=f?$<1XUY;1z2bzBl->=2h2^H9AFKaA#HU7<9+hjPE|22QD`ZhkSEX5&v57or?WWZw&~X-UEGL%U}UR~%7K(6d1$x9fzi%+RwZiiQY1 +7F4q4Ynr|ry$@aBZXkVMA`QsCE!)>Arn=SV~LTQ#N4v+iGU;cAVD7lg-KD5MH`$#<}>1zcjLc`sk>j- +4RyPK>)QdKvl|BQ6(qaB6BB+SpNti`f+$oTn6-8lK$}`N9qQ5Zl|Xg>&kaBC@rYQ|Pd8?Z<}^36_lM@ +n=RP_xEJ&TcXyk-W2JO;;3;r+Ek;8Pgx11Qj^XGO`^14o6*Vc%)BPJ| +rB6NHX391-2l%@W~kuh$_hu7}8^)e90o7j(2_?-kq&i0`{-t6lF09TOgOlV-dt9gx6n$2r=}ox1JP?s +UIe=ONuUg{2;|*Elp-vd4+Tn4{5h6P@TN*&Asz)y677Q}uAR&YP2qiI;Ss`aAi8<2_!WV|wpRf=-`y*@bU-ELDbsd%dA~3hKzeZYXl?mjn{a>w|JzaU+Bmb;YxCt2sMS}0^_$IOz$kuc(*?qo_M3$2=XK8Fhoa%m6~qQI_^%H3i3 +@we5r)4`Om(pa2z?%)4tRXw_vHZ>^-8=MeDPtKafaSAD}ZeSsqiB{dCzYm4#_LuX1rPpKD|RKW(dJ(u +EX&_Ys{N@>vtOgqy|5<$v6!=X-BsDXp>PSQ(A)tReJA}kxT+a9Pw!h3}E`Hi<4{f__Ty<*N^#rs`r+{ +S=&iPpc+}C(fAv!k?jRhd!^CbMlqTpo%v>!pCyhjJdFB#U#Tf;pyNqcQCvvOyTgFx&ED4?g59Ef~C{c!Mfcf$Q&v!G2fX6ucedqQim7cxbG_v3Iiy1b;a%VVqf(8G7Ivftw +}y}$-JwWX-+$-`Wu6RCDj_~LSRehHoBEXTz&#-A+ZV2_4$lEbd+oGgTH1X7+4p*=dYrcS3|r)Rxp?-B +bc%j`h6mEoxM8S%I0=0Z28y4achW%s~vPnrZrh#^tyMqTAs+rGB%k{I5hu2BIJ#ka)B_=WUNw!G&a|CMaa>=btGymMc8L}VlHxOPlJ)WY^$bM3k2Iw^L +dCeufW$vQJ9v2XP$AD;n_tm|!h6j|Q?@oq;!Y~QxuU7v0I4mxdoeRO|H;QjAB&Ib(s<`_SMAWc#TO;Z +$2Aqa*c1OqcLOv400FbG1U7=hCm@}){>K@@<9$l6<$0>ze~Ad>`!Sp>dzibDa#L=li~`$Y#Df&pe-0R +k8zD4lt07DKGYlM6=D0NoZ+yztfK{}2X6Hp?zy;5z=Rx|!8o9bH8|Ks}7FwqPVMq5!rSt1y^Gz-;0Ih +rqR*T6rwFmd>nA;Xulg23QS5N+g(}1bmeOt=7}ux|s_!7|{FXTY}GYkZIgn4;kMHX)4?5&PkhJSy>e2 +pS{FI;VmBn@Q6d={Q`yu|6Ki$8S5Oe(qEBWPf&1*uQAVlcUW-5LgU#FDD@qHAkSlNe46<~PJ=A*AN18t3u^c4y*0ap?Bssv@uQ76osOSgj>^VM69xSu+OMYr* +E-3RyjlA2|gpqI0z$4#JN+!MZ#YMK(7qaCGu&%FHYGd~Ht{D$-lgmaj6xJu!`uyuH6w1_x3^Pfvwp} +*o6-YwMcQ3iA;w-&ZHn?9E|O1Qt}H*o0vHAcujYS)2-pOaa0o14kXs$JdT` +dH5J5>g?rS2$J7OKCK%GN&9>Hkj$l3(memu5;50h0^|oID$f&E)!bx_R3EvI&w`MYo0uo{aqjj7oBG~ +BBmP`(<~-i_~w-%mtDn+V@^Y_W3P8S*PB$IY4WYrka^d{GJbGsJK8?A`z@-^^1V`-F)+JvT;sB(i*RmT76zxP2NE$P5RWvDJmRJPP9r$Uk)iujr +!NeEyclcLa6vt&Ka+#?H^4E{m}e>8 +Fy2Si^e=>&z?!u}>sizV}^S>_;SABokzK6p9_Oq4><-Ten-W&tvv>N0AW8S+nB=G%yqG<6#`^f$H42g +2$O3%_Z275p7wM}7Xj3<3)^S^1PJ&OOZ%-zIU^TAG}XPgWjDYuERmT(hB%Qvqk<$kxIHMOWjL4+K8^c +y@qtFIbp;%$`Xua)U0|{sqb#70K;g><0SGzkcN|`IWW@`a#^&Ppsf&=a+7lq`=eC{19EF;s}?h8yld7M)gh=m_13WhFaA2PwQL;O9Ax8^_%a)`(Fqw +%|Yuq~KdK1m9^PbslYn(MNzyx@f9?T`1rZ{ +?KVQP~*X$zK*BZ(x*$+linF1bPS6-e@kzGOpo@HZ}%UKC$HyJmx1`OV#tRb>t#t{%$fi$^^l}*++xsH +`!@S9|fij4;0#!A`S`?vLG@cV7O3mXnx3$c>O`mB(%%PquB?#fCun`CSTmMiRXSL7>LaoHdOpLgIuOJ +oJJM{WHa`sE7CDMkZ#14nd++k0?n>m@|%3N9OE%LdD}#w<94?)_8;aHJai4!{m%1 +zh`$6|P|U6#_?G_B4P6hk<>ua>T|1hp{}q?11gTr6uc*Be3BMEDu-?VR;&ySpcy+jXh=TOH*X!qgpGA +*dYty<>#JdVY2+#zkI-;ub!|_3AnNutIK)apaaADpPmC)H;z9JX?sT*ei;91t$gDKVEHn%bq?Y(pFS5 +%dpts5FF)>N9axJ|JG$QiSf68i{M1$QCofO|Efr*xBDb6_=6AG<;g +*!R6qTOVSoOsJ5}+_E#yfXly|!yfxE3x_KsxVPzxF;?FTga0W^j||8~utF)L#3oXVd;1z-yF0V+1?!w +aZb@5S~&v!R%+w|o;^9bx95kxP-f_lYP?%mQ=B0%>_9lFUB4r_03&HTNmPFA+2M!prGr?0OEWSm35lB +vXMr=hsKwm8|>C^6-amOA$xd=kakTur~C;xOwykXak(^oqfKM$@7+$uNhoZOJ~RU&F6j{6hNZ+7Bxzh!e~N3)S@i0a#Vue%|(*{KqFPe){nC%J +qV35}huw@a5$y-=YrLT2c`oin48Jr6&OaTqd%w+$eg%s>>*z7~ePL&O_r$hXhC>ZY*j +q6+@irzxnQPcF9a)+W|BTD3Y0txEeB|hl!Z)M_=LHe?spE`fmuEL-WQN~>p6{sQiNq^3{celf*d3m;48pYE(E)dS7w3JfD< +f%|H2!hm9>B@9tCoCpz06@GCh2?yvN~HLXv_hIAm=!yv_bb)t;gqOgZ^n=% +Bq!7ELju!&>-`!bq!7k5n|RYn!k@}?63^uZ|Jd%?|+W8p?@HwSAwIwNBUsaWw*(4s_PHb{cMO0W$olk +A{8m;)+ta#Zl4nV79PVKolF@)19~`*65` +9;B@2Qsf?Qbt~23BbYd78V8(!7F;O>7ZaVK7I?fwkik7G7-RI_U%D2)O_;A`#b7zK +$&qR5=)=xr6QUpUB9eaisB&(DfJ=TLw4p0x9&A^B3196A8e0h3t^|_-J$*=A4a7efC5tU6&_C(vDY +>mzDfq6Zou(vsIhPpKe=rqZ+=r6HPCBG5^J;&+hTu1!r#Bc9UI6OZ$j(_;e(vAg?gyh+GQJ(zaBz00< +n{P=k&>{CvAF>iiemQ>w@9iXd7jf`O+b54tNcX>V#~=9k>z)4O)=qz^Phac7@!;D%c>_i65K +-b!I6HB$>#nTZiedJx~b%h+tC~7`q{>-6;`+NwH;5prPB^iERN;3$_Oaef2!9<`^hu56mI=x1%zN!=qf$@#LZ{PSf%;5z;@m$7P9{xg>Wt=e=!`DYx+ +A3UicxYFHr2hoM{fTl&mB*NK??K=fpqU*KW!XavxQo}VjwPuy8<0I<1PWGA+uu}hYk;v#M=c(pAWa`` +FmAWsZ$laF6A!_=oqE2qRSzzAU${9J0WV3Z0w&ymwJo9Ziu&3aKpxKOQ2W0Db$dS@qJ%W% +cs`C;&S1-O@AShr52N~Cw@g)3{czds76*U*F{(`!&5Hl*tvNg*TR#*dJmWrAv@i`H50&Na1--+NSmr4 +n0YS3FSdgmAbE?K}E8Imt~3H`fR<@2?#aq{o2WoCsr=H?p5k`yGvd*@)ZD%r{cZKZCwzlz1#}%tXxrJ +3C%kcN}xN%1}QBXjt90Kek}`RDL!NSQS2Bo`Z~OR-CW>4jt5PddAxPJ#{7W0xJP*TySys3$@6X)-Y>d +zFM;Uhf`O?)IP*55e#_ecyuQ2j~pD+T!y15MP8aFqc*3k9iND%F%&_v;iJ1j{XQo+Rw*XS++qvF)q$X~jEqc@J>1kZqV|je?H$>l4@WZ +&`twKM1YMbras)0{1Q$B~;sr*Jb)DT(h^2#tr<$}Xq8ohM)z7zFFTa;1$s_POzs=GqiImpg*^D{>Wq>EYn3<#>J8EqU|sUH%{P$(#bZJMj11G&HH`*1wopCb^hN= +B1pv_i=m~*%G6Zu-7{0vyRkM+`oFGntkITX<6J}M6tYSpq;l=MA6GIS3Ur0`S5I4U=!JC!<`VbR*xARs;{i93Ao1ORgY1y}}sF#u$-3FwNdFAD9I+eaY##{N)5xafEuT({4`rz^XJvJeb%jMN2c$JwD3U(_Nujga=L$j|pj+>Jpr7%mq-I;S|>zC&wxqzrj}U$%c{R$&@LYRDWWX8w4a*$ +Z^G-S%dFb2zItMJoOoH6ip#e2?;SrzhRiDdHq~v^zUMc|rU%2ci|k@ +LqD<|71$KI(Rc>41VNw7H>6Af!@u4Vr4Lw$1`Aehl`R72sx`m<|zJ2tEuB1C3lB2cm6830=>JIo~Yqk +UU!yJ`{{n8w827v-0Q&B3`aY6Dk*a>zYQhdqufb7B**=H*##R}E1}bULBaIMC}n5BW+4YN+&FH=xY)&@T1Gl9KsgWeYpWR}%^k{%#ciB3ChnC-{5 +(FFNQH&TSSq-DgNqooqiDW5J&;Xw_F_IG8$P_f!m`|Tw;}Vh-5&01c)C^NDZWG|cZSOobUGj>&DtAcl +;!wAv#QfM?A1UqG{XCrh(>woz!ZaAvSXOEJf3Wk5y^Z(~}_5p{#UH2y)1i0C@-GpBoa=(Q3rSpXmRPONfD_8vzG8vn1u|3k7cjX{%76r$0XK3Cq)b5ybnOuidVQy$Ops +hLa(S_U|WHD#u9HtnaeUa&-&z#=jLZ?mCbuCBC-~-9-iCyK(fOiY3CLDy~=Q_G +<(1&@R85T6Z!iRMVy#Mc-V-x&~aapHtNVx$nKoQ~=^gTwJt?$GB?NH-D#$l$v +-nMm_-UE8!#{QCw$5NS40@jqQw8oO1hV(^(Hy(j+{*I6un466hhq3pNPMqY7>3;UxC3N=C#JvbIrZ)~ +%72B$Z$(ep3dZ~j#+k_CwtJ+mSXc-;;?rm^V=(D7XbexZOQSkG4PqXY={?`EGGtGF$h&%{_{4qEU4c1 +qx00R*sE*qlJxjgy;BN5PD=nKtMJZ1;X771RY2-bnqLy0J&K!`ZWXr2ug)= +_i!{=AMbxj +_#XtjL(SEpWq(J@Bz6&E2_p5~#x9$Thka`Je&qxFU +9_P3EP%t}l`qEU~1N*rO1OhUe9{eum)4y^0~*JN#U*4p4&o9LX}9uzlnxOm#;C7qDMB +UoBVjZGQX03S0`2JEyr^n@0a!jAtcI!5!kPGL+zaphjcsgP=6VX=KZBk=T5EnB0R$Ot{r0nP73JzZwt +KZU3$=+x6ZrHiR0T|a+_u{?!G!}ofVK>Z+=ucOfWzA9J>EU3m#Yp?_J-b|1VMN5pcMD?7t>$HOm +@wHD=b&m`CGa>Dc+%2Ck;;(F3mp?QrR&6@llr8C +cAMYn4;SN`esV~x~-Op_kw!`)Alb0Gg4*tz+k3!KbG0D_$9%f3@ZN95UhWpdyLB}WLh@PB{;K$_^)lH +t4rR4G2(=5{q)e+jC`>QKkUdxVt>RlPrH)}U5Giw?=&1${Z5PRdJvwJ^<&$zLBwlasFCQdwGRQ|zlq3 +o7oWQmcR=g{Bn!ZnaEhHDXYkzsi5q{WB=*L@H^bS*9$@u;7l;iIf?Ji5lnoos8Z+&Z=v59Y)h=3MsH-GP2lG;k1V&s=WPz8~@peOJ!P=lRB;A +nWaYYw?U?-SYnFEQ%c!iZ(e3mJroVp`v%lSo>Ub9bcv$pS=jT~B?zvs4$;fT_Jrk7H9-wdQGyj<%DhbyYA_=o!M|4#*CDG+8=!5?xlH%b489sI|CuY>77{x$lKf9?L`U;p^qANIfh+vDH=t@#66 +B0Xn$T@_RE2UpZZ(*)ky3_BjlYJI8AV45QYJ)av|0uAYRzXpsTaJMrpgyqtdkgNPn9GFXMw +*eYTG7a06D+TMYAm+d!SAWr<+v5;r&?sK?mLzv?qNVv{CI}OMqO5QZ-sLxBE~J9BW5 +-$@@oeu4_fy-=I*c`v~h!VG8;!xk_4ojFm#1hkm=lSMU9n +l889?A6%rt7}jPrPvgsp|9a>}D?NP0*WOuFoTEt!UC0g7EOqx0~i(2m8ZhP29NyG4kVqb4|DV*lA|d1 +_}Wi;}2F5EVRUyYBD@|pyW3n_e^&=w_1b4`Hb`qJKNaP2nAl$Vp&1

^ME8S4Z9H&)n*NrY+{|q14hl}l>@RmbZq|9 +FN7%gG;pNh}sF8Oq<}9bb?-v?#h|hZj+`Pj=X+G`=wA_@@7C7nS4j&P(i_bd98}7nohim$$sUPceBK8 +Y?;ouM*UqMr?&k6M7gJPYCdHGi0fg0z58o-e}%k4SK`GE@#Ltvx3KDOU(KJ<3?cXP6GI;38%uTGk3v` +bF;&?A_hBedc{>~F}fp~-kd90a8;z@Ih2Jsnap!YTZo+^ElE#%tqyqeCFX`0yr`Z!>B&{Qmb@>a +BI%h*oVWBT2``fDp_2+3l+}>k$Ziee9v%({Htwbub9m&@CKtT3aGLXTbjXphZLOUk^b(SX!G=cYyO=x +O*?`i0orZ@7S8lp_qY*8V?wcUYtMusY^Gsvz`;flERATPtG?MIcT|h-nllhquA(nL)I^yt6gfXlyS*6PUg +hSHC^nxKrq-q?r*E|SZosH>b317AClh^6H?y4jK2!dBc*-ps1zq9u{c~G>1WjLU^;`4hkOt|uB@{?u&@E_zd{CSmuj-5lOj=PSkR?*9x5qCm4wsl=Sp~Rht%{8_0#ZmS +1crtPy4o?*s{|wlJp*G5OtCEsV{o)zH9|^P$HWLsqM>WbafyR~8y5_$mZ^0H5a>B!5Xt}}X9kp2gBd# +p$VSitryQZ-%wh~_T=#)*uGxA-v^I0+ICp}V$5R +{iQk%6h8fAwKKk#5D?vdooEzqxlzJ25RLMwpqo*lo>v$4QpYtTw}Fjm>6_<7l2&!0>dor?b9NY|f^WO +`a}IN7W@msy(?OtauY8s6%U1%b2p_*@T{vpy@L-mSj{Wo=LNJIfE~r`EYjM|1G`!t~o_r0-1Em39!8dFj<98+l5L&MXXFOUKbC>Vi2p>_7_-HOV9Rak^EGEh}}qne|uO1e?5-@WMDbKh(rLCsCdKFE*d +S&d(>p2`W?KZe*ILn4)BcB3~I=X(%TzJ$4B^u$yoYkj{mLZl52>J#FkUMCPb_3+SB_QQ39(vERFqoRL +6Q@>8+VZPpBvr^A{_UQQb10OGyeB>xe?2Y_;0tX6F|8M4LWwX9i*zgfn +IY``GU}>f~>()~E*i$*7>i1#dG#$*ytarCaeS85C^G^ef#;xpX+?JYi>-f}L6pLlI-Mb(H-2mqAA4q# +wEXZ_@$Bx&>hW|KqrD-yiC)68#@RkRVWkA`ylG<{&VN5 +Y*QeS`qN9MAv=-Q3%A0_}a9GUP*OG0jG~30Sq5Ter0D#M{8+w08#+}$3kG#vHXvNt^x(7)O=zCUUTzF-*(&UewzF#kQ=uXL@{ +1Z7JvP>zUU&t}}H#w#PA>YZ#aJNOX-QbNSNOr)v*T>AxPufAltZ6FeSOnoFD$tx +K&%}Y2_(;90H*r(o9n>FtsmU@S!_-G%Sof%FYu{p?YPN~HO-2#y_)PlSc^jvX=XKt9G1vA~v2GJXC?&tJ^E@J9k~$1uqN$sZk8zb+wW1yDkX6}*nckr>(rt}}4{kS2HmV^VEX0v^8^{r)=|a?b^o;KQzO|o5jo|IH-0o{|@ +AMNo^1)Hj?Y@1UdUBFuvLNUtI@F>uKW1WvHkE>Q_IbybVxuE|`@Cz1G!C&MLfUH>k#gf7nLFq0cuzYB +ntrP!?PZ!{kaH7%gAM4=2F&@TTgByhJtE%xVmfjx%w2ukEBETDtJ$&k2+?Gu>veY`}e$XfV6e1BcB{|#So6-f_9|;4G^Ee{{ul)EZo-c2t<^JE(L&>evb(GLWB!GY=+bH6 +>m_)NV!A>UjeB`B!f%eaX(1NWEYLf_m5o1Irt8&2wzmTbI<7|sqkHL1(Pa0`xD6q(EE3iW;SMC*r;y*3tZLPF+`QqF1H*4u1H;%vAF7 +1@a1)$_fR^|F>Q*+NB1xY@5)b=b1hf_x_&J4MChI9KKlsqtoa)HNMfm5bPo-T_Xq8`1IGN=6HD?9qG0 +S-4*9QN_&qi=802AkX$~^5x9~L3$`J5=r<#SI}=7lNt_QSq +omR~X_a&u8-9HNr)REcyjcBf2@jaCUtttAZJ3tpqw-ef1Bbk07EanRgp>xd)e(;mjAkfwEI+gSMQHMc(JJBke49Pap78aO3~N2=%cK +}T%7=R`rd-^%&nNC$8!So%?YLi)uiUA&&m>6y;-ek&d6D~_dahNaQ`JX6Zvy&L +^92&>%l?h(Qjg6)IjA0AG%Dcy(S=caVaJT!N65v7CL*^)OJw7Z2dPK#EGG$eVV=UQsk%Vic>Ynl*Jb<(5wbENgQYelJcbP%-p%wh@UkPoN;dcHe2(>Pl5KR5#h*JlM3-*@9B5VG7`(Q`{Iwk($5aVVU8TxA!#%EgTm6IV#Rkr&J#;9~^hQ +3%M9b90(V85s>X3PF&Eh-CD8@aT9dXV{Mf=Tml-Li!u`tI$7 +NIto)>LNWv}tq+e=Ug-PqM0dX+gMjNn|R>DM6~dI +zbwZW*jKSVIy}B_>`p0oj8yRw2zT|KWS0#h%zSxuyo^@t89%+JlelFrxftuNeA6#B-#C}>I$3)p>HI1 +A8lSyr4LZCZG~JIoO?^!4H7%m_BISR(a_Q+^bzb!dgP* +^xwmmNEBRF9|-^b|y?1wyTZe%vv9&T6_fx8f!t>?T-#(e)RtX`c@PIFAPU~ZvgnV@Y}NT&qw@xKOdheh;s)!;*gGX3cjpxCi`kO{5{eHJmc}Vd9({jwG36C3tVe&OC(*36ytQ#9(E*FKdof@5!#pN|`A6w7=admT7rMIu +^OU#ERJY!9$YVqDkW-Ga)=)j^VV3@rdSE)68ae7_rygLQ3h*v*@6`HufdRdsTmu&BiV7vJYoE^rGwx< +%5laFtd))4RKS%E4DoR~)hbTQV%7OUWK6BUWaya*?ejo$9=*esKUB@wO0d +ip!`73sYm5fVb)rp!V&gm!cy#u6+l3H0uy++EO3q#dH0{~#UAbu6V{n1%w;q#o5#m+1Ikx9>+3uE$o>S-(hKb`u>lgKK}a_@vnbY&x*tj`x=W +;2nVr1oIBc?qF=$D|b3FksyBQ=2c<3-c)OqGns=Y+UKggHLK^oOiXmNAcT2&4{KM#lPIVVISOrHtCW- +r0Xkrv`y0XfIzUfTm4>M@tJ4*#VtN?<)`I;{Oyk~Hvg%hk@>Q6Fq!PAl3@yTIYJP +?0G1&-{#qnPrE7N*zM1g2YIFloHNt&L1=ybR+7PKU( +c)xUvy#kxj5f$cEjaF)Dh}t7RsOt0eFTd@A;DzgCMkVdKp{@Ri2=I%`lk1u57qBYn17V&+)ylwMN)=J(v`5L +C{R4`ZPe7GlvO$ZY22T(cIfwagWi$-KF-U_eKX$f5%;hqH!(4xweYmws8CAS6#_@f*5d;2XqJ}d?szWEq7L +0uJt2wx()H*;a9+X7Tcb8DCK{lfK}6;5M4m3FyycHc#js*|#9m>DnMv2wMsu4q+E)eBJ*&ks-UjIfdG +Q-YSjM^{?;-OfmT_AOPw7(7s7wqA0+KcyWr>hzgw4gftS>;f=rx{mu2}?_>wlA^<+TQmiQ +7uunU|g)>TLojHDN^`zQKIFZx~@55vQ~?ih3Fjb0bH6;wI%rY7hUE~Z`{P)Z +71(W4ljo*Y=enV=rao-z=WX~|DEKt^>(dbGjUn8Z*HD)j!pkuDepzr^emZ!0p#BM=&|5bSp}t$Pj~T+ +FyP~lqY?}jjFR9?hj&ns9QnWoCp4a6og#=xEoX2Q`&*XOCyAAKZHihbM`n_`A@`js*$n!>@wBgxVR{X-vs5!;Uojqff9 +c=6p;*jf(n&SODNoi3H`$!6I`%Zj_Er4=P5g)SDfIxy}=$$H9kO(Yj^GOgDSCU +(<41h+N_^aN?3U2Ul$5V$@R?~=J+U@;4%HOE9&3=kbsE$+xkiytp$nijTPuWe*WZdf9$T0KZ3W-=Oq5 +)xj@*pt*1{M>;H@6e?aX&b?l#OC21INJc?u(lqN_VLokNMVVXc;hM@?WCJ5$BU=9h8p#wT;66l4HwIu +^VgLzpB201r$^`4G#&;bel+HxAkfJQor*Hyy5C)DZ=9Rb-9@z!i11QWhmKV#lEI5sjpd>Sj!E1bNa7eETt{4HNF~)xj%-gk9V +eq|HG8msV*G!4qb4-ye!%=pW=g(l(y)}Jkgg-ZE|JjQ&u0!ObkiULjCVVs;7W=TGgtYHn5O78O)5<`2 +D}|VnUA`3^-fExc5P<#*sCQ5Tv`~Wi;ZM_BsQ3ETph@1}!qaX_>|YmMLTlCKDmahkcfl3D>~L5MEx#E +XXxI`S450Ut?okC?lbcVEHBMs@LuBQFbIDb+0}y+nH|0-06WaUb!L*P_l6Z)-N&xDAwdL0zN*iQsk?smxKjM +O&_Nyea7?QN}9GE-6`(8$8d*Hskt|k`+)I^oe#xvdxG}O*j-q&c4}{vCYx<7mPtQiaiqYz^TJ`8?SZGB4{L$Z{!(VKmxVh +PjxB|2>11RNkkF{lxIS&qSh6`*73a?AWpC=}es_&~{kbRGw(cJqb);^ZD(<%2eY}^QY%-Y}r%S{IzBFFCH{bZs!r4_V!D#KlWDQ6j}LU-g|&chHJR=|XG8emJsYxwL;YwSkKUD|lD1%467QNMeW +CrvJ!kdpwuzsCGBHbJC*Mu-EIx9TJ~@sN)3vTU95lNmN3*mz^7gFnL+N(E4j7u}5t9<-^|Yr3BB||MR +g2^(D)=*1!X?C|0zr;zp)z%-dSOgAUeHZ0>hfhUIJ~~AUWi36C*JuZrl0)teF@W1h2l)@d=^JPh!z?i +n6j8WBmrViIa9h)UUMb4_hyT +Y4D0$Wb|_EDUb?^f=SY?;=;b=y`LnQ#L2bW)2Vtz&yA5Np-T8hGcvOPATUFqZ_!x;9r;*Jy%MTC968p +a#7W8>A^vO41{P2ZafDri2y?y#$K4UQT$4?*p)ezu+_pv_U{vRCYM{uW*1;8;BCMlFg2^@jp4XnM05U{;{~+A?;5R?reXTD^cU(Bm*#jrM>&EA{s<{ +5wVi1y+iKV1fVN~#6Z2^eIK5gO!nm#Bk6R-Xn6;5%@pO~L>4D%@JgHpup3;25AZ +D+Nsxfxe3dc?5z1+a_<;UE19sWEUd}P +>+iwm&hf-Wn^YX#IU#g_tR!2Kch_VH|@))z~!#@FRdx0&!0h@$<9F1E-`MSTH_rwoP8L}0>%5U_3)C6 +~UZ`r=```Hkd*ucpqZFULWSw&ppr%Z$A&Z4Jr-`YKD;H;q^Px}Ye*Fl`Rp +7G3EtSSAA8||gagTn)ZD1Gyt&Zhy@yVnuL!!uDWPs0e34>98r{bc>@``ZDSn=AQqO5&-ZMw4)CEXNxu +!XoJOs~WKD440l?xbZn+}j6Rt<16&x7Y1`ilhx9V%rwGC-`GWH+QtnvwF@Mxow_03EhI*b3@(dNaNZ< +RS-lqf-Xh-;Yp91dqL3KP8n~qwV4|4z3$~F4G#2`2@5^`9!7--x&;Z;njL}bqTL%Pw_EG)$ZVOl0LcM-I1#!W!$p0!@suM%hjR$d02 +L$*?N7PBbPZu?KwNiqdO~zZsW*xgw8&uJ|3{6x~9HIo>u}bBJmYpjuSDlbyAk3=>Ah?rN15!u`dSRpU +KfOTE2=X>HZLkSJ5p?w%>@@|6&mMKXWd>2Z^6+b5UxE6M=%4AW0fQ8D{PIw}1nQQVaK6a092PFDc+Mv +LYdHIbFtAIsk6p3vZ<1pI022T*3alJ +2mlOTATfGV>;HZ8>i3=;8dpKyxhYdHqe>iLtbMq?-`1q_i{XJ5A>(aL%MGAevPJnn8UEbHx#EHS#zeV +V>{0oQy2(t|G+5a@ed?=Lv8pOMbbv(WfUhyiB}eS?_qef~=p$Yn*!KNReX@>rpq;~h9+r#k{qPtg|$X(dBaRX&hw|U9alO`{1Q +`%)9>_$V-3*xAce%p-q)2X~&US5f^{SiKB_okZ${&+Zua!lx38oKy%5m8D}TRTD8ZN)xk&LMlzV95(Kl&!2lOC;BznP&9)VCp4}VdgP#;jEn$`4L{a111;U1kwW@O%~XD`emYGh4c9s$tYuJyY{(GbUvBPjvl=*M&st<*_Wg)4+sv +fJjt?VTGs8xV88<4=Egx8WR-6nu@=?oTAm-Be6ff=0y8%u6>(;g1&2`1liqLN}v8TxA#E!cyzfpzLIW +t2{C*b1gZz8s{=LWT)rKse%_w}<-Jf_k126;Jp+XxGHOT05(^|DtU&+Ovgj>3Z2;@vl;HXy>oF}P`C< +y6q|-InhY9R3{`hTd_w@#g1M=3^?gx0@2*Cwy13+Z6SppVG?O*Z$K73!yvr+OV~CiG70MgzM8FY6n4Z +Y`9ldG~7%{$)>`G`JQ>MKR@?lx@WOQAQyVCNva3k`A+C9&p2WHL!aHwTyfwyXQyYYKa66?j_|_jiy0a +IWgE`jwVBJI9nQkDj*cl3^-xEbT0kqi8+Z3t(k58OY4TaZSe!_rv4mhK-^GP8n%3{hogKHy9KfjMSZJ +w)azVw=-jPkUoE{IV<>@AfcjIx#u+g*Lm~-AA3qDpJEO)a{ojHcoV|qLvelu7U>CGsGXF60kGET#T(u5-DiQ0S1f`gni&^^H~aS-*TF&8{J1xhH20UDz0)tigF+}hWNmZs`8D^1B>y(@Yyh +Vyy$?>YUZ-J;y|eg0H9KMD;Q}Ru%g>Q#{b}U+4^qk?qYQmXDP#X8r3^C4(0?VR3^K}4`W~{qrIaz<7R +R^h@<&Q}Wi#T6a6hM%zYc8qmnmg{{LmVf{_B+T2QB)yDP=&HAid>VEY|9ysmcD8jwzsrWab!K-Uqm(A-BFYsHn0^* +o*<5U{=A%BwCuI;3UxcJi}*Ps8AP~*Ds90RQ(0Hsbz9HpNk;vfG%NI3p7nbZI5#`EiRotTwSB@un2p> +TQ*T7~?CR`YhIsz%wXaVWSTtsJ+2D2A^1Lv*^9iZ-!y~+?<){#fZ9dD{sz%=5cI|m7BdwBc=xI>(Eg2 +_8+vkrdkJD694!JrWui;SN%$6B?0T)g-FKvpOzKd>f+$0mUxUVvHQuhyhqN2-P4zWa{NWkD3pM|XZS5U}{^7R1!y!<{B +q*H1aG1sk8evuxA~A|UNgRhUghEOBb1PT?ImyfV2>}5ho`6~LYqUtmuXN>WPCbGH4HC#QelBpuUdq!o +V#NrcHCn-fLP5vsy4d<}NPyJjdMEZa$DRUa4-xgsZ~jtugaN!-@dJ4!QP(BbNESF#rC?*}%btOJrAU( +u2#Qve0_9KwXq(mumwFjO(60et3=CQ=qL-$21u)>E_4l!D4+O5H{B@>1*N6cxufduq2+dH5MI$LcX_3 +CfwuAjiY`d`T2Nqp{>gQ^M33(qO+*dDi4HBoo1D&T1dcCce$oFgUF*uvpdZ}!5`#v7ur9zANZP@mD9` +yFaFOl;FKuR#g7p{1})~2;vsme=(G(`18eA}5S&Ws0rb9OhXuRt#Ka<=+MX0$&ByuXNdnNQ-~Go*9Qd +%$~iYj+Oa!y`cP_i%Jlz8Dn%@Rq)LL*FNnK&nVw6D3)<)K15e#XpeV`lfa){rsDF2RrDm(C)oW`2}{! +w`X_z@Vx&2cKB+1{~LC=pT@w@XF>3UirBdkxx=BmAd?quks>U4y+msMSS6`Zs|S*}=D|^2B#7zVs)*L +0DjT{Xx`m4avz?xIF?m+Pv+OEMMYolq+>ZHiQz83_SF*h)pY+SF$Xic=6qM96iS|@U65%s98Y +?h5dUI2+5hCk(l(N+~%&TTVAq-|o&=8$Il3mCbZxXZUBUYbNFVs6(R2gQp!(jN0deGE(F1Y3h|5_ +Now-CmU*ZjLYg7%F9oucenA1dQ%|_gg3`#cN#sq>AdjHUdyl6^z-_u9NyJY&`$PSE$*VEZm;n4lp7U2hVG|Pqii|6tOcgpPqXAbY+Abi)XDu`t@_+Z|~Kno`q6OlOuXs>fws&56^7RDc$Uz8>mfI +R|EC_JLcwHGdvPxrXZAweasS5?lxE6B4KPd(=dxgP1ubc#=izd0@tJ}bMOaC>Y`w>AeO5)QiW_-{a-DA6(T8<@oQ0<0&<(^*%7`RGLio#w*!wZx1ZVud*$z+nIV^C}B?eA*>39|% +r?A|dMmbmm=;ncjhR3Li30+O&n8m1jINYof +p?~WKm=_v1KB2HABbIm`(()b6N{||ET=GTP%aq6S%CH|d=75^6mhWamatN#V}`4iFl7km7cb&(i?V_+ +B!P9p?Hz$8f$7=kb~LBPn$!blv3iBEmBun@S^uhc4iCEP*uAHD|GWUs7$2G|es3Z_vo8uU}vwLX%(Jn +mNtL}$SA3PS*4qZ80s#3X=Y#VIpG5z2 +`C0V;4;U99T+qK^Tx+!a!PKCC#JC)1G{!HCYni^KZJZFjEWp@h4V@9co*w@EO?BZf$OHt~#EZWyA1za +07##A(z`hKHTk=u2Mf`0joI`l!+ZzbpKj^>m27dbz{?!`@-aqKS@&U=a@Zz|#ZRM-syy29avn}7lw)BZ+q&IBXnX1fB +lx*SS&h$$tR7^M)?t}J)jwFD>pI;RIZNv^1ERoFIqM5jb-VfOkP4}QG!}>=}Rh>obN<6_=($x}?jDYm +W_t}x0)n$j*Wxo)(y!NF#o+1Gc;rom}+)cBx*fyyU;S?K5!Jmxg5YPuBIxb$#R4f)nV!QW?JcJ~37laRLK-_v(T(zyw%3+#snLIy=6jMxWII)BQlh*UzJ(!EU@8Di!{{f`0P^R7Emy7mo{^ +Ngp10(r-(*N_ncj4_n|L^uc|Icpt&;R2FauDx_@3Za&jP`d2RF^RM&;P4hm-)2N{@;Fp>Hpd1e +uv(Fa^CL~?F5daVDcM6BA-gRVglsOSIo;YkTOqRb4ZgnhiepQs8*O{QqOI%} +H)v$k(;<)680j2Yh+?AMrn4Y$Q<@XZQ*WvL&j$1;)#oV3Rxx?P*lld6$AG%8uh;91l7KI_kk_-`ZDwV7Z*-Q6_X*7jfW~mQg#0MtbbR7hrY` +{@MaoQgcg~$aL?@WN^m`x%B_@3A28Pn=br0@_dd?|Q>p4o$q0=NT_rlqq^=tl?o{v@dYhQtpoanf5N2 +WPZVlYPd_>mLr#o(yhrjq_M8yX=QqA$4Gz-KAY`GQj@p-0-9eTP^oI@JKrV}1lcaKuz~CB$YMDDWZAqlsUic6}mS+3(GhVjJ3l_MIiBo%-?Th(*e?IAKs +!bVEwPeheCAAK{=TI?`Y>W_ZW3N!cvo~)j+4Q81TuV$)-=3KYKgb$=LR& +T#;MqsVw<8Y}k`!+#*&6jb;0bc86DDv#{2;HFz*m75Xw$Rs0=2+;V!{sx6Q92mU&8)Z%PW9dekBfDrz +#3-SAIOBJK{3`W{9_*3@FxO0#2bbWJ~sm3|0IsyQ+HA!&~~hU<;=KL$=ExCpm@f%o@)h!?kdtd!b?d=3%=qu@Y +n~MtLLu6>0oJDl^R!)}z>nHSsv&H+v}MT9(GIm1E^Lq;?mY^fOBvq}UCP{)%;dv#I{JqyGWsO&SjT&4 +`aT@}r)<-~;4iINCN>k8)bDmHugGk5Vc7kVq|F-YuK!-cTaw;>lvsay&<_y*Us~uLum66L?=*HW`18^ +=|17nRK^h-^4OAtf*EosfWmyEjTq<$UQ@lpNI0|r*{=DG5LLg8)qoCZtAV9npQ$XJg2B}iO$0B~2Dy> +l~0LTbHck+sZkzY;00OgAKWu}3@CX17xNV7UawtCOH$L1usJkvW5cH}xT+6WQIxD}Nf&1PTjW_@jL^WD8=dbK|=Qr0Za2;h&8>klh)izrpPq3 +ia!4uUqZ7H{Q)BclHX51yBiB!CB2$I9+ddt?v<4;Nd^YwC1lJPWpU!p=LfEkoy@DKzkFo(+2WseFC#v +y&t4~b~R2)$;Ka+((VEFJqcE2a|QUz8Y6n<8eC3ARGZhR6dRqd-huw|S1$<&?V#_)+`y#jSItQ3TQgD +)nvvEwTXzEjU3uHHB($66;mr=$h|?{YpIuT?4k4=Axj~ftxDi=PZcb<~%ElxI&%(HhPxwNzTxZbM1L} +`Xc5%Af;7KaA#VlOrRU)chOAES8bv +Ty%=wj9>z7l7?)j1>IrH5_eHdpIZ9Me%(xYLvO{iLUbL4+Q9W-w=C^H`%;{0d6_l +v2lLn`2`qlSo-I%#qpYLK^HYk_wEdAi|7p*p73taeF`NXmFUN(>Zf45!y&%5#$nbo&zte9}5o}lySxP +#X`G>yK|A=!tDwzvfzn$Vo{!+MV`xyh2tlBQ)IRAC>70@iUY&L*F9~mF{@%WlZ_?q{-N?V+^?_t0Lk? +^*yES5jz&LwZ2Qa$=u?9_y{a6SARkj*8UlvjoHyK^N~lX4SFLxxSkI1beEBp(gi8`Q-H;i=%crLb%PS +WM`P@{FcG0`z#-#4^X)1LOw-Flc;7QrRczV?C;*%*oe}Ks6df~bV_C?(lG^bv=W-*Y^ZX3i>ca}jvP; +`nf)%J8v>kRQ$Iu^<6K6OKyOj8y2P}YSVlq_nb3OB|2>Tx%LlFC +*Rz6xnCYD>JX9;M<)Fg)6Qdk^;K#6d3L517k!>N3cbTH)t_SG-4G=Y;xP}5??Qj*s|JC4qYoAW`*x;#uG9M$)2xF6oml0-V4+k~5(Gt%;$LgG&HZj{?m1-PvsXtd?DcH;HI#kdB=^Cq}TNi(@UK +x_u*he1@1VPY55UN4<R2CYg8MXcIVyQRZp(#KcX%Q4#se_p6MP7pm}^;3o@w3*y8S3OnMxyQTL;EGbzh?+PdOx##%-lJv!sD +(Zqc=F?uc3B)QqM|D>|B@+jfbUhUFqV@Qy%Pf?JDpeax;SjkJ +40<|IhN|B&1Bk-Yl^GiFLW91Vq45?|DqQB5OuaG-R2k;@e4g|;S`sfJ9jlOw +U4kF9soiRmJx13 +a|pm&^mF_vwo-`(M^C7okwT8PSmTwEgG_2}p5_)8G<5 +2JBI%`6u>vgiy^UE3>%lE?IoLu08D5v)iNGi_kPTeK@DO?Xep$W^67<>{%nezhlAbnteMvr+m{@wtOG +TQCJ9WwL0M~r-iIJ<*qiNUn-e^xTQ4e)qtmPtgz7<3-xMD$QZ7`HNX368KG8@zoc`WWqHss0cotjrA<%4@i2A&@a8*Bp6SX@x?6O}mYk7uT%oTRb@6%PJ|E?Ayq`{6i +04+UL%4mqkmc#ZKQNy0a<=IVmmlZMUZF>?O_n`I1TGK!-gDMp?&?k|_1By3qDbKi +-T=J4$jJE?3=D!b?yS{J!yR~0&khR{2d~|KPLSB7otF*29_6O+vy=S}w>6fFw#ZiV~5E{W?`ZGKY!X3JJ1fC1@@#}@EyRLtcco7ZgOO6)+v0~j^B)% +Xkvj4u-3dE|?bSUwKW1>=5VLQ9Uv)K+OIojpA6P}B~^3A8s2hRBf!yJtx_sf&xaGjpjHaT*TH3Sz4>o +VK8_prXv)D3ZBE0Q8dYCo7oNvdpIrea*$SiVKNjI8bJ8UbwUGp+M^wLmQQuphHh9L2%Qr@m`Yo8OodS +;~QGdwwRf&E?dz8Hajy5mjNU-NelZo6KZMHb<#OdyujgAQ~*I_$& +HWu26=pOX!d71(>CB!%v^%Hc8a_Q8`%QeRQIp6XInnfLP%GJBt4}*K(t4CtAyGJ?;q5YUTJZcUl_Gnw +Sx*&L~LFlx&-X(~HSa=eiVBEGif-UqHtCb_qhT}?&FfQp>q$ovJ!1r2T~=oj +$hnLp+U`;ClH<<~EhA}Cp0M5;Y+`T~IAA@w&GIlm=8EcvKah_loQZ2-G0)dE0bQvAPk)!VfFyQ}39Gau)OwIxdT;Dw|AcM_@{De +D?(KK4j>dXz2-(k$g+31cq;y04RC#kgw3jI@`d8_Af%r92-qmU79BqNK=;m;~n6@(CMRN_k#cR;$C02 +NDY&I>mGI744ky96s=)RwlZNJH(Dz4EAW$0Y8+i5ID!KbLaAD_NbJPu`KPQkoFpv%rX^O|gTXVvqm)m8(6ny-aRV%c}cjb4W>DBPm){qt;r#QmLR~kGo<)w~z_NB +HGvPKu0KioI*A&+S-Jr+0U;`DX5R|$z0q=yJ(j#+y-KQobS)MJywPOAfM24-P2*k7S-5;zKeSP29X0!JHkjfg+5t^mD6_?kfu1M;$Rj06 +R+k0-zzCwftam5QvCVU4pR^hI+(spi)c$g)?@A(enId}TpvfDgaS&tn)Ad}0zPGhpy00cLRO9oqw|%=-cglx0~PWx`)6; +s5#Mi*I#S4x|R3FE~?X&EwLMcHwdxK_Y8HhEXC4L^u7|Aj5?pjn}Y>1!af!QD&3}V^IqAMip)Q)yTbt)l +aNe#w&UNm5!XbZS4fB&rnI@T5M<0t$RQI$MYONL{Y_RZ)xQvv>x?HhI|mqn=a>ZQluuGp|mhYkygHR=&11UATeTR>03G +0!MW-;wE%Bg5QI^*&cyt$4SRo&9kq{9N(>Qt%g`&tPNv3)m2<$UW_;OTk>z+;4fP7DcrbXBzE>emC_z +fj%UP3pE?}a+=zWgZuRQ_R&WvAzx7Hw!e^GJ5>uwS=m!lF^GCx?pMn1yE?uh`(U><=ap}Vsd3rHYCVV +cb{9%^J;h1fIBC%-yOKq%2EO|{3W={Abie3aA{6dr+z?uwUR2h=(8s93Q(WNc=A7E*P>4CderF@1G{q +Ysjf~2rg?Qrk$*zUO!mfNDZN(j*77|a#PMY-I~Fm*-^d*||e9H +C5?rwy5TofQvPvg>gUyTInyDzJUoYNUA&77Dps?HCU;hbaW%ig`Z1n-rge=OMa4Y&`_tKYS&y{j-8ulOS`2T*Hk1GDpOZ@$)X9`HvLCA*!-PwBCrD2d=%}@|erZ~V7U>Ab|wK)2D +rg)7dWBgAh14{8V#>_CF%nRRUWu!na{-yyCx+w=^j_Fr!@$ +d%Avyk8OY}D?uMhK^7?_zuUqV8AjUUV8yt{r;Tfe%@3>ehqzgW%Kpz|&t4}yapgamZn&EP)h+dFkB|H +)|j8NRU>gn!E +46Dh<#=W%9EqT*6713F&zAG0Y3hk1-Ij9iL?P=c6m${JaqYLTD8mw%!-hb4xzihTxpg(i6KzmcqI+{2 +dckiV3aW4;hmycAbbIfBxiun-UW;=f{kh8}S&Ojs^4yLV@Z=7u_qC9pEOk^)_o70hEr@D0eH58ZOkvH +jwp$5)89ax`D@3#v?>#^X)>#OT8H@!L4waCj;4By22prDcIDvAl<(Ey`fg;;7DP1% +!fjHka>BU%ty4d)wk*Q~PVt86-SNW&Pwgd={KL27jedpr0Dx{(+bHTY_TG7e_9rwP)ffvmA57J)xrNG +TC{Jio}W9AGT>i$Z9An2~I2g?m0hnZxEKf&tp>!?V~WtEZ4G}V`KAp6WtzTGxJy{iF7Sa+QlWxLPC{O{=e$7!$rfJ1+G?8i8aZ;$)VrV~aPoWU3hjNhXWguy=rp7mNxzsapo;3Kj|0 +|fE%ElI%->y;e@G_M*aivFrZnZf|D*60F#MJgEyv}Ys@QmQ~{h5^%*6_XGeOwuD>Ds1`%7WA(=(t(Bd +OTMWeXpHB?_2q|JAvM}^3zUKmH#D{a(yIN{T&gPtcx6tgA$-NIdn?pZqOykn$c&u~gq!9s+x4 +AYOfzHN7FykY!f3zBNjw*%YIYF8pDs7k1eA5p<@QTdx`cVxEVT?u|n!UFK-ypKy +@XTRaSR27C(mW0OUdVqCY@J;zTJaogIK$CxM$>58o#kCYqj2WNXS*ly&a!dAVcJU!6;F}N8H`z+Rt;1 +UyI=(DKNPCDE6wBJq7!Em4~jpv@*&`2g72ai6pjX`?5VG6e^Q=2Bki}-C26~a(v~K;4#Qn}? +0XS8s}O2sC?@7n%iCO$9Rtmttx6$4W{&h9&ZcjhBH_Y`_iFDF0NJ0jAr8vU%E^J!L~Jrjq{DZi0C +BjC%EL8WBc#$@eW2Lf}jj>v-HlA=^aOsIN3k5x53n0XVk7PWE2FognkblNeArg*nRCs8?zP9+ImpKqn +7?O(}FbMiGW8V~mj*(3UUx|w^HJoi}G6ZEM)+mCt3eYoIO+gMR_j!F4>JvkhK9j^9%GCmC`iytK9kLF +bD=Wf?^$#M^$4r3^{7hWqw-Tb=`6*z&SqP(IwHgMBIvVR0Uh8B;p+wpw~l!uDojqf<)34jH-nNaF5UeeXLOsgym3YBg1?swD))+GuB`9^T^<2tRp$pK-K3%J1)^8(jpmHXfJ+ +=M5V)lu9F<-<1l^uDIn_O}Qyw`*LEqK=MZc{93EM0i)bYr9PCHH6@8vyDbO-A)b%jmu;&Qs--7V&*rd +i2f$a*KQlDd>tSou9SKe}Mk6-{L%SJ!1Mg`~+1u?8NY8{K61s +A&-iEzkLy3A=p&3-JmZC6>gZibmsB^4Q0=TM4#`1n6!&y2LPTo`xYBs?uC$q#JrKj1Q2kR4YL>{PXp+ +KS)Yv8ckicDSue0`%ykVbbdUG>&NMac#3$fj4@|!p{eM0L2RtYvx6F#zbE13Rf>h*ck?y%)-SW!sG)I +w^ut|fv8BS--|_Om?p@^{q8o8O)~PeLZFW&Agn7;Fo(Io +&JKvVKESpt?Y7L5!e!ipo)&huWEPp%07ocd=_S)#-7rE$59m6Ax(m$ct` +{Czhb59;E>huVL)#+e&qG>_&&2fygZ?-!QWYl{3V3|lE$sEZX-ui +UIY4$g2YWmMlo-A>uzlGI*|`oe +zP`R(ibotFpw)$9A6mk0gT>-(LT2PO7D7)_gQWX!wISqvfd4s;Ncy{Cg}UQJg}LEde +Kunnn$V-3DhyJ`*1jWQo_%7p+N1fxM1b_^Rn$?D2{F+b)xRseOqZ0IzJUpLAA6X?BP^94;fbVAdC4zE +M_-y8W`2nt8MFjVPDzgjIR_*WvyBg6vIpL`wIN-K4|S?o8JsvA>*3VH`!*CoV&*E*~fH4Zr$WMd~bs_vsjlkucFid@6)|KT&zn6YVa8liXhnxX!m@k3gHo`JhF)z-@k+e)!C*2Yi&jj%> +3vfsQhxI_amlM=btW$hT*`Z(2AMew-`%^;qbWgQGWICW?~4TDi$RqBc7*TOKo@6i8!qP>Hwa;TXw*RWbOF`c;vf<%Gd;mm0@vR6&&NE-!)0YUJa%}V`g?CEc +-CCaB2C+#7qYXuJ?b|KPuf(jpd{&Y{AxIDbdUF;;WNdaycdRpFCsFF!nWJ6QgY2WMY_!!ZCg>6dpWE2 +nBDNKr6>aGX3<>MciO%2H*u$?@?vqy6OH9o7f(l+_Y*(mhC_C|XY+n5NyWxtnuDUaxW$Ad6+`H$M&%X +V`2|L2N1OF7A^kM6&;>iq``fN&mdF$BbF^HB3@hzB35UtL+tCi_aw0lN(GQ6E#1Srx(6ay+)HNDsU%h +DOhx5b)A+vVZ{Kk8~?}B^1N8$CADL;PqALrZueeHiUu^(-0|IGp)KD3`7@!j-L8Y3teLs#e}7>ZzUlm +rvZUQT+S^~5JH?>qcu&j%AP9~T1T&sR7GnTc0pI+lW=q3Gv5@ySbt_GZNg()ch)XRN5Wu8k9*)*K_CR +E(0~R7CVAO}yZp{4@O3?6Np|6_ekxBNQm~qA&Y;G6eX&?r=rhb)j`RkT`jjd(jjiJxu-i)&U5noP~c< +FHS(AFHIZ+?p*hTMSq*aKLa6E^`Z9GIQI32Q{BSm_di|QL4WLM3oBM|_*)8|pY*edPJ>@d?YAj-RXlL +OJ;W)$oh^O0`6_86bXP>u0U!|m!{F(!53Y}WQGZvXzKFPPf8*OyzTF3X+*xwEZn2~C;ryN`k<46tZ~7 ++X{?Q$0>0gxL(1-l{+m}#&m4>hQ{KI44Lmu>(n5U1|f%bn^)A7 ++&43_9f%Gcr(Xs?HR~|HG)c7{xP440~KbV{_s6Bw;_wyBFh20vQILA6p)NkjkU2HilO2a?;JT-mt7tF0V&E$dhQFCEJZD9XGuy-sr| +*UF#t7x+ezExw)KI5{-4J6{gJ^PMN2nMm0+CmfV#q?`fREsIP?zlhCQIrM&ol#uxM{w*3MJzw5(Nx1) +t^?vPeFRZ}6xrap!jhPq&8PycGj7i(~uaTr)<-)v@f85kmPAk(R-YtHVBa9%%{p}c3~Wv+)h(Q1=JQCXV9PJxgd_=87`yIiXZ6BEBhFL$#a^jutM|@eFV +x+J4ZA*pY_4r(N{2n4RE-~-3i=7|-p1Ti9LLFEk;mQpnMoD7tcgcoEV^Jy2=gT8pgBe2Kk)|$Vhb0+| +GgQZFmgZEc8JCVP#&)~Rjceei>bzc9>BHHIs6x9Sw66|=;fl6OU`J-zHCI-?*J<2B`b3k*`D_)Ha6Hb +loa)y?n=F#*IyYiAB9%KkJA&`1q8(v$X9OnIRF729lX~gmhXQ#5ll^|azVGhMB?*&1lJslwHwMLD>C) +8Uqq%1(n5Pn6|KL^W50*qp42Mbj$6Wq@VV#dW|G!=1I}0@!r%(z<843ksSTLIY)TNffUX!?R&_%QcXi +@ZMh=B?~Nd6h4pcoCNS<&==X1JV9otz1oL$yq*Jv?%jp|zCIsDZ&4&WsO$^A9*gW(r6y+qjAu +l&+r9CVn2f!8!x3(3F_Yb=?(MAhp;>kkPH>Hy4Zd?+wdN5M$06-`$ZUiX1Tpg{_Q!OuWrjRU7NFlYw; +GyU7PC0PR3-R=BQ6L2;oMGgIINuL(pM&}!2S_lY>OjnnpwN&Gpr@2I1}erZ`3uD~ +fAn6XyA2l~OC{JR-2KKiPi%i(#~t>NMvp~3Yv|78WS6_obM*rKqNj-mJx%KYpr +r|99rxF|KaxX9(V>dq3ZtXFAUIvZKwTlI?3G-Mxe;yjInTwE>~{}bG#?MoO^43nctUMYM7KsX`O(t0j +!DScS-*)mY8W~chb`lr@e{`|CFd@WfiQ>Bs`*i~Lnjirlh$_!_z};8q#bg+dQw}VP%`Ez32>WcGNdtT +=lKZ9SELuZD*r4)pE@n1r0V)%+U}|{*&?{u5wS(!0uFEM3_jJ732#kyL5K@@tDvMyY~RBRu~_TV?|L#0)HTR>-$&W9(5W>|EkxToyf`i8)I_(Za&^0_C%dP5 +ZR8VPx``nU>ASnC=S=$<^)r?y8UsHSU!F+?4kDn?jvT&1g_92b)v@W@SqBdo%718*vNOAh-^mu}}uy~ +k^q6j|}S<7X(?8ou<<$*q|A@cH8D=7!vlQ+5vO&d0Cej^|MHuw|YwS*y=ya_;@x<%Zn%;puj1$`BHx_ +N)bUBF?7F(B})f+Z;1GJtZ;{wtX=(;nMFozSCAX+RkWb-XvwHw5%VMh*7pSv{&iLa|e4i_H`#|`{r;xZ3J?W&9lx(UpT(FGkRkr$c93+T5RNO_V!YdwBM&eM#IQ5%+D-TZY49oR^>02dKFWqO)q*|GqN}q1Q4>(*lg`uMYqu|l@3q@?@PNQo<%f&Pn^znVbT +3@|UE6xe8A^q-4*RBU4-9UAfQUU{-&FE1Ejkdn=iI=`IFOw8tW2{>{&xR?Ww9@h7eL$YkKFa8mVe3TW +swEV@+-Y%b(Wo2A^wGuVZHEj33ETyFczQJUn7ZVJIyQD=a4-7V&CSBYt7xc6o#vwV4F$MCIacIYw6GO +alY!e?2N+}I&$JO*D3}IYl5zsW4F~$-hC5P`}1PrcAn;!VY@@UVKe#e#1m6-^pNfLS(y}4>CJ%deCx7 +}vQc%8>*vqR5VRnB)bipFj)T*IJ#5cpNtRGLmmSN_@vsB2gd7H$PQ$FtoPKVaJNKpi|TK2X;B<& +bD}Ix^0*TiLp~WmIkF0MlbxoT~khv-SyAhzhb&d&WquZJmYP7uc=Sr0c!4XgVn2=Z#f-%EHmI(>E1+( +WTaW46G!yKF`9Jrg-!cge5~lK6hxY92h1T#YyxI1XaZsf_fs@*^C<{O&t4X+^~y_b_}+w>65SD$vbbC +v8zKtERA`T<6BXm+QAnNVmddc_QJJoikXR`NKD-)dU)^dW*b_xO5dvCo^AWULN^keLsn;I1clsF^gK% +@WgVYYM-%y%$o$kZ!hrz88Dwq%hHf#KgQ3n?45^pE&`R&_Vl +dI))b&wqp0X0SnNUW9~VMndoJrJC9oOG;Gj~|FQnMfZX70?r|$HqCq*@J5^wnav_swBrkv`M-X7`yi0 +}0u$Nx|R@o*CVu>J@8W9{KD4tpnzUk~}Ny$+!W5`#$sXJCwGP#hr`g1|_UCK(37;guJDDic|$Uj&0ZJ +xu@#mV}^20Hho^;D#6j_!OD}o<&lBQlC@8^>K;@d3=-rVn;A&l>!w8l6dLpkyoDL)mhHOAlrcuKscB( +AA=Bn9$Y{GHW$aBE0B3nzx6pV3UVz8^D_3008a#|m*{02_{zkfuOHx7Z$AD~xic@7BKB&>TPbaVzbQ` +sRwhD&^fXg{Sm?4Ek9q6o=1gsidFyG&bgQ#Z2N$q7^g}9Mau(6~f*ZhJNVD9BWM4T+mGm{t{Vt86^VO +Av0*@F2>s879>OWhG3&{5$1r>kupZ#(lXs%mS#4B0+#~Q~!KJ)vDA#i3u?S7Nl?O?3g3lrHs@aQhp?h +|TbH8SnpbWLs>Q5y7SlU`FpK3(F|p1!&hgQc5K9$>U$L{%Sc!Z`TudhcXu#RGP> +hAlvL(AGchk3YH7^UlXw{++2F^?SQ**HIzsK%o7R&bJnn1#)E*aGx;oM$yPf$HFGzm$Fin!ptKG4v#9^^->$S< +XLfCL>BjOR;gqNW;1Zd`6dOQo!ack@}*SJ~xalm7%J+-A)Rg-e +DR?Hb3W$&4m&_ +Sl)j!?Qxrt>Ta!W9UdO?{B!Za@= +-_KBAn;5Z3Y#HSOWp>NTug3SvLmsY?P3Um~dhMa0W>_$$D!Osk*LZ-?;wqcx%2H +Bv(Ru%JZGQN2fn=dzIsO`7fyUTH$JU5$)ZE<~2kc7i8a&=YM6okbX-Q=FkzP0l*i0WRPF`cI+*$I;SU +B#>B<4y#RuUS>B5?6qgE0gsKj3w-+4qQRG;B?-ZG=(g%ON;4S90 +Y4(H5JS67-rS46(97VdV!8uQnbJll7-+XJ`0evHZ1fmhl=o=v<(Fo8R)pOK~6()C&)*~b1yZ5hJHOTO +E1cnKhZ0~dIoV~ktMRVHNXPO^FO=Pv2n+nHv*7gri&Uc1UH!{)bu7me6o5w|TmX_{Z98}uX_-C;R`ut +vOx`OF?A +NtOncCmb10wL6}L>x^Z#oSl_3v@7?q$&r@~xpbkPTXt`f?Mb%+Dq5q2h&?KJun)|M5>FGKD)-0!5HH; +Bo*ys)>-89NYk$0m_hGDkN28MbXdO4J4cV_;mW~K8ySqF?$)LCSfIv4=nU=gH> +x_C?X6`fArT|zQa|#hQfog>4D2T1%mEGkZXYg6(?ix0@TPATUT_xo?I{?~UFaP)BYqWwT`Cc%M+^d4v +WLqv-U!k9q4*OKqB6R~S=aw{&HoavmrK?q+1nn}zux?;_W#WZe+kk0LJpF9pHaa7bc`<|M!&iKyE+u~ +Wxa?I48b5PW28~yQ&ng(d$p}(px~E`{*7dS+aWKX<&~A?Z?(k?=t;zZN8zU|aixgVEBP3`bd93;Jx{l +C!u9w{_g2=q61w#!5d$iFfsj%JWRdXXSBXOk+-@bB`O9f>C3|TOT$l0Jl#o{(Ol! +hqBm(L(QrwQdV^xY!By(PJLV=C}vsMt$*TIrr5Bao)P`mXE1N1NpGmQ8%OulaJ~){&0D1n@PuZRnN** +rN3`>H>!hyPuSgE|pp5t%VoA9qfZ8ZXK@u*k;ot^SYi>0VgX+Q`pOT;1RzrGMkUBvfaBc)YtOnmsi4K +)Mxao{UWd}{(5l5TjIymrDwRtWWCK$m7X^<@a+{btzrwLDUN&%r7QZaq!n2o$T?K?1_)OJoy)gmh*`$ +Iw}h8wiGArk2lC~-n_+7cB)ug@Woc^om0IJbXe|4cZYxhN{MdJt&a$|^&2I-Q+=b+KwRBsdHTl@>D=e +&BPg+NBjUvW^^>=mv7X_I6-Z#n(+RMqS_`a!5W^ro$9u- + +60j$+ASm6(6AFXhKEc#HwRzr1gpAsbx9x!LSq&rj@$5RkBT_lBcbbefyXKCL&PZ;Fb) +RLNX`;9JM8Ob5A!Kmh}ff1hJHi9Qn?&kp2>Q(m9?02ZTq114aztTwZ_Q*TA^(hoCb`9DLm9e_P3ro6;jD4)(8Xs6Zh_H>y&RO{fOOg84!gUd@h)XL20B{D +yRwFsh~iItffBkvKkE5lE?Y7mABVP0%3F;PMLuX)EwNj8ud}IuK2CJu8rHFjjrvlqG; +>_<(7A3^rK&Vv>q)>1MIgZIDFOcv1Yp{~A6Xdy(Fvu-bC)MbH$+2_0*j$@6(CGUL5M`^aNYfyXrN%lX +jH7hK9BKAwwM`bP^4^y3Qirwa`9;|lYq3k>w*3iGE64D`0bRDxg$HFnnF+fEs=`g0ePgY{8>9!#dlEg +;zpy|T^1b=q>@SD>rPmkRVZ8B_eczGrz@vEcIBFM3Z|{6hO{#Ymkyc8i8icY|aEI-}y#EmLRhQM0Ta> +KT>ZXCVK+?Ax +!6v1-7#shdCtjczdAPPTM>)Ves_DSMaksd|R9bL`swO}Xy}6e^miy;D3B@y3(AArqr8?fz) +h+ndOqg)_?B4!OBKDeR_x)ErwK+hs&Ho(pRjc4;CNlCK(NP(!2@HC}YxeK)RQd3QwZ$dLDJo9xaWw}- +nVhYOlw)m|S8^d^e({yv}D&cvYGk*8ss-15H0->MP~^z1151nfAeD2AH1LUQ%=l<+E?qk{}@joOS2Bh +zCm%$6x4Xz}TGf40HCpB-()uMAJ3QY;?ZcGK7=i7(L|6(m)S58M+ +ff^KNngo=GTb;uXmy&q8mIlv8v9v8p2_yfYul>5tRE(G6S)t>6nM6OI(Mi(4`qo@^`pE_;6*4>R*rI6r}u5qo`Aenfq#@M0RAsZvr!wf`R-b +~9>a~NG(#T;zkM)&@?4GnkSlGWcvWy-g3%Mb+k`RIZ0e2#nSF^GIunj&7b?YP+)m-@jf +!TKc}f=#`>Xk{Ri?O#x|x|aE^+tf5tT0o~~O(u%_!XL$mvt&yTSWTh!jqRaSZ +K(XG>;_K1Q(T8g`qxc%=rIU +|a$d0wi{ehUC1=bC~-y?dIl9`@K&4`LT+s{~_4N*Tir}#>7%?971X^Cf0oSplynvbQ)%jcd*$jp7J>7 +=^ovA$n5`cfwk+{B7--(K(-8#l^PR-L6?tT-zVYzI+F9~}(8>X98?O=tKtmB$&|Nhs&d55_)|hpH^#0 ++w#$RUItMIkGc*MXv01f0J0fgr-oTkL$WsBZ_fEo^fRFHm-h5G|dbX7-g>cZr-FgeoRf#U-?MDT-ihB +qF&S9#Qs`9Phr@dm-FF^vTh;Yf%rsN|5A;|__i(r;`t*fB=0(VU?uhA3}Otgeg=KX~4KEQd<+ll8{df6R<(OpMyfj?w|7*CBbpHgh_UxZ7JmJ8_o*TJCR$UD2UG#bZb(yb5q5A +wYhdHRO?zY3gxNGMbSBv_*UOb<8ogw)SJ;QJqRANo)E{*O!ASH7MpvTZi;DB)0OW|n?4O!8fb53D4)0UnAztX%YAL +>kWp;X%f2XYu)-c(ElTy<)L~`s%BcR_Y-q8;FFPqe70xZ>cHR?;Fr#2=Sr)|eo>h6+Qu*k>@||^Wki) +Tfa2FI!ZmwRtWj*&n?U7sORG;`dKX2J(Nui*8V%_PP-fAfuI#tcD?ghTv_hCI^nCj#F%$BfXSw7F(0U +3ivJaL$Fy-gvuxT29l$9ogq`m;#GI6_k8SatTP+>hr2D~|X3UG=fU^$hFX-8>RWTXqVJkfgjuv(#NhU +3L#~2Re*y3}aZ#l`CZSvai~HtDoDpC5{KpyC=`fB01d}j)hD+%!m3pU$(id@Y;s#`YU80yPIv@m^j}m +*>NKmWy1rwy{u!BmF_>UqeK)L^k9TzBU&-BWOy}`59_gMDJP3v9vQB +Wvq1Ml;ET8Uq15%gS01WR#4#z{Wj>D8dxXj{&dv_b?Ly +I>w=PG8DebJ=hX3bu|N560rRnnCWb#ErD*N8+82Cde*Vmb#Xya3Hs{i3oUjl%CILx=9z^6KhE0e|}&~ +b`kfbM4$DEMVw;u}EN_*LBjiZWgXRLJLjrvwccbrgf966~!flmR;jE8hmyA}>P&ka>TVYb4mq@i+yyV +&Y%$eo#6>fNh8M*6Zk548n+nc{xZCprs~#$v)#RdFGscRSaXVeSi#vC}ae}hU}%rwFU!gkPsz6W&~wH +nMwLv-Y?FeD&&rRRjvBeVM^eOA9N6b4KO5$Z%guerNblg5}j_3_#%B%gONBwW7aWlBMD}gvEt53%>^G +xB1m%6hy6-Jo!@fVA9_*FODy0GFqTq{7hVF8lpVjc)4ZH|p?9m^Mw38!atU^Wk?ebGD)QAb^WGWro~p ++UAg;Ln2bs%QDgkp^)fv2{D<9fx}NjJ((0)Fl$!dy_h!e=K~c|eb4J+tp)1=1U +Pw(q9k(JRQL(H^2EQkqnY?;>yX1HFYQ@f7Krmbg=BLK@mJ9O;J+g<}VTYb4ZCx=GFYJgbr$U>RtEB-) +x~E42J3f|5)U6IQhuj65yR{eL`xdTB@1C>7ZlZ%w=1yCx-(Pv%qV0BCATc+%uv%%i-wft;vXx!#^yOR +(Voh<^=N@5Eg=dNFVI0!jC>faMI+r>ggG*!UmRCZ``N-G8am_W7~>)bXQMGW-Pb3@h6Zt%wlzEUS(Q|r%(kpUVyHO;I=0#E)8I~*x&3(VXTBE?T-zNTIf>lpNl +0(KH_%7(%|ER___6!|lEr&eT8R}d6-I9&mUrb*GZYsqHrcOxZ-fv-Q4-BBC&>2`G00_jKLvAo#7a#g4 +`GlYEEOdWv%c+EG4@CLkZSXD5K93oJR0V7bUa{9pJpS(4tXXqgCnWb)*h4-+$H07R=V?!Yl}mBZPD&# +l5j_wY~K^^sdeyBmss-bocz<|bWow~yGx-BgDoPME~>n0a`Z`SuG>pa>r@x<+t6d8gH&Jj+YXgBR^XY +85|iS#rk(l7ghf&Wn&h2a^3Ah)*8hGJea4(My69S5ijR3ze8&ky-qIK=^+_Wp0-wEo|MQ{Ca}FL0{LCK7; +1#`pSA;N8$SuknTLV=TReC!^P-W(*brSQ$?r$)2tE^_n$g{2pKb6keep@%1abGXDr(p&#+}CwM)&lQw +<8>kP~)!DdwxD^}qtUJXSG`2hCu>-+gCKMA}jxeq$ge0R~0a0~qoZ+{23&>P<3!(<&8_PSw!ON&pk8W +y4?ao^$`Ci}`7_6$S5Jvi=Ixd;5}Ut;`vjW)JXK<&=f)2DXx9vDe$&s2Nd7Fhy7WA*`8XaorI$2`pyb6V@!C$U3N>A!`nV(e;cz_n2lH&=m*cdbl~cPZ +W6v~#`^JRSX{g8NJ%u+j$?0X88qB3Q^EE^3OH`iCOVYVwdos+;xT_L5Tqm$O(PkbxB5|Wr6H1$FmNo= +3?JM8AUAFy(-`ot0#YJt-b@f2Vj14Q}{pdaIOX%3w(X9Qc!3Hm^2zNjrHH=+-uryw7tqVu&$$@4jc*@ +TQ>APOnU%@T(JG_Ugwoe=1`5inpBY=hw!W%txc2=}QRt1KJpipr);t)}%8 +?C!?*NLRv$Iy+>hlJpb?ev(%Dv7Ej1!K2YlRM$EzfTA9>P|9wJ9W&#Po#5ND@Eo`zPuX1Dq0q&+1$B$u=^Gy=m_wSao#~N^hJ`!k&$D+wcC@RF`_gZb{{U`3WR3 +q%;qL$5_&)>iKOOtGNQ}~8-v|_;+lwCtfCVyEICBPK`A% +Mow3gToAq!p+LY?%RN2IduUGN3U6mtW37Z>WdPBu1(%^g+!_(U8hORz6@ys>P=q80|HkXDZ +ygp0xEYEAVzDAI#sa`!5gm&_APs8q)+qk>NK6AMhavkd5?{psFOm37A@2=|*J$KBB>qP1`Oi@q`n#z2 +3o3`jFHsr#yQue{pfdC=EPsy5{j~qc3P1JlQ5o|VC|%#@`mp{uBK~J;6sBwJd+QFnbj8L**r4#flJ~R +v-0YqtQ%D$cgZ6!K$ekx1;Qx7ly21bkNid1u_$Ib?hn=omZeyN7rCsW|67H|h+i;IhqbX37XzdAuWmSrnyZU$vF +AT*auBRBca4K0s5YLTR#$lh(!x^G3GT#}k>zS~+W0I<`VxvVHH_|uEqq;t3*-cWHFJ!_MJm<2@C-(<6 +ivKVomi0O3O!y9QX)t{OVQz}BqcOp1@58oBirmGRtZ|Q1dAdLH^xh +oFKGin|b>}RzrPO80FNZt&gznQAr`9~!akg)^3y^{?5RLKdiLNQ_kk%XgVOcW%6tY`zb)QU~Xf&=K(k +ads{+vRUBpz}%NH;UB5(&N0*oOjNQO~)b1rkYYyQYy%jMCdg&X^Mf^mO4U}zE2TDI)k8@4SU+;wP07rA)28fk|oe{2L3>W>xm&($b$P|e|VV?TTpY_9+Y +iaox*@T2g=KfC0M#>A(me+!ljg)lftvNX+71Pb&cKCJ_1-b@T4P^yu={jZ6X4<%)R8 +wW?Ce$M{lb3orAmQQ0H325_Oq`XHxO1tUP?$gm`z0g7Cs%YRMy8Y0um{nC@c5B^{44m6(n2yK|liFsQ +hkS0yOyqM83T006lw2PbOm6@7gm!!hsL@@U0@jOfz>|7P_QjmN50&@p_()SafrPmA;1IIe2Gc}w +Lk!BUyi+I0{w{Se>xNBV=6z*zo3_j{wXvEE(2|6f_5Scl +2p1{Bnne*07>uH;EYahQ+uxMWD&%dLuD+yT-h1vgwJ7Lz$Pt@gMf?=Bnj185ch#>% +}=W{5}Icj0$Zij|Yj=*{BQm4)P|W+H$C#o?v`y-p~g@*EmO##@`qewBbQtOz)vwM*{8&OMH$ +?d{%aVdC~FWgyh3%b@?;bY}TZ2RHfY=BTo#?Sk(^vxXk=lL!JKTEq9f)r!^qgedw6X|Fl?pm#>5n=6K ++Zp4W_I*5-DMUiO}NKTcnM5}rXP{Ay4ywxaxQzfQEfLvXzYqeNn>96IULwPfZFD^4` +bi$%16G9IiHCct}PNu#*QezbL$nOwv98M@;&nh1_j>$fSC=`wL7m1=s$*-zq#Zyi1~W@cM!vpG|pfQM +q{8&ouR5`pwBfT#!{;2M3=FUdXN0*|~}kZ^zUMCNH} +J90dX1Iw2$jy-4dN`O9Dd{k_=Uj}VhfjI_6(?&XO5%D3Qu7h?9|$;Q_JqKka8{TX74<;{leTZnlb``? +F{?`QHS5Ho0wVa&-Gk#-+p^6|PK>nDD3oxSfCdb{&{TM7fV4cFD0Kqvf|2agMJl++4epg>0^r(dKp)B +5L3Wt%$c3_L+?vp}2j%9>+Ii9_w#lzfkZN4VMbRM$2Unmc|Hj}deh%9I(#=^h +nu;sqm`lFwOTdpdw1MY7fTvr|FnBl_QgBeJIIobv%==(bUkr+$!!i9My&LC*3d)p!2DCpwxp#hW*%c6 +YEbZ1CR&Z9+1tQf#Dcp))N@uC5iK51)+&;#d>*~87=}I#2aEeOiMLiI +0s;n4=W30aA%?BQv2YJaKh9P$tBL5A<@bl(KlFw+mP!(kDj#Jifma96_vP1qy5cAbiTx(8!8B%v+$D+ +d}zC0bF-C2t)VeQS_^pAT6!_px>JNX_OL~V3sH!@ukvv8@PNfUQUZ`xgRak9|?H%3%vt(7pyNB4P?ko +KU>d@qOItvcVHBV+~0jKK*)HRlqwWD3QOL@2iAl3@?p?Zx9ZD=wD8;fi0Ice3%_@=%-~TA0fxHSVq<`p;%YQE~chFhWmOL;XZ!kwjy#tDtLNk=dq59T+8HUzIxYz7@=!3vfW&hXIV58xg~UL +4ZxVJ;GZ`ZInHU!pQ*6(*i9%uicWzA{SeDiK40rxwL^k|W;}a@+seT=;jJL_f;q1-%N~t5`6#P=fSrp +uf$!1qVEg|JVh&w)sm9Ac#+P56{~5TvpZlF74#VO!z!ZeW37o`MRR2`Ql>qBA@{&$pnSYdk+Hf3sm50 +BIT|fr#RSeFoameSvOUk@r9UKHE83N?))+ixHL7V9s^iVjE8=>DcSSf&G*elFg?}Pm+c%fhYr+5xpVR +8E3R1BgIk2DVZ>WkYyNY@(iUX5!L414d=3t7zPD4Jmwz7-BecFejX%OMR#tr7pdp<+q# +#=?a@}wH@D}d2kfY&M+$Q*~RnHnjJ;IX8Kk?)El8Ht;dcPnhkQd1G);$CAwcTvI`-&t}|OsJTkA0#cV +X9Kzw~hvPIj=dYn=B#^axyQ5_e|u2)E_BK9)F?Pd#~na=EvP|qC7NMCeVy>i|_BVOqBFnv4Y{&t5?U` +-sVrw~OKdb|f$(-^prGK}K(fDy$BGZIn_Yu>V6{*aBMOfI3fG?x^UO2bM<-MysBVK*|%FxNYu+FPlfZ +k~_bZENuXGVJh_hG=BJF;|qt4$bqnJQqaH$E`$MP6TX4-1#vc>VzN9uO5-oH<3D*8+NE*4MVaAD`Bx*CQL@170-%T>u^lRxU6>w)3c^_1fJ|Fe1z_5sI-#a9PU;&S&8V +MgJIP3=fL`lcT^waFdLkn)3WZi2EDmjNU9)370MTmzO?iaB1eRv#)((!S@X{4^$#%NoK9(C&p!#Dy-+ +7zHAKQ9tzKNho4_egxlze-*19|=vJ#4#DV6`od%6 +lu5h(UQ^e2h3JXg|qFbKVu)UK=C0lj(NbkMstn?)NKfKC!;NY=_JD`nTVg)#&*8mkkVUIA2)T?`|vck +X9CCM|1s8wBezz0=nO497XQKdq#MA2x0|if+Dxi`^Ya3qdI6k(nM}JW6)MZ$$OJ3GJ8VZM}*t^LbG>F +P@3AVFmPFVAe?7;Wr?WCa6D!Q!wHtdFtrs+G*@GdzXp;Kv9nWcJ=DAv+O3cC&Y)}GjPS!iQ4HK8mRVI +r?h%J&s6@+qK3|(~#6BDYPFkye#-aK6j&2aC={*{{Jodu1=MLEM&yjTo%!|%j3=L!4KG +3K&qs;l$FH-v;m^7Se(XQH@x{NQ`bD4m;eVAz`>LnDknsUvQuPJ1F3C&nZ)w+J{xc#C|X-gMNPmuw_` +z6Tr`Oe)4HblKONt6XUFO@)H1-#qy*{`|rfhS +6`s*h@VjyK3p?8@=3T*BoS9DtTIZs&AjhQ?MxijAz9uwLdo0VDVg`se9BpvrTySCgZAEP~F4@xSVohr +kY++3fMzH{T}Y^nWOB(5aMm)#^G%IGh`oih*EhMuAt_iDLx5V+n@8MMs=Y~-4&Vo!nfCmJB15gSPm{+ +JAXcFo@qB5?k9;WmMw7)G!N%~0t21EW4AMZmKK0TOB?`EmnC0l{Ed5W21bIEsU`>dJUl;*_mnc=~y15 +(8}eR_5}Gpg|TEa3~6Bt*sF}kd8}$?0rN4f&;8yVz567DvEwp=?gmZP*4t>zs%Iva2q(~=AdMFjoYc0 +fN}cLn_Hvub^a^mqFEq*pEEDXxeSEWK;bw7$z}4TTf#7aKB2&3@OPw$-vCk+_+K-+deT&VvdJ225{f_ +rr07{A>-uR-w)6d_DD+z@@>Okqr6TEfga|MZ=!1%Ak|$cvS3lish}>+{=h+199<>en=@3AaKtJ8bF+* +}+Ta?iEdz98&ixmec)oDE!m +>E6Fe{F;OhYDOIYdMV*~+9DC)7dLsikz2r@wo)LYVMRyzvhA8ttbe^|0I%TgG3u6vns^B{kD+aF +q8L3$4vlF4AaaLKUEnz4eSmMA-T0c@@XT&%tsxwKA?_OPaCg?qHA2tLW+= +L>7bLhQJzjcSMYNw&WuUoCz37|CdW#ml~yR$!xA~TZVFS#bYA?P(xALa*j8qRXydB8_%s!_1L^zl7#? +l`8T1)}?cpI%&3M`xne`_!MOinjE5>X6$kLB|9q`H6|F_##&uqAUSDEo@GzQ)q?-zdWm;I##<3}N*|6 +_OgB6akuJAAtkVl+z=pLRE|D_!;~%Ontxr$d?dnoNQM;T^*Q3+#2pL2}TIOn>g{u|{fZ9Jt1K>%Z7b? +R>p-jpk4mEQMV1{pufq0IWTWKY9t8rh}WV<6R$c_4Ag4IuY@IvfKV2! +i7z`XA_A)BcjYF2;H(`a}DGLG7$eW~bgy!g^ +k;mLliab^=>2UC!@P!Q#YZuS;=XD%9L=YJzZ-(Qnv_3|L4M7{KQtvQl+O~N(63y;iOs-X@hvqyL +|xW$G@9f+;gcLs-v%8;H!Ru@J=&>|>%rYk++Knp!{P!~keXWq&-xU3S*eIk8eMF1F66Kir}-8FMZr@MOEY%92P1n-Ib~8hL7Vt%Vy7oc>Zy ++o|nNp)-qAvY1RG^i$-=$TZbM4QNFB}o0iSlxKIveUEs*5lBi4Esh)WJVUP^tmh?gkB?iIupf|w7kCRJ0Y^X<&x}07g6&aq_F@BXMYFF +H_^hwd&iW8Cx-mpzivnuN46bIbO-cuMCDTJ8mnkeDW^SHq75$Dg@JU|R_pj`+U1Nt=i^!3UCu^wOtz{ +eng`~o9HWM^P-J*gr@4){7lGp}%dp6g?pOcAp}vL3Uk>w~9LT3;A +vs8n(hS&kLvUaexl;Fp1-VkNuf>9Z0L=h20`b4-^NqL+5bpHlHiEreukzPLE281dYh&-#A-Dzv7zMWU +*0EC@;Ma%w$WQ19d@ge^ftAh!Y^Fe?ANJ}=Bws}wV0-PQN(h1m6yP5Xz!qR60<;N%VhA{a1TurjD~Ae +#k(C6jVaso8J>(W_#1Y4@rIJ6XK)dqF3hN&bL~&R83Vm2Z0o$l|fLjp}y(LfSWbj|mV*jc`tT@DY8sy +$7NJBJcz2?pzsuPC#hIqFXch*S302O^7z8=U#fxbB4GD0?A75LW3;R&><>jG3WzB`P+9eh7F1wZsz*p +2ps|CZT6-`sVUpPcvhV(*AGD4$&80MU5voinj_xTkRpCjG;CghyXk2CdV2tRck{2x9=`djYz!ziF}#+ +(*XH`CcgFN1Y7lJE066lUpKo2x_DDmtizuAsY}4@j{#|VzR~r6BBQ#`wSaHc}V0;)Bz-;oY7v?Xp%?| +AJb@5Z~K%;Ofs%J_(rbyLrc%4L}v1U%0^IaIfpza`%cHryI7GX#4N;B#l_q^vU@s7=Xh$C-H3a}Ew>o +2#1UU$oQ94sR|m5(S>A3!>(;XOMuIv(EK6U>KI6JN{;lTqVlRU#7w=RL +o_(gJ+F`nh_mFa?-$K%4y%i>-rfk+YDIJX#-?aBoQ@dcNyqNMiRV8zRQp +%^;eL9Y$7*!U2@)%2qiP1SdB~3iyB}JYvdfXDDrXL(qQS&5|v5-tQ!?3;u^mf)pPk=B6<~i~ZuzSNI) +E&mDLeCg7C9Z+a^J(Ag*mp?2jomV+`So4YZhh8$_?hk4inVeIYL1T3bi3)2cSFU^h(Z#p +IK}UjMb0HVU4QvD|41T#H3$ +ol1+NtiQLwWj;C&agaDdxOkWqMz2Z_mtav@lG8xf{Tz*)_@b%n7(n}6tJK>m{t|I~By8wO!Q^)4*2^N +~Poo1JKqJ)P_6+28KH$erFiH#rH^XB*t42-Tg>3fW&*E$(Gk^7(%1`lS*qIN(B9%^2!1Jnr4RL_1E}v +4)Rg?s;Zql&^!c;XK$Lx<2p?QN-Fl+|2&HO|_=*?po*cS+EF!CdOv65saJ|<0}`(t-q1A6DZ>ZL*`EpAPVt2r>N~qVcJ%9u0PFXh&2?_iTQ79{WVt?wi$9cZ +E2YL{UlOK@JdfQ^WaGF#CX?56THj$z-Oq@`dn+54LF^uQ!B(@M{xe{dv!Wc^X-EP0GD%?S+#ZejJvxsAqfFM#d%IW& +)J|ifcYCERPu}+CSeWxD~dkH6nM)P&ehSrdYbWVwm($0Zj!%8MDIBz(g7hbpz#F*-N4s0mA_oR2+24urGc_XP|v0B0#OwO2vTBDgv?~E4f@r9-6#F ++TN1A6xbYJspWe4`ai((6bD_dzoBkQ1>~AfUlJSA9yvA9Pn|9=`gZ+Ml?-y9Z|>Ib^v$<1Z(R9I87mC +}1VO!v+=o61>R!jdkq#hZ@=oWJHQ>@A8x8p%w0*w1ol0pFU%Vyo=UWP-%;az#*c(?qRK}OL+y!Ka(zM +bwUyjEsTmoPN$=$iG}JdtAe0IXt4BouAm-pizo`s +0naSKG>(_LRL8DK;yeQyOTbl;;#Wrnl#o +)KP5ZvR&}@R6P+`$3n#t5h)(z+cu@qwtxkPM5$KXXFRg8kDa_{7zff%z- +8kS;H0cS7k1PekJ+V56$w85!m|lt&1U8lU97yfHF8mkuP5~pdJBkPP>-xpy)`p=|x&UM8+>QeL1j$Qd +@6Qz1(r7^gWQY1_gTpq)qFZ4(`G!8_xp$X6wnNv7Vq_zqcn_kEhpcJ?^hWhD$9T0q$c^Qt&rUv49=f` +CGd(Yg&J*8kch5^?-{kz6LI2!LRX9BRJ9GwwyGr7p`}bEa0eC13$ENpyk_{K(DDN-~=!wj!O!$IS& +r`FC#(`t-f2uZQ%y;O!YDZ#MvMi32|a@cIaD00#K*bQ{2X48aTQdyJ=VW~RKq74^KKINIuClC@Xe +p)PyZ^=_ft2%PPJH1P~9(gO5WY(UcZ0iN(Y5t#C7Dir);bvi%;;D);|*t1`1vexd3-Yz*|@s{|6^9Ts +p0z0MHr4OA_;YJIKvB+aSmgwG~kV{8|(K8nTp`f{ptd6{?%X3(fd*leYV#B$x;t}w$}g2QV+eY +^@_lYgG~Cxuk)0GT{;gRT_jD|c4m@BxEv>43pFC#M7pm{p2JDXrIIQpI4quZSLZF&2RfG9=zJEV4i(Z +vwyS>TZBy=6NkJ$+vIoN6sDC`gS`C#|;+G&-3-99%|th$@pHh5#(S#ddYDcnykRExZSbgL%mEaWvlExzpQKGH3|(}j;OLZ9YWQ-Cqf+;iF51Q0 +amKI?ae4DF6!1)rG&Acip*N69n3AAUvtCwgZhMjz4pug)mmfJ{0qTBk-^)cm3H?3^;iC1e;uo&%(^nG +hQ43=A-iOMRhPfACOZ$^fBhv!L)JdB?wpm~U&>I!zF8D9lsPhs4IUMH6<7|*}Mf<*(8^;iB9%2!5grJH +-tz22E|9dSy!1ZRkcx*>~ei!OxIN?!n|uz@oMbrnqi+O`K_gTC-OYMd#|+E`J@e{zTEFXHuCF9;*TeN +Ip-~3ih_+o^QkT0=(I@R9eg>K1jrAD01t-r>34kR)k%FV`62Mn(gF8bH4I>p6x2{o< +tW*!ka)bBMEq;jn@Rx7k~JhUW$1$UU>^ekIXv#Av~~I=E{)<#k&OZe-fbK-7$AOB>SZo}61ljVq8mUN +w3iY#*+#Q09f5xZ}Qb?UKgfcF8+lPZoKn7#rT_pGWId1S^l1q(=hVatJ+Jd1LA0_Fg%;fb1#^jhN%GZ +A5*u`misPJ +&4RB|vd`3~vpb73QK^F3z)EmYSbbhq +r+#HQ{4`CVZCF25nle*_UKgS2TsQC3G^v=%BnnQk-4wS4nZ{R)8U8VJFdT;#H%WU}oHt0SnRrxup<@R +q~FkWiAh}USR-QFpq`zBa6=fWV6>(j0dk2s(&nP#ltk$8Hz{ASpv*2dWl2To>k1={W>W&N|B#e!;1F> +LhZ-cQn}`z#1kxD-pgYk0%HbiI|*PFOpqooF-LRJiU=QhndR5aVnR8etVqjXUn~SOW>2Yx+#vcU3N(+ +GnBo*N44vGEFI5cfyBlnCd6d4*TW`9|;?hm3sE{LhFR+D6*8^t{C0p=MK4>B)VUAot8S0q#Ld$BWl^V +yYYakOM^HW_F!S<2wej8`lvfqMn!C3V&*~%+lY-cj#LhOn^2{-OE0D;X5vOMc)!13kDW(nx*PNqwSLA +R(Hv)2;I_*7PDSONrTK?82gm67CnY#5FW`PuGx@H}WkpDb(|peS7buuI7nQr|I!g?;| +AT{?5ns2q>+AALzn~HUT2k|piBmRH4m=9h`&4y&=}MT#@W9~3Mj%L87Kt;_Od7_cU&=cohnd1%RnzW` +BHfyV=zBZ$hZzg{1!Gd0GpTn?{*6FA0X59p3)Ke5bs|hQ}-lU_Yir%b4~sm9k89qrC+$YaeVo;yn&k_ +yO4*hg#F!*>o>JDAEhxbZ&^c37O;m0y_w8%@3k>5x_4aCuRoveXS0R=WV)Zt7W&n6{{*zAyxkHvZts% +!JQJMCK9(|9QYqv6mYdP8Etxp{U{BnL##MPdA?8Ut!1BSeGFgJSWQ(YVFcIYXZKv +(^fJL}%$ZLN`E(@gDu063yW#TZ81#4AV4SBV_P0w$=;2E}=8els&gH`K;cff^V!)3mwu9Kw4A5iN6?O +8Id8YE?nzgSTG1(r1t2dYD>chh}xJcu24lsmHy&mW%PMnwmYq;BRa`512>D0O)Wh5L%)t>pMRHSQMRE +%oj3amBOav1xL&6*yF^28=-^LcKuKvM#OP!y(Pi8~iIp*@%n->JbseI6V^BHRQk$6J$e|Gfe@}y;oe&Y&XZ) +O_*aLLyT9G)ZvF4Bz*)ve_vLTyJ7nvBwz8lE1y%Mp30{#(lA$v<_M(hZ(58@&Fly{c@3;THph!^|p9hL4FxPi>xqlvy-)TzBKJ$*}^z; +E5@6y1v~`*<4hrd|qe(gEKx8Qt8G#c@O$*XS7TIOQ@GFEblE??}?7^WA7y3 +Bf)OO_SUX?Tb@P1_zgI`QN@OYZ&Wt@#d=3^%(^$b0KBLCxN(YpXxn!i<~vz3Su{l(qD@8ojNn8Q-#aj +q$S7@y8g*gz9qwD3oZgcgv)K)5_Eyd>&X{m=Yc9ZNujgByYX`u;DUkW0zQqK96=<{HS;QRNxLJhV?$Y +w-6RXb$Eqs|h($MkktSpb{#b3B;MNvGZU4lfSe5wXt>VP$Az^ny9(8CZ@W5}sE&B6w}*AxKY=|+vbaC5e{ +=f{}t%t?(Y6F$YK9|cwV)#tPWjyj$P$!TatF=yiHD<6q;)Ei(O_g(%a*j++PDfNlpj~76E)JmuJTCX5 +(W^;b%0qpandoNmN5yzbZPTqZevU6MDw&f=KERq_4OUs5h>lAQ{~!&p>rOyCnfByDlsLeG$)$0&1#Z6 +@h7*~m_>8iKJy(>i$QX~OJzyOLjpWx~1zo=wCitDI06)lY8P?MjI=vD5H1~?W)VZr(oUKPnHcijzPc= +e1&27Uxe^BzAwIYx{)S16@?ka)zK@%?H;dH%IeROy%x3$+@gj&plEK|&KXA==xH~2@+-l!&Xh2+O51s +>P3kUY@3g0C5@igESH3(KkjJVsZv=s`AGYdIjLmRuqaDG55ij@;EkIyg&Dw~7LW19GV!ZrMp1s7*K7J +hD$F851oyZLEPo*Tw89pLh;;M-py}LteaqRG$tGx!{!-7XbFJ99`-S%^teKyoEu0Kafg?-~8fW1`qC8 +dV1ZAa_ZikSL{N0iO{!K5GfNQD^7X<+{@iz{j1)RC$x-%?4mu^=pj4`Eu&SiXSxT3{_Q|a&YLFRVB$A +s`#j{g?VI?X{pRF-9(QT=n{w}mdKh;M>A!%;ZwLg#8)W^HBlpni-+nnM@&DBtJ~8uu@cMrVrW>~H(kf +fHlVCcr=h9cGLC?EOxv&#$@iEni}zLph~ +6O%LB0;F{V_01cL2qTf5G^UgH-Ys%BJ@~FMhj4$M4S3?2XDBq!Pv6ExIiNA>S4jZ!e22{zS5!8{pU$4 +8AAP;$3;0g#QXm1!M1UoNs>urv6)Pv-ts`99WqFhiAD@h_axnNu;^i5k?Wj%PDmBX|0PQiQ}$LeU3IX ++O@cL5y`s=ZKwnTZ_vCOA7K{v!}NjAOvmz5WinIF;k=iN+S9T<5qD$L5N?6(hbp=4V$i{Q4#nk!l)F* +G2ICEsy@m=|F+`73OEh?2cG8s67!Q+f7($g5_q;oFn_C9ety>+sX1{jH +S=?1Q7Vx#<}Qq&c3Psu8Q>WkqycIIci;x|x3N@g}WlwE*LCm +%6BLV(#PV;zOpuHh8t_Mlh37rf+2yq!8v8oT2iP*kMN%DDnpFKq$^}C;}5Jvqa|DHZ6WVaW9h~ZqO=| +gL_i%-W-##ENV0uMtQ%;r5>lky$6zVRc@Euqz?je68f92XgMTbR^FyBttd=baqZMukrC@jOOkf##SLE +)a-U#C9xTQt2I=T2Wa*u#0@G@ +!=y&XFJz}^z(W)7<49vxk2h#t=}X1*BBVpia%%BIEE9>-R{3{9E-3#@;I^zXE6+E(Naj#;_2m2;Zi0( +e$>EO#7j*PomZEt{O(4m~~@%3wl{S@3&$VZ^dD#&hIP?DmP#Z^1S57^y7n5lB$=zU|0<-O>KsQTTmF+ +a5pm`(w=o_@cC3kZ800jSb_G)QswqaqbmM&6zOI-3It+a}-Ldniwmp>R^a6qt@c8f0W2B3Is{p$C{X_ +mA_q_!*e3H*mAAF(Mwkw0bh%^e>}RWL>0EhtxG68+FM8C#knS`k^;OZ>)jKDxLad$SA}r6A{@p{qN_D +Movzq|!|HHkxVC^N21GO^4o3kytJ7+(uZ`&dnbJp&dp5*Y;t#isUVZp-K6EQHYhk`ovpy__%LN4Q5XI +4nq3Q?IsA%fB-~q*?OAna$=izZT2^u@F!}(c>x^^^h$|M&(J>N&+<@*tPfvBZxP*XW*L{A+IkG#~D#k +g*y01X*tx3)2Re#P99OU@=zSpLgV=^Xp}b=7o;o4S7kYKu=HCv`#?dJpfoOvKu +~_<_I@8w*=%1eDTkIwf5~eVWBoPeRzCt)e{WLVD_b~}5+o2PB=Vakzk6??BB1k=N5AYH(ypNoIS>ks-lZeV +YWo-w{?WgDyyx5ZbO=KIIGvx1Q@FUTU%sn@K?lKe~+7)Y05X`g7#jG4V +2#b)7{7X$FLcAXJbFnnZGW^Znt#V0Qplf^!sh!E&o03{-0U?zIxz4v;2Maz&}y!X{khL-P={S4vl1ll +dqXC!1u<2YdUqhmKfJ7>4U8f*CdojpE;lo{E(-bhqpMS)_Cj!$H(M+<*qFg!U3fu$~^+Gc%c+Sn=!?7 +>f3IVw1vXUfpKKw!jG=A2A2^%zGV3t$f%p+93vHNEo8JW3_7&ZfTp2k{euVonS-0O? +MS;Shfv;Y@OlxchnRmQB1MJcw4)uC#;C~H~C;i>c#?h(MB4jZkQjbX6-Fd +PamY&H_^q=aaN-k^hli*MoF?NmTIE!(8Dyd2}HG^F6o`>2l5iO#~-`r^S^5UpM4HR;G!DZSd+;SGbP^ +H3`q7+a588lWW5dDqp~C#4_MQn9hTViNK36q&ro^Yi<|toJxH33^LI-W47Bk!cd=8c)--KoN!wXCdkJ +-NCe5czz0yr`s5B28^!dgkTFH(5gr-WmxajCyIU?<6s>E+Z5fxtDBu^7Ah?C|(fi1c$HOIfAgGXEN#J +tS<|#n3mKh9tBPMr73l@k +_F6i+Rj{~C9@=ecExwK`WN|0{3T6%jY10Rfr*Pu9VHA-m?tih@@+^1k> +{#v6QUZRM3>N8;3@`rhxDw>7Upk=CEanfC$>y^VuT~^>RVvQ#=aDVhLaZRfYuc#(wE#s@&kFA)ST*ArYeGj#eK`Eo~_6I;W{JhVf2ljf$!+)kc^?7Jh_|t)G%Eq9 +YDh(x6;82dbd^|F~iZx@-DCp&UJFIyFC4&!~xm8ukK)>Gc=0F<* +mNeE&2Cud&*>;rQtc_~kN2`FO^NY=wXLctJ@f?=~8OaA#^#Oh99d+^1T$r7>L +WwO0RGAE;(WOUpI+I_qU%E>HonoUn}x|eDzzph7u5t5*UP%I7-tHilGp;Q8${RXcET>l!PJt-JJFZ28 +X_N&GUCno=A3!5E$D_?F7D;IN-M@83OG(wFLPqu^%+q``b|J-Nc5z`QOg=c3&`x*i$O|L?43F(@ +ICdj8=pZNJNyNM+h|wvmNum6x7rZCuVJs-zq|3EHzCB|lE4JDSN}h3O*ZPdyP~9fTN{Mz+jm1x;!Q8} +w>!)GC^GxY;>LMraM!QJ4O^PQVW@drH4P*_6f$*M%JApKdlC4d;vw4?;bgF<&w|JCi*CctVvIP1+g+O +C8!bW|5N7kEA#UeJ!rAtJH!%4^%$VJWWEc8b4A1@|<*s~)|7@gfqkt#)EwuY%x(HHciQi(&FWDj<{^) +nx=Y>6~8RE!k&b*KU2K)G|wRqnwSMtT*?L_QfBr^6q2JnYOh7s5~j*(`@7qhaOm-aP0CT~)4qy2iAw^xuK +<&vXe{Zfbes@E%0}F&ZbouLkByU@fRx2et}Ykglgr51bP{oQv2}Q +$`mIAuQ^z7#jgHBM!ReN0J?3o+ltT93l2TSz1l{N^_t(s5hKL?5d&aWSwNfQ`)pb&!R`}kka)1Y +**1Nog1Tu-$m9_@Z_jvEgkg1Li~CayERx`5GCd1G0ekQR?qLq +_U%@$1HoDbWF+KifRP}Y<1_dCjVx2%DC{8BgRi|^KZ7k$Wnud3(2@pV}bar2$AmRpzi?J4~eyRZK#7x +~un>(4ImEf8Y(Pi21J%D4NZBDUA-i}YRWCidb1g6@rKIQh1(gx)pypQkBebZ@HO;0=9iO<>60ew`NkE +Mx}nQ;ZwFp!B|-rgm8+;-e^5{TZDC&h>B*t-Bhe<<6>`-J9h7E10_`}jTixEo#5 +d!~ZK_w{e+N+NrLB7F~d?$wIzF8;FUAXoeFWB7XoU;hK3y({?i4|t|}ybx{(VSfUe>2Gm-dUyB)fl5z +yuKGpj4DR}gAoZ7GeWM6Yd*1#$PT^Dn-*=$-dk6GAxi#Z?6F4xRbd)HXt{^J!tir;EEmM0=1QhmrI=TS)V84HSC397A+t@Z36RE`HzuwLTDo +b4t@ofG(Fg!~3pMAAM}z&nc4)kjOu7&|HFYru&RqsV?vW1-~8n@Z1QLK?q20?2kVLj6vJdgB}-FUWDUh$RVwD-egfwI4q1Cn{4);<#Sg;}UjKI75-S?FkerA +Kr@4mu93Uy_xO)!w(z7m)H6a)HjDBNqO-#aw2c7kkIMz7^5I#+QxSEt+DDErv +qH}4VfSMT!v-Uu6SJt=2}IVG6A@zsws79$&cDFIx_NiHKvprC9~j@^lM^X)RF?S7l>P4v7UJQY7z4E$ +b0{t2MIGtdHac^vMj>fpsu5(}JG6Xc~u#b_K#PXwk=cM4zAUZRCIjCnJ7aK@+S-RIaqjc6pVY?GL5%e +GD+qSPI`a6(=UE@^=X9HE8}XgyO+zkeJM=i=rtp7%c6wnn~4r1gZRz3z(`VyD +aWIT8`4kC-|DM=gdb4S;Q`C5vnzY(&8*0P0;9ssNw2cfXO4^ +>oUN7!$o@?VhdC`89nvSuQ{@5r!-tzuEA$h?D6-oa)j)WBM7OGL8w)FWt!MgvVyo>w-u9QhU0#Ej^s4 +IXXIM<=N@>IfBrhqelyanP!Y}9Ip8L4Jekdp{^T6)NB^H`~!Qbzl;jLy8eC*4E||c@zXQ>-JszIXJDN +EX|ocw=c+bVPUm}tkV3ww(IwR0!9={PlY8Y5*;zb+{X97a?{Pzs?E%5Y)Cu(MJ(cfWxm!%K1rzj#j&{ +5!v2gTXWV-*mH}C$+9%OevjQ0c`@s3*Px3uft{t!!4ZZB^9|EJ6QJF5f!YG> +v`@M1xnkL}u53{#-CqdkJef~27mhB)IaS1pn4sloeZ9bpU_MwDAI+WzUWL`_v@BuFLBBs9KG)SW-JEM +G4VK}eG)SVauP_pMcOK#M7EUNVV>>RFKuoD_2LSxR&x@r%8(lz;Ng-d0qGs}yZj^hqN~C8FCryfOBfP +rYxu7Y#8xhnVZ>C1;rz3sQ43)KM=1u#*Mjg3c7@#JQl0^O1(OrG@WTA4D-Az +ydK90HE(!LsOff*KkQqWNTT?iel$ecN{7CwSiic&L(i5&+esMjk8wn* +L3fE?41)hYMM5c1sf;O +UQww?C6n|F%mS_*qYtONEdvjf1RPjVuMDbBWbz@(sTGgW#T_V@f06H@V9#I4~$T{S;#iUDsy9@ +41rI3Y$g{;(z +h!{3cQ!zmC7RtWe(x$cnx(0nA&H&IzeV>_we;9z2Qu`aiQ9$=Sqre0g+t=pAp6eG1CTp7tYQzBa%9Jh +?*>EsuK{cJjH0l%b*0yyDdaZ#8t8CiDhwfTBVwX%YA$^_L8=r8#5%A5f&c^Bfg(-Eyf!_nYDo9l(eDn +gdH&h>$bmD$o1%<#2nkN$lM*CvxYE)!|63DaNdJIBRAnTis!4cJ<_Ty$TD4a_?q3~3ajZQ>qbVyMyP| +p(7f?BcsJ}(yl%#IDJ!8>x{2W~Vy@c<<}x-N&_Ae=9WKr_EhORP7zdAuCQ6Pi@pXCT-R+UIIEfxlLt{ +pIk=R(4DSw+!vE$Oleg7NR>|c>@I=?<&Vch>hQz%TJDDq?X*grn_lSTdF!0)v5f2x{6yyfPRe|@xSZw +zXqNqD?BTkRYJdUtM9I|JFiL4MxljlFe+Nqm>M&)##u+m9Ie?k%Hs22~Jys}}Lr3f|ZhlzD_6rit;V +XLyTJ+Yjl&6-Ma^`I%)R-#fB&CXzOO9)MDO?WS%3Ua@7FBk=vA;R?VuoJRP@n<b~)m({wP0DtmT{L1s)i@)1v%EfHPLr)PD3gPWcoWY(P&bL1b($&iC2AvTOy}Yl06JzN#dy5aX +QDeD?;dqV+)U}NvKsdx#doHrZt{5IB`*z-SoTyC0ycJ@%DpSubHcM2u*$E1HVR)90SvGd=XWpO+p +xUkLssbWmUig|}8TX`cc6metX{C?8GK4@1+6v`=)9H@JP6yhLx|@+>vE0yk!r +3i5O=9LZXdGZ(PPqjxp7T?KIT|OXh)c5ldJ|O=+aJ4nPCDEgC8ZWPWQP~R!4lm>Gq)XdsJ{9hjb{8rv +No_;%wure(=!CB_G6NA3IB3^zIR7hp8*H8Z2I@cyn&?nO6N+uL04i?(DTaz~KUWiLqjm+(il5-WY0uX +IMXSc+3Qv!xef#JkS$+WiQW4z8-o5y;qJ491mW-9@XkfZ-GDZiu@;Wh_!*S2{tkV6QjfF +4~E6Smrl}N=3}hW>0tu2yF2u?CUIAIH+#v^4A&>BpwYA38z2cMi8C6~C11?bt(Sv5Cv90#>ngiwm>14 +R;QLwWUvy=C+ty{=m<(j=>qCc~c3pw-l^GLFU=ISq|DNE-@5v`0rYe9=o|DxmxUOnb!tg3dVI?^wOVg +5VD?5k0N~qxwBH-*NM`FB9vYH9HIFsFc#0aDZ7z7$qmw3&VH9Sbj5aJvO8qk)7yF_pRRCimtfXq;wm0^OP$=I;Y@pQyv)(+|NY +UvLEEc!al8oFO$=|#FihchXUZOr3&c##!Obfv1*RoZ1Qq7RhoRTrqk&}nz?u{^Hlf&{emOhz1nFG!3G +M3o4QBo1~1p6=Cjcs9?Ie#-d!)i|WxQ&rey!qWqF&pUfjv>6-`fLB~jSJ=)zJ(S5Bo0taALO*J7Kx}W +RT&iV>xJE=+tN9c+nkwc@fP5`8^<0uHq9o$`7|V>qARtk;^zlz40WO=W|7&X#0@Swv1gbsPZ +7DR;8cogIM|-4?Py$1{84g!+YDJHh8ebypQ3=Mq=xXg(P^fMO81)xVU_QGjVpySwSm +yx_aT+W-bG}XYo=(q|gGwuMVaXLwm+R}k~eJoZGiZs774owHmatMhU) +w`d~_p3L7*K7CJH(Ekis`WpxToGhV#n=Eat15I|TAv)jZxj&dvPVED56!q>>&)+_@mS-T)Gz5lqUp58(!H2U^LdQ&OvFI%ww|3a4j(0cU^S=vn!#2?7g$F~3JWXbp+Bu +iQpbFClxmK9J9k!2S_GVafWa#&w}1~~#<^^SKUDa3?^p}Ts&{I%db4wYm +hqrXElit(7u-S$t$wBWv@z<)u#7u+K`El=VZ=vboZk}t)7q<`O;W)cvZ+T0w7*}!VTQ +>M`=wi_c~sM(XyGlXkyr8P3QCD5Qkm(u{3JX}9 +7gha7%aC`Jrl69JJ)>QtiK_``9iEyKDx`>@A-;32PIayd}R +!#+}S{}xkZ9(O_Kkn7Ax!iAW>J-N+Tkn%4XRAQX*V@z4z +_N9pl3<%lVTWA(8+bHJ}B`dDh3PNv>W~22ux8kL!&IYu?qAl`yUXa7`4)WCf5ISYC1{{)#ik0T$@s;IPRk>kpmmmhfmM>3 +RkE_!+C)lO#Z*RItsV#9#om1S3ku(m#88Q6-(=f|u(xQao8czl_`2Z!$@T`QytATAGJ~wTv5`p+Nc}5 +sm)hfsv$}+|;DJpjB&r^8As{b8A(oD{M#u!D+>X4To+Z$J0F;s|}Q()Q_vj6Y?&QGCTq7P?94(n=s-n +enQ@!&mkr}d1SkJea&XgwFh}Tr~g29?!S0>le>BPo76m#xcQ(hUpS1lz5J=YBix5KJLvPB&%Ek1@4w2 +f{=V0TUJsY=JO8Lm_doSYUt8t>omC?vsA2r+aPE@`-IHuTp?0@5E#m}{V@OR +TWveTe6*{g#a7fZ9fFCIbnY!>31b+s!m +1#d&kJ8w~H~Kzea(9~a&Mt9e?kyGD_j@ZvuzsqV$}5urpR%Un_XmG!#`60V;5kyhk?JuFS+s{>*G&z~ +W|t?B6N#=*;rvPFK55i99+3NJKC@V!k9?F2jV}hf?~>szbocZ7`#ZM>{Mr5eo!bNc?Ee1j_CAI2epYk +*!E1q|v-5E})#^*t$TGjjeUYGN)eN!Wu$llR=p}*HO3)C=t+6xDUNm|*9@C@a4q5H7mMK+tk#+0Wq}6 +l4&}U@=8QikaCE}+8;OL8Y45iNNA@lWON);|GN2UbnkvA}Y^39gF-R+T=6@46|)(jd%%em{~(-AKUE( +TQ32&tDIN1nzSn0F$rI#j9rv{uEgK$2!co=neqd!1u?0SI@-NCdll&hm+7?+Db+t_c>z&?~bAb-t+H +hI#JbC^!%-Sy8-m2+NuHs^$v(8G-q0cPAGHm_vqGh{VN}_LRh9$1IZnI*``#D+05tyI#=O7W>o4-CBT +9C&sIWoK(C3nM9iWlEb{*PL#+_ik=^%+x4l&bP88!4BhW4g{Lj1#4=hsXZ|3b0a$WH7r(t!+s+q1ZX2 +55`f8Z&_=Fr!f~w(jbUX)Duxx6orgjDC4|u`xP@Cx);Q~D$ujC!dCjE@9`~cu@ +uEW%zG;ohtpRd6uaDg@Z~x#F@l)R+41Ig8Q@eH!neB>n*c*+CcQZbc?;w;X`#Ao#1Mzb}P3awullPd~2CfvepK` +AOq3?zna<4TZ_5SFdhPUwT{FE`g3`B~?M4W84` +%$`+y4e&8s9IoooAy6`;c3*e?$JILV&>RfI5B!R69_3{2?EQKx +SY;*V3hu6KT71R=P+3I-pv#ln(aRrNLS%uaHr3)`oh_w(VsN1ypbop`QM}(J_gyo1rwEVPU`M-VasNx +--5>AloP)yUwUwium2CL@@QO`bstg#3@=@b)yGY*i4FNjZJ$8=)-#%C8`fV~@3Yl1lQ&4;erR{g$an+ +O7!6j#EhqJB#)K9f_h-GCX0svka&}o4_?pyl%1JE0O`Tj>v23OoX_yr0$8+faR9zPMg<+AR7<`Wzf&Q +E_tSL-^eDykiq@l}ABKuH(DsLE6oR%0uPP@*2`fd;h{z-@U*X#hRFX4rJ2Gw!^Ry*#gLTHvPPJ>zZYzS|;iEM*6(BP+UI;aiq8y_ +N``QrWpy!*5#_V +-_(yV(;ZDF9wHFKg`yKcdj1pIJr;JE0?4H=8e2GgM)eA2YMTvKD6jhv7eQ?P)Yhd%SzmA$!^qAmGyW{ +D&BarvnI6C}{|imv}am8kcPBakV*g6}pm4+2^(Cu5pKDtaN*vc>8>uS9}CUw=sGDrV6KY3Bj|@8kcKi +ouL$WGO;barXWd#6b0OCr;g7$yffCczNkH%mvpIwK+T-=;d#~-?&6~tMDM&*^idB?`h~LRY>r-cab=( +FDJRjaT-WsFEL}=3%;h9I)Zqn40jHjfwN+LBIQ4x--Du=$6h@Xx;e3YvK{Wi|{trj<9N+bR6W%@}k9& +Rn1k-E$n_REAeE7|c|Kq6?2e>M3~|M&k|-+p`L`?inorT_MSzw +&!i|Hpr=znrYuQ1&B_BSaB<>un6}HIkJ2Fk0DrJrL@>&lcDI+^=v0X!5Pqmk@jOo25IZZ=@kc_tR`I +Z6W;@PH($WZ$0>(rO>;^5Be*sX`0+MeD|G*w>Z&<^n9`tkT~Ai00ix?ZtP)WHd}yCzD4i1(0p$hA>O` +(@0~XeRJ`?w_Gq5?VpF|^d4I(lj(f6y3I9Sso?~CDa4>l26XB7-uu{Ok4!++6UchaU>DxXe)SXY1I|J$Vbj}50640ZU6l+f)50uGV||_=`Z3)S8g`uk4% +O7#D~0J$88k=%u;Iq`P=Wnn97z&BvSht1jP!mye3{n(+B)Vdnnayh2)Jv40eh$En^S-xu8Gb_?lGTpuInfV&;kyy@1)_~Y095 +|gjE)1oH=`*{rYZDx6+==LCgMbPU3$Vu4C$wf1Yv_|OZSPi$7V+sKU4sf7BMe5721V-Q#>dYDTo%kST +9yK->l!~f9JtNS+4RoG^uu2Q89^{vP>8_cUMOV7zX80#Qf*3_NEsTeRe&HPzED@BHhm+|C! +pjO;4Nj-YWf8LfRdPsnTNzfD5;|MCH*-zCU*h20%H=?%~MPouP3BLBb<{^_xw5dP=KeXk9O63|b@WOn +)acXuU0|BK4@=E?YN0Zh@mp~@Cz?+prX6BRVug6p4W&#ArlAx?ImGW4w;gT4pjsrS)agbgQq?i!)@WO +z~R*TIV&cZ*-m*<c@!A$M(hZWQu_^}Z +^dGq+=c(szaj3sKUe3k!9LHOj_c3#vJBxz^DsvQ49A~@=?jiBv+!wA_L)KcU25Ji_GBv +ePGtNT_dl&pY)c;{A^i2U)4WR#x9q^Gx1}c +vzMH%@R0t~LKMQg*bBApcda+&L~wOR6PKD^L9TCRL?B!%Rvuiw~^Bvob)I&C)xoP_xMPk1o +RS5YBB4&tV=KL%xFsx89Z%4(g@3D&}!s)URh4IpB-cfq|Yq%xu2!p02=WbG-hkxUh<)Jhno?5s-^LT? +0^{Ol4}cAcmFvCGRR8Dp}tO38_%A^5JDZ_ai;|i)jdOGlPc3^h(5@nUls9uvLSp-=wRmH2#pUqxjp^U +ugbU_<2?4@DwgiFm@0OZgdLlJKY|m-LLXD!1*^!qp~#A%NX$bf%0f9 +4iR4r%|9I($)26rJ0%Q`sn)fd7{t0|jOVv}Rj}Mu@7+(q@`!-|om+hl$vhN@2U0+ +h!l`MO2g};7$_tzW*u3c{CkG>-wk+017vXP1g*p`7L$d?S+#<5b=o@|0;A3P`>!|w;R&m0VW)Nt@|qt +mYws`h}6*hBUqs8po;GDZ6G{#$^lHQG)bt!nZ9TX6A9di$eX=r`E{FhW*dK?yf4T#+bc-V#~0tywoX2 +{zm5dTR(^;v4D>kqOh#gUQJ6H4vx8nwotno)VicIIv?xxH53?4k3pDVaWUOsL8pS$7X%GpNqzpc-O3D +5Yk;tq+1Ahpa&l%xfAo8Uoq16s_QI|FdEgMYw(MHrv|Wdi*CJ2*9$UvXB?hS2PyI!k~9t+rU5JGKTX@ +iPO1=O9?TvVqma_7Cot7xwdCq?s(Cpr#M%riDLK9`q0U{5$T&5S30o-OsD!t8dffP&^KKG17X9hkU~L +uQl67tswOSLi#{1#;Iy+@dd^OoPKxeM1H&u$0F}R=E%-HP3c +-I0tABa;U&Hm6L;rx-KeadAFfAqaEI5+xNp&Q97pk${e`X6}@efUWcvn-y_AvUVh)ol_gxm(pd)XP^i +_%*xy^G+y1LW*&IyDI~JwX|Qa?0e(}{?xlhz0VczOk)kAhQ?X1XcATuuV3n&F5AM*%k~a5mr| +uG)@odJy`45-anUk9{&$<@3H-;vUds2d5UkYRV}VC8QvQS5awn2W%|Jyl;&jS$*g@lmSpGY^My`k +X)dl2poI#d2$>@f&;nH%u1%mPu%_=i{Psd5@g?Pg&YrX!#x`hLf;SEhcR%aiL!u$vyTWp+lr)zdym#) +gk7=b!Efe?9lpD?xUnS3&~(hn?Fp=EF|U{;hO5Rl66}Qt) +f{kcaghbv>nyNdQRd(*EA8WEsTxzH>YK&TZ{Gx71xke*eehEj2tuVFt8}?->F#*TE{|9>9!`uc5Zw&OCbuTnB;Jv#f6Z%QlyX0<#ul(%y05Wk4r1%w^w9E$G!;#}2TmCvRwb%% +OF%ra8ey?M4x@&)n4}+5 +lMkL!SpC&Sd+Yz +sFb;QolEmHXr^CV2_QbY0mw%f_9F{$u +k~BgEPKPu|0Qdcag6w~zYoB9F_e?YFA#@4w2uU*<2Ngv+Md74(T3#QbtC>FUR?lQno(fYo={n)`*!w; +?e{)ZiHY*G=TOia{P=>9}u+pC4Qx9#T!@!gF83*ZV}V84%jdUSWR@`~v(98VCF0Fl&fB>W6E-qv9XWq +6!fuy9-y{03FNu`fUOK?$`CF2m0Y%`OQSKm3``eWkk8%1(mx?*Z1e4azEFl{DKL8E#h?%>ZaWlTo9j* +lUoMd<%pV87BtU>AJl3`0R-c)bLuLurt?VuIi4@9gLf+5)g$ginBL=_Grh93V^jJrD5o-PY3`Ldi24{ +#*L{6pSTD^kq>;xEB_k7!I1&9|bu=8BQ++?@ak6D;jXPT?z29xm!b&xOry&rFn>-?<2o%YEhZ-_HQHt +C+CnLR}ql`pbRdu=fEPD2~EmY34@Z;{b9r&&%pG7>671%z2hMEGdk<6TLeVZrp@E!$H*Pn05CC+zHx> +NQA9g=Ih=#9o}r1&&$*YinH!amIq3<)nW2LgJQ_n}(eF)ln%2{xaRqOurw%Pmh +0nK3Bf{X5eXN3IdqDvMUi@w}&g +x=R4~obu~qpEi?~d3NM$E>9~EBtkUDk4i_9!L8Ka3Vw#GS+2O4>QB*iXj~OXS}nMp0laBL$GSQ9^?4u +T($AM+H`tv?0fr+)T5Oc1TVo3`e&R__h8p0FU;E2eppDBuxcXsh{c;j6>&!IgC2s +@cb%x*Po)b%qIv3cbY_-UVyR%bZh8;C60o?ZaU1;Z~7l@`?;-|}}a&#x}EJR%BENi;q-M`@JCPt|&2q +A>VPY6!ebF`JgDM{Wy_%skSi`wrgDVgFOdD8qwTR(a|I8myPJFTrWWAd!Ox1x47XJ1v#-xaHdWA?_|EO(*(_u_$B)dR +zmgtWEPam-{z4AO7;Bu?OT0{+MF%An*Nj!2V1K^D6Nrnu0TEQ6yr;{BkxKrP3-k474juY%hfGz!WBlr +~I`cpH$v%t9A!{o1$+0@Qb7p#nZj1T82uEnr!NUXEhYk6&g<3y^AH>1;bus3SNb +SepmyM(*xUEIy%DqTP{N?tANItLdCRYmeKdNwP=4XD{Ma|bMi_n^E%4)Tj{xt!T(3ub*N6GV*cj&9f~ +(d0H+4juk3@49+iwZm*GE1B9v_0&eXZL&+8502PtW4l&c9@G|Da?2*)$rVjE;v^G23oje5{s-g|#7kn +c{t}@AmUQa)g0Tk}&^eF7W$?t?(Ahwfp|?%ZAf2cad>f(c2f>j-C~^W^7|UCel8u6z-OZvoH9UM?z<} +-D;eTdsU0_y&IKn-$1terf$lpZVdcodXs#(G2>x30lzhz+TToViyD07^8V~fd@Wjcl`(m81n!k^bqmP +0cz)A3lehu{b_wV-&!LY&d0b$Bs5@Gz@oyIae!7ZHBR^zc?a#-IR%N&p_n%9ovPRG<_LXEpeQ$w>cTuq8VoZ9(q0eav8EQ!}2PCJB@{2U +tMp{^MkXYEhA%#+otJq1N?@6HH=LutKZ73)F#rx{A6cuh|O0q2BRce4wSqtk_RXN3jUMLE$?I +`GNuBl9?y`=>^e|W!iGUnOcvNYNG*uwEW}l)nn}o2;{bvcT*+GPAMH5upbRqY4T?$!LAh@QL-NA?fdWM5=vcXR +jO?%)@j`TyvJznRbfdl&u5TF8gJnYGLs0F5n$NymH4?ev5$nhx=9+v;%*-t;rQRxws-);7zjE(r0b!*h&#~;5l-1F9zr2mvMSNu}j1sEW@ +9M0`;#a*|%+U*D+KLlPsgv#j%qGPC#ljbUmH)_v&BW4~wUr%HjNM9th7;ahA&uhb6sPafE}=e +3)i?#~#_+wcD?5yOE;|ETO|e3bo|kFuY^(+z@c0PzBegwtZnOJ$`{SPvdq+Q( +1Wsw#A)emywCpn*q76Orq5@9iyNK~ZzvdzA;J(?zzG%lc;m4)c9X?A6zS{bJsI3AjQ!wU5NeSMD;%xm +4Aqdc0NY&?hI`~v)?#N;sDm?8z3=Q}HynMKv{EQnQ^VKflL1Rr?SmoH8SIieZoYc%#UO#4=_c>WgJE8 +$=@R#g>%D_j5+R4i->`@=KJpGX10Ndl?h~Y|VN-v5!^myR8)moRx#-l$ZXs_S9P|{ORRI(S3G?Iml1Th@lgZ89YlwC)aEA@TvLe_>JljR^}bK{~|79l2J8a3(1B4)6 +pBe^8xjGE7ne9UHjkTh5VHk@}oqPN>^EnQW}PDwT(?rk+ZCBcyd|&&$RmQadP&>Euew`B?XVYd{KyTz +K1^9_1FBm&g=dJ_3;8fpfvLAiyLF0rwgN@A?|Hf9QG_axuPp^CjuCJCnT4IVKR$PDNHlNv(#PReO@6& +Xc4-;2hcsS3yDgfOa+zYBT$G_wC$4~$I*=ek|7D=d=h-3+yodN+h^C)ooa<)tOC27c@#j|ATae2; +yX?~hfP!DUNc#?v;1MsM>(p+a%lSs8bIgot8IH(56gu%Pozw~!iGKJUcJ%<<$hqk{lm|{)>GT7qlZM` +nQ)=^XEKxZ1cgV+tenvR*gpJ>;I!#R=KS41c`E`?8P8oMt&KnUv;UaVHqYDF0Y9H?AZwIye|NN~K%-8(!Ux}grH~acd5&e&Teo~SFaf$@7kNPbIA{0u&B#A&641q8Lg +D42&F!kG*Iu;(Xw>Wk9kb`}jLk@PqW7{Q<)Nc|$V%5oqH5xx;ZGZ0uCywm7eMdfMqCd^S^zcCM2XXY+ +D!-Jkh2+tI!j3(Y3=YAV4$Xj$eNFi5^?C0;TC)j#-AAZezComeVdQ5qqr_akKr9OJ|9Lz@^cF +KNxX|bS^3a@U(nIuAO-rDF?9hxV#MTkJ|9Es(GKU!6-&-s%6EyI=k54=j-Tq+lD9J8c=Kyy^YCh3?nv +B6h+2j)_(PfWU`t<>S%BY5vwX4K_ic0$H~R6-@y^#O5_sx%2nT#otvB|~{EK}1mwnczVWl*V6ggC}&E +T`mevaMuZT8DCMKpf$ZUA(nc8d8`pzH8Z%()%I^%fnz;{BQmt9(Kfd-K6b69Lj&FT3&*A+R> +S*Ibg{i)IWvm~b!QT~o7QKGc!Ug^vG2Hro)$%K3Vxw}!rE743+c1$>O?dM!pqxQ&>vcuW=u3hRTdCW< +q4}PDo05r-?n)c2$Zn7!c`kcMke;}TIP>@wmNwyWI=uk!Re>Hn;3RCo+i;t=MeWw1lySl~1(rX*#wkCC%Ucpzajd +nw6;>~EaCCrXr*jv+W&OlS&a!y8`shyzU)_87;=~A>uNZit==<5~CHFNoZ3^EpRlN1iNj%aJfE7QVEv +qCm4N{W$Mqmo}rW4FCj10OU^y_H`U@77P9{T3CN%4L4Lu7>lE4$L?eUbp5@{J_&J;dxs +095yIcC1dHxC?Mv*W+X2qn-M&M|M;meb~6;wn*P0ACkNmD$_bylVA}dqvVI(bBjvUgGN|$U$5&Ua~$Z +TtvAco9NsxVopifm|%mZPC;POJKGZrTWgZ4rs%K<6H%$g3|5FYNH6F5LA`VEBo!T&veNo=&r9%rie?K +rl>MS*Ac)qvz7=hLmTjx%A`iLELVHhE!tnk6Irm%hYz{mB0yp8+chFO~o^+A(o0V{qItMCTp{P*s3Xm +*^>$|SS?v0>ZT04C2-+1|!n33ZY$Wvb*MB%75jc*{h>baKn+!-_ghrS7`-qthv*0GuVmiEBp2T8;4N& +x-uC4f1@_%k4Iho?5qa?fDy2iExEy~136OqsYSw10H8L(1rT+63^0W(aI9?Cok%y3^CoJfw(%?<9e== +joqHGe5Tlero(@_1u+x-71kBsdsnvim-mB=N&*=s0pND_R!k~dEW9>g@aI>;DO%;?G4LwtDces7i^2h +m}Ka(eu=`dEeGQ&ZN?KcW@vi@XP9}UBrJ63Kv~RO)8*2p>3zj5a>hKkPRi0CVgLEaaaBRJTZk;vQ|O` +QRqmhW7r^9`&enUyGWy$`UyvtHD>GT|U+}9>xz>%wDMJSX +aT46u+*lmoZzH(s!D-X^Mhm@RfQw>%*D!qJp-8xnrLfYgsgdFiL1+KuXju?NziH*nL&hG9=$sv?{x~$HsPz|$Y5}HP$lVYCjY()m-sh1aa2uMEEvc)N)-_vvLjtXOPL5M=HI##EJi}aiYKi9E +v6u^txLV&6ka#ZE*%o*X7fv_k@t%qXj|hV5PD2^6CzV}e+7qt(`Z}@iYK?No3ZTdS0YIjw#-Lq+akd+ +?)X~0ybheP6=co5J<30m%to9#}ogp^+dS9bC567y+dA(J$LSA5iVmEy^jwq1G6Y#-Xyw)DfZ8b`HV`H +68u`kG1y%x;gzTPasZrO+M%oPvQQZ>;o7%*Fd)joqnB)x_ks|7ax16qWiQP|-H`Tr0c{!FjlsrU4(&KsuLqqf_c>LT~2pyi9ef%MOphk6 +~ZVfUNyw=%2vZ8lmZw4OQ&kh_P&KCZwxp|1)vcli6?rUnmm%M{z;R84Bfg^_WQ}o6&e!UdG__iU2C4caR +3(Wbp=XW9H(CjtwSKF!_2d9(jZ(!xOW_sO>#~BAPp@A7jH|QM=^{P!5a#Vhx#_*;!O12R)=qNvGRR4} +R8K~ifR5#15$U~~RkZSpTCNXnGcRg?zu6UPj)nLzuH9MZ-r5;_CtJv4h~D0_>%B>7b*)T5dcQ3`NCZ( +bF^oS6f;L*}>9&}0sc?7o{K|DJSch{@%EeQJU>DTV_sfchH4wFhIs;fLcaI`-uQ4OnThU?)c?Io|V+k +VAK+`WnVrjGbrN5Q^4ku}umZa4K=@Ee2Ei&Ff5jWUMR$QBoLoJ9N&rBk_bfJFs*|dG%7e}aWR|Ep_mC +O9nj%D-FM$*f-)xeA;8PH-{3~Du#f-`)A8!{MYW+M=+q#DX4dE7&ZfCHz#!NBKD90InT$>(~JF)tdUG +++VM7pIdnG1&Avy>ugJ5HrFrWJT3*Y!1c%=IHCnCcJp-1`@E@KW>Mj>I@4{m964_16vU>V@@?GwT(NAK6lHxq%K>q<+Cb=WdEcUQfJmIhK{ZI1#1sWj=QPKe78Jd|c_jQf^OfK5E{PxBrBA)e#V` +(0pqbBn$-g)t?d)Lk$M@wQBmUg4L3&{~+nBI~FSZXYU==c9bx%mrqT7FZ&^~Q}KQ#U$Rb|cf8`D#kwJ +{N-;|t)i9tNS%eEv> +b)f)-fmD5wNd9i`%RnJb0vrOxkqO?Kff2`#ov|mnNYp4B3-l2EC{&I396P8UHArH`>>kMjs2#q?x~q& +7}pghXT6&h=es8I9OMw*oE75Pr5Y2xQvrPcOYB_Kmp +R(6cm%ngfkRBVp7k17eGVu+rK^9uKKi^Y8BYq&yUtn{26w`U&^13_ev;zyEq9dY_nCiM6_rU;Dxyk+A +`YtB@cLe})l7e;KCF#vo7c%ZWa!FoOGr)X@~Kz|}+Lw*`|Ww8D6FZm;%mjq@3`fc8b|t8q7w_E`@0w( +7Y1ydur0cwl-?=SL8E@nlov76ss3(n;Fj7KBiFTt9Ujb5!8X2-C$|9xB!v%xlA#23&=w_XvVAN4S-i8 +pcG__zoyn(#0ed +z@l+Veb;&7t$hK~%bBwwsLt~9gY(-U_GE%M3({lJwpHaH1sgR@Ut{S)R5C{q#9K;ie{yS5cXVV9fy)W +5h6Qw^N|i5~@JI)_ds)G`d;bSil{*0AilNB9ATkp=%40r%2mjabt9;zQYWqDx_e;B>~QO)=w +CQ=l+7FkFX7<>#P9x_+T1OKb5&4eh6X*;0L}@2 +XEy;4jvyNK;l!1v*Wmc7na2RYG0E*SA~lf&89Jh^C7k +VFnX`RF9+xQF9E_kI4t}|n_r0>Y___tM<^?TmppFx1^D~J9eh^D2X%W9`6*h_MYL(}yT9>(jQrQnzXG +!TVn_YP?`5BVqZjv_krF|!McG4r5--Jy7-j`X6?;abXc0ct^)EpiE`Ij%k^RZoky54twF5+D<;QL0Z +U_ye#;Hy!`Qf(Q3#+kx-g-q)86MfdX+qAnr=>o?%MN}X$j8LPUyurFrD{ydg|y*A>wElsICVw_564;c~yc5o +r9BTvD51%LO=)XcXMctw>vMnvrOHJaufmcC?~32Zuhx}}NX3SO`9TTDZ&=v6SYqYlReidf~ASzBnla{ +xk@vYdxEkEb_WOgVW<8dK{`)10A)1tzA;@4u;SG^Cti?hU0C3#=@hW;oRbM$jsb=WO8kKB|cps2IG(53%@G +;+qsoo3h(Q+}b-jw4Qj%Zn6<(Zr#6K}XrcLn0s3x#Dng6I@79PE*BIy +>|Ygpi(?`SgNJ8R2j&_v(NKtkfeF-3{%9V&rAzL9~_7v18*2yl(KuOw +7tjOo-PCM0HB$gF_LAZa-(zPLVBFAw{E6$u%ks5%ajM}F#gM +2Rwua|PsGZ9M}djrL5rXGaBV1;%h8hyL??C7E)%7(-;=uzeOf*8QQMkxpNXMmweW5Mv7XN~EI=#F +%l0%BG!;pop0IM?zmvWn(Odwrhc%SG<>;*VUgBO_RTA?XS#}{>hERcK9%~2?;S(+vln*gK(-OE!tv0k +2oJCZFElrSDoR?&snZb8tZxkdpb2k-Dr?!i4yMc9D0B(!@UcXwA8=bjJj%JtrXCmLzs?kn8^1M0496W +D9G&=C+Q?z}#Nw3P?jM9VO$o#GVfoR0GES8#H{8D3_XE~PP<9YSvyt?(WsGiM}0cuEeI-HFskE7BxSz +1aQ6Mape0uUh2xa}IaFN#Nn<}|et>OIhJ_(WmmDnjQ{E*4TXLjtE`ovr5Wwc4jTMV9JD?)VQd@OkNFy +~WS74`pIcu1{Ufh}S5KtO)q+GK&*%xN+7f)%^;ORVP5$pfCHOypO8;p42dMOuFAM@P0!A=! +$Jz*mAP5QnzD5Yf4_{Ckeu{!W%$*Q%U?vnhXgCn^!w`xbZIJLU5cw@s3b6wZCE?+z3O?d+33`Mn4;LD +Bba05_Vh2G7`jI?2ikXRnmy7rl!FB>4RYYj8U-9s65g+ogg!*73?C@ow@PWt(>d>?cKk~Y9`d1hpzOV +3u#dhR`f9i#TPb8L#j|%4WLsqum#eWQyt~az$r@0t}^7nKWb_zhA$L}Kb&XmDS{r5w)U +S6O|fbLo$?iRr^%%M&^PeV6=bb4~kw +5}|=cnV<=ic|?`*%22^413GA``5enrrIG5D+AVWW2T{ulLMBWA!_Gjwdy`<2@q);YhKCOe5^F0Y+)og +0iOj&eO)0LCjgO0#HF9L$h}7NT4B6(X39PGk$}6;zYhOutIHAp3bHgL%;bNqp!+frupR+hYz4df5Qnh +(w*(76H&7L!j@}&WWh&!+JEY>$@s!>Zz-BVI@v}(D~hPIO>4f-~x`b*B7H*CIj74i91HUo@F+LeM}K% +(eJJY@qD>N{ez{d!#T9ODIyH!cb(1(T82&<$VJ40%mufpeN0w$r3OM)!Fn+4$mlVrZNE)dY`NucyO0$PDxTLU@D0wf?f3{r?|9rSZ|CFM_>OiIPFtbKEM-?OALxCh#9n>4%JTU-Vk8ec1 +XXYluh7M7W6b&5%iO!i~LGoS$cqz;24>-x@&yM%J*39lP#J9n#9)4STK06~z=WD*CtgqM^;#Lf=`#XD +N0K0-sv7Oo?Smj4W#XX9|d2Z}($Cz_#NIrX)NKZF9;A%dbk|wFE=uSF1R6!-LpPYPCU=ayAFBu{28Qx +xNa4`W@#J_vUZJ0}W-P49^?|64xX)Pmek%25Nlei!Bf*N)QL?Mm`9$aOCbv!P;Emw*WXLwIz3B#y{UA +xFl4anUq_m(p1M2@_s2Q7umsCfWn{#Y++p1BwOB7hB8%=iX$NNu-^zCxI{RJrfuUmeDN#9%jM8QJBBnIxd2qjP +wr*IMke+Q3Z@IVrW{#$aSSnt>Zq>l747&>BoMEp_xfRBhD3I7HDp7xYNj#G(G*bl-!{4VK{xV`@gr-v +Jff(};>_Ju(86Sl*U!`%b@i7tJ|XLxcru^{-b1o}w(ejrYm9M}q?4pF!rYVEk^aCd=6t~d1IeA#i{4u +GJ~u#YiAA5xd(@G61mm&CEZpnnOEByeL{Cj8FFa`6TY=_~czYxM6DKWC%lt$lI);17VF=c{p7Ij6odm +eVai)R@T}9UB%{GX|)-iUH2-cXkx>>#<=5e&kxeZ{JhEpby`Qtsu%4e@Ox3c6hY$-;XK$W#LQO0KR2J +vv+|rc8lG(*Magw4K_Q^(w!f_jI!iah5oKy#~;T4=U3ek=TP?ew-HYWJcH@%-=E%VJ$aA52R({=)Ne# +bC$k|IGBr1yHE(*_jA%OU7QEmsy=n^Y>CiuKIvSgo{p3O3)Nns*7ZqCU8a16*^a`o278&C3|(aowOpqF028TPD}E3TzNTD)T +`RlKrQL7EyFyW))=h^Z=Dl!L9lqC*BFWBLL>L~-~6iHZerWv2~JmN4O-8M2vF|w%3r{RCg+=AIq8X;w +yba3SfFJWEnXNH%*OozHfNgb&uBs@tnnU=rwNYLOqNeFWH?Md1K{oAP>ynq%iy*K1(951v7vmhsg>NOg`-SsS!vw>~cB&4BU8M +WOr1c+rnruurM00BR7vMXWy2102&Ab)<2a@)U{tbzXQ2K~JJv`<8XzBrYxIz`W^(2GB>ce>- +H`FHoNc47;)vwg2#?W`wGA{X}77;u$y8f>A+h``w)$dmdVRehxqs~-?<;K~54*l6yPS_=~MQsInFyKs +22D3w@WYF{bPYLnA=8vg2Y1H&oT@xE{(ua$8QmqcFB9$lVD0+y#FzIE?{ysRO_^y9c`W8%P9tDh_!U& +i9@HC0Q-(>X{_V_?xaF#Y{+AtW1mJB+anUxkR`mx_7EgJNNW-3~|AFtf;3Pc$Lei~#{r-_ybnDvnC2MCenNhXEHJq3=y>l)I7aX|M!L7#Z{f=a!Dr|^Ez@5*vJ6K2+=4-a +H0RR_O)oUZ)2czkG=HaW2K~9k;}#5BP>!DKuUF`fo@1JsX|AK?nSRq!M8`9O&@B4(87Xv}?Hzm`;&xO +QeJ@tszX87rBoq9Q9_~{&UjLp@GQ89exZXnX3paxY?}q!{cvOThf(6oSYWr_tww}zT;{(wYf2Je+Oyv +Tr_o>|kM?JD@jzHj|Z^OHmfmp*KqI@B4_?koV5cl837p9EQC=`dP9^Tiw+&|bF-j}J&^9PYdW-Ol*4e +|Rg@K5Ro`?h|K7P>#T=eyck`>uzvjYQn%?lH2u8uzLn#&o^I-agCY19~=#>hF`$x~q4edKH`8 +H`txxlluJ#I{sy-&iQ2UyA`=zhqaWj6wFQMB=x$eWu;xijITRLj0-F3zaOq>x;QIJK} +9=re-E*`TSC3d*GCfVXqHNl%^$NXP9%CX*zi(abjEF{GZR@mL>!FPe`nrf$ +tRw)ogW#(c?iMrwuX{H{>8_kF~;++VCNGx?nK60CAD+8RkQ!nunKtRCO+(uNCH0*EAcOdh`Mu;7$md- +SD8np0I8R4O&pnTFBK8J~ksD8xy!Wtm=LvUlb}4TkcjjOD-u-}>IN6y9g=?(i##`WN^gZ!9o}2mc>ZR-| +wd?Z`_zSnwA^F8de*DVH9}}a|6LdK{wpfEE0xTrlz5~OVzekJ3qo$T>q(xsY(%C)hdNjSdfjo +2C3wiXRXHyMoJ1a3qpP1WQ&!^=>H0{|r=iJ#qoeZvvp{{~-m{*x2G%Q5`(q@VK^@!twjr_|y9B$A{2GQp4hJtR746u)RcA3+WNM@Av}Dfax7f8yX#LXu)1ZG`kM9Q%Xufl)_f`peZ*;?Q2gz9cw)XrD;pFlvsvQ0&NnB(TGH! +akLyD0Uc3;gKZl>UbQiz59Xu@osx_pPX7-|B_<@W*}?_?v&wV)|-`lteD}pdrg!8Fn(*@W4{8nJd%K^E6X0K1Co>bjFF3 +mKVb|pZim9!{-z4Zd6E4iQ*Hi!?aM8?rD;xX`;!AT7qbt~RLYf;lk2vVHYu#!ut2Poj2Cr`?c;B?gU{ +AN1m#Wd)0Fai`yZ&%qu&=ErM)FzmrIZzPFS{-~=Y%l${v^t-xw_`|rXPF-kN(-Sb;L<;DVqZdGe5g)( +Fh?joy`g+wVP?6XM7!f;|kUaK_Lw3J99(6o=>6Y&LS*^h~BH9+wbeX1ZshrW?+|HFCK8=KMK`1^X_W6;rw{Tzfi!cIE{MJ=&m(IN)6v9?Fa=!HD{jqur#7D~<^W@kpuxaW +C2S0b3(8qJt`-p|gXsJdRSZ_lCdy3wtW|qsh2-yLb7ct(dNaJ$uFSj@TG(ODD$CaP`!e?$TDJ63=pK5m)*0& +YH8#Rzf&mU+r`v-|LffNyaEaVUGM{wZn)9p1xHo&(lOSgI5r@<=kv}by+XZYkb*;TwTwKxIz0pR<}jU +F+@i34C^l%^PYvvcxeFC7R=O^Bko)M>#EEb`}dMl+!sLplROo0{vG+-*X%uSvzT}~xl-)aV_dO5YPfT +NXOSSb6u3xgl*s_JW>n!xk7ubecy5FtyJIhLVMPy5182yL@l=50i%+kyT!vh?&-1BwE50$FR{tDYK+b +zL3r{>G(aGzcp3e7Ytem)YicEoJ`5WBSeS}=pcWIyM%QVgl3PJddBTjd8!Ce86@VBmN^ZBNu3h5-GJ= +6}hYB@ahn1}xpwMJ!yk1I!C-Q=&O{930wGt^0~*3ifpBThhD)Coljrq7%cIGa}4a}fh9Z0!8Nmd=bbq0VZ3L7NLnR**CrS6V_~ +v%D&!78!01K$sB}oV;9Gqj){t24=3kEwUv&p)W!;%PJd_cR|4cuEE#Ws?$_e1Vuhxh{ZjX36h +!sZPa_IGv+R$S?SPLh;5O@N}ie(7TvvGt7_kV@mp>xDY&fpE&-BGzDtAKs(5xEP*B6qF9hE017#JBs{u8jWdZ&(S;0Yv4rLh@1}ibz{7y1p{kd-f_cc99jF7H?;)^e +fa!@MXb`ICfGUbMhO>6IAmo$?*`{I>Z|VQPv3QHa8E0);>dgg}DA(ftri +5->y%Bu;`5hLOKRM+k9vE71?rHAEgMcvNt3V|+m{5&Y4F`l20;{e}L%WCKMG%o85y>2QhefQ7`53fu@ +f#3c{P4*0-J(Wkls`4kcF0EdMCLjL5MjpL&cf*;HpFmyzmQ}C$5*n5PL!)Lq?28KR=!bj@fj-bA@gsThP~L!#IQmi0f&4{M{}LT(hf85)|1R0Mx+meuA#xQi$=0yZ`zdb^|F>>hK;8KJ*J +``N*(o22#(^u?A-vnE4gZ5YvZ4sJS%+es-(hOEB(M1aH-N8rBa2J^tCDlH?C1wo4zfn>K7XmWxcq#qq +!GpZq;!8OE^Zt>-XHGL`;Ph!8)x-xKK<&yImENvUqXD*ESxkLH#m?OD>jk^ +dLeHFWA(AXDdc0ng@E~|Zoc-r{B(RqRb0-MjyE%ElgTUmngDM7!P{*x6wFGTTqjYps8|i85;ww(nQoo +OMK#8(Z%C&6r)(c6pUUGX{>tc!eBpM{C9_>&LSWtp1j?iAkUF +Q{DX9s|Ul#ygMh;V02^E6r*a%;CwRg@zl#9pLM9-v~n`N3s6VIj2=qm1_nXc6h^i?^x);&JY*h0Y{ZJ +qv9#67Gqnz=qhrZNhU)2~u)MC{I_ndm{pv-fdm73a>iZHtat|DFL*cuucNXp^9{sE}LE65xcg7O+6T$ +v0)Q*db~EHon9J68Lkt-fjP~!*Ul}A`$d_6Vc%-WEy!N%xe8&4y&Dy#ccVRpV+)UqJ$a9Z+Cv;>aoN7 +2X1R4WM>5(b3Up-LM1ekwiR|vf%q5Hy+mmW*CWf2hsfn{mgc-TXIlyzKPLP+8VyA6nJ48cRxq&9^Mx+ +BU)Vx(gO7D*L%;#KW&o_eaFK>S|&cR(Jxi}CO~a$QP=2GVL(coW(2CykL*G89?w-*gm^m-h?Wp#p +?m3eV1^K`mJE%&`0|dojChdj8p%;aj;@HYE+oAhyshbDq!V;l4#U?u5t_Eb_8O+D;he@ESy|k}0S3jUmEv4E==1z!NWi2yp`lSSy6V5JG!A)zel+crV7SJmv~m0BnEsqOM=tJ*?xfX8~y +g~zPdkGN5uOF_o}1PcwAndC3$2@D!WC=pJeG`;0em0DjG2aV4$wC_`Sb0_gf;Q>ryB>9aot}q528C39 +;2j5ekjTZtScRCcLtTOz(UC;M4|OJ}-c_)|^@6-VL&~JA6{DDRECPYT>Gzoa$iLsmx{FA!c@8iLTY`> +rlQp)o%)UH&&Dr0lb~}EB26{z2Ks(-e}MDnZqZmHeg@5hL(5Hy7boMew;aTdV3!3aL)k3zMK_Y!Py(hROE+*fAB*Fn0WVU^ +hz60gvv?v(Wmo*z&zxo+tA|A8X-|FEZQhblkIaMRP6cduexcbIdu_<#QIy$R2Vf2(xbN!50BR~8>}&U +f-psZQ>5r! +uX>V3LUw9WN_3*>{tv54md_oJFxq`9NCAzEFnJn-_!w<@Z@kPQ6G&FEIPvVV0qts|JuY2SnCL6ej$k!xsLKN47T^n(eTF+UL7zWATM5vHl&eRL#`Z;>6X@eX +UQ3=0H1&{`f;A6m=~y2dGlmv_+A!y)MXMa}Y`ij{5g|MK=G%Z{RJwAh@dICJ7&(Kj^%(f1%)&1gj<5J +HGa_PY-n`=w;Du +K@kfks15RhHKdO->QOZz5@f-&vJe<=KF*>|LeU-<$~oKIc^u$cKSo-{?%7d0mQ+TL3 +Haw@o`y(reze)}?eG2KSGKvP!Q8B$W~NyB}8laS6z775_+at7s9kh+W6v`}Ij;+0EAIC)ilj1Nr7iPP +Fx+HS5PVu!i$EGDpxt7o-On(iV1Hf=J)QL%#QKY%9;-uSybr%P+r;Es3*jeA4GOq7)WG_m`pIwHuvDw5Pqn|!TA6JtkpNiyk>e4^Cy1;V-mF +X?TEmaCw2;sR|s>CmR`j$H+r}_{tqhz{@6D!RtK&8J`x!RYcMC#>-F6<6yMPz0)(1196J0c6+}l<<1gtzgtl6v^tGvl=f>F2ezbc@IGv`(W1jU>5Y1 +YQa7UtmO&b+|htBVeE!&p9CuYK}8xCIz!s|dtPdUWbU>h7pL+`Ijq +iR2wm|Cl01*yHE{a+6HJ8Xs0<5XoTeAsIKjLBfr?H)79WxtcE-l%0pdWYmT)G14O<2Jb*sJUf8oGTB= ++sHYjhV==fnAIG5l5CBi*}>z4p)q!XW +x|x85BH!d(_cjs@K>0gv#m^#GYTAzX*_V4GIr_Xei`Ng8K|f=J)d#TU~hr@%tY$4zYm8pKj8@sOV1(U +^0V-c$gq)ya-flV{5sdIoQWK><)qq+DSb;X-JG&%@rFKVqbMgC0h)Yhs)kf8My}lnuxoLeiFr;?|>;n +~5%50S78DDPBBZZn(?R9MnrtdT-UYpHLQg$&l`xX7{IV!`!>B+11TXr%O?Y&!D&_@qFfUnE-?;=mMtJ +64+on{)RcoZG*Bxs%Zz3GnZqpEODZUpwf6>^`ZJnv$uz%?6JQcZmxC*);(UZ36$0zZthR_PpbuQk@_)gehXH%WK)Zr__ +E!h^5RfPOUs>&OKb*k+J816|*6#s(GSCA@zM?V>F3DlpsrYyLgmhOr2CZnMBJ-YVc@CZiwH>J@Ve4m~ +$?u3^244DB~##)g58k`$v{^6O%B91fH|8+l?S5L!^C873ObH#JK;(&F}doPk*jy{z~)im{oEA%Vj+ja +9;o54<_9mX1#u;J%8xt9WeBtdwtQ<`z}ZDfA&hhq$&U4D!)lqes_Q-ITD8SXXb@Wej?Hj{|fXIi5!zJ +X?kEslKhOS6h9H)pEbtm50hW^sgF`0=D&|(Jpmup-xxoDEQ%bHIXl!$KT`5;b_d^7e(>C+*)iyY;YUd}Ne}%%82e-;u}_lqqtA;Rv^Iar^gACdV$W +YXMA_f7{C-4s*xR?Al)Se9>c;e6F`0a~M-Tm?k&>>g@ZsL=*d6s4zafM9s+o7BD1ooIOZe@2cq?Bg?ITfar3is=`Tz&-0fiZJ=#too#UY|c}@Mxwpxb))AjJ6{{H>_mD>aU= +>Go7?E!yue}8m)ACZY~<;Z_76|-MT#r#n!W{)Z7kbWc~SZ+-o#-Vko@TRy^Na;t6mjTT4vbAuxNss4b +s3^sy+V#SA?>IUsvNe~_TY4oEHXX!J3PI>xNF${=Q}7;IW-hBUAUs^+IxzBbx9eN(8gH*T(GC4JpxeV +_PQvug9;pT4cL=>Kc;$HNz&n~=7w%mme5C^5Qgy>2UG9x6fN0!FPYa%>tlq3b@fxv7JWmTv?k? +yJ7PWa#`U^*KE+NO$6R11&W)W_#3)56K@bm7EoTJ`s!P)MNUkI%wwQN;6&x#X9SZ_VgT+fT>2d2buXm +SN+8K!Q9v8D<>oyw<)_!PVh%4A3@c;R<6Sa%_!z*yIVqIENJF&g>D7)oDre1Ki=5AO#c=DWD$H+jCx2 +?#C>!bt571eBpR!ZpfNOw-@z%lEiFKcvk(quXW`*{>oq%M~zQ*AeuP9IVs_774*dA!G+WhsJ5Jf#@m0 +L$~p18hvpw>E_b+;H|vJ5XkIMzOtAz@Sc`Z2BWRrSR&r8RZc*>j5*OY*Af*QI>pz~=x!8~@nEB>t@ezRt8&eFi&HGs&43Xvz;#^~J?iRpaa+4>7_k8;sewG;@Kl`ja`}iaTfV;o*yQ-63XDU-D4vu2(tqJqHXDwMl(1i733q>;xBWn`c8F+ZNR`t}mxzQ5=d!%1(#@fS~h*)$z-5Td*ou!<}v%l<$?DxZuv+DIr8wdOk5#9aEFWa@kn9)Dsj^r#!q=n)4JKk6Mh;xOW +Reh>q +R}=oh+AFBi%}dqOYKn`&cDVT08l<2CWF*WXtrj=_QX!u{4G*bVe6x`2nv3j&Uli&_r1N +-BKzE0)2g8!?X{@KHN(=V)~Z@+Ze?k-7Q_K*cNxDVqy1bn+u=WpLgt}Di`s1;OxVVx|XgD7zN-RtT=9 +KikIcE2GO{q;^?!zEVc_?xrof2*_hHr*M!es^oapCMLRg|{oI=oxMJxZy2!^np3gb`uLVqi#)QM(CO; +u~r72@dg|nEPIi{sLbBrzp>M+B$m^ye~Kgrajh@2P#xsJU<|WI-CN7JyqKF5?{`c-8ATijJH<}r7DzE +l-w2ya!g-@M0!*(uo|?P)eHz04bpZ$}EZ#Gb&N3ol*bOU#g0NosfU#!EI#smc7W}%Z(CKWs8y)fr)ZM +yzP0s3W0xypez^oa6-mSO@cVB+HyORJ3tPYl!2dHHa*?1K7Wmz0Fz!`+a#KgKKgm=g5C61WWGwcDc95 +3Tl#?zawL<6$>j_bQ0q5FI@TC~u4$m1&a@fK5owI3I%1H#&cM{Uq=N7Qoq|1#g!k22i-fEI5QAzQ$XvZAYbtxXr(`nyS`D~i +ttX6b%xh-pW8G*7$u1g|nQ101!0~giG5EkDQI_6)wY|_r5&+P#>8KVMC87JPAQ1P*n@;&Udlu%8;ZJ- +8($%fVNRV1QL^X_pQ4q?bNw-E)sw|81NXUQvGPWYtgn(Un?mh(ihS!@||1h#WM^-4B#2Q&XU^MCQNCw%oA4 +NmJ^YV?f@H$aqE{#jvzgFr8o6#5f9?AN4@t=%Fd$2WzGc$qVsJGkoqP(@9nKJ96BFegcFk-Y|+k}hKf +xr(1)<9Y33S47h>t4YhtG?S(HBs{#mLU!Sg|)=+98t5OaEiuvR7GMK@ks&DJIva*?{Eu32nxYS1pfh9LR=hCJoRbGNWSE-vm-IEW2 +imGhmm7GD2b0>4q)~DtN=tGLr%nJNQg>~pDaBx)i{2{zumQpHEzC +pqxg9^9kx(a>?Uh>!;_!oIfrqlAZkU|>ofneP4C`+4^ZAB3UV(WVRKM`H>0nT+}(#+XCsO~PfU2tBqpCy9RNs`}qN=YO|HG(C{@bXk9I9YtoI3Tf+sS!P_yB5 +yj7n8I3gxvD3gG#qIxqL%;*xk;2-`2gK&S9VM5fa0;UQJ_Qy@Nw@w8BWK?lB6Y8qZ%cvhDRW6%Sj!-j +gz-q8-GB7I38&a`%G!CgkfH_oA=fQ2eyL>CvaK*yv^DDi#tn#&8+@Ha@WEs)}(9mNqRoVgXp^14!y@g +Z-g{`R_iRoDqP$zRDEe6!cuJaHvfEOD3;Od6orC4PZ`Nj@$gLS=tVM%h!hn8~MvnpMac-5ngl +k6%M5qAzor!`hDYx&{-!CaJ=v6(cue*bg6!%IhRj!_rwST5~^4o$^HgVxoy8L!5hA+Bv0`=#&z+yTk$ +b|?Lo9$nwSpbn^feL@P2c$TsY9$IKH~09}7eC5||9n5z!q_&h^c>5lGJ%JGiqC|BpgdWS&jg{dtPaMG2_*o{{4!bYik_&>x^GMJjF_&7DJhnWtiSVU>mX;yQ6K3|`7? +)z)i^j@k3QzxVcl5}M|AG~DSSK>$oVNPDOC1LAMB*YORbJc!^S$`KEbWQjpYvI7U8}~?A=iqsg +L-9QAsSMU&(FDf~PC7+V21HNeWMjv|3sziiPx0cmVXlF}izAdsidUm%2wtgyuV%q(zE7jCqw;VlW&ok +?-_#@rlqo$t!bf<_BEwPet;9^c63KcqiwRhdAj{CU;!F>wZ4GZ)W&-pJ)obk?{_dH|y=QHOP_VR6Lx) +293Ej#tg_3*$C`h5H30nPg3!`L>AoC(u;^H+SSpZ-3{7LH_>WOz+wxWSjs>K2z|rVGD=w-YtahQiz@S;>>i=V~~QavhL-b3KA4wyq`3s&{fwK4J_AE(79h(6u_Fk1`i?QugF{5MGAfWF&tZOtc=auZx)nEr +)iX{;#7d^j||&KR)b-s0#fCRqcQYq9KxiVG`Qm)RCGZP@wZWxHU$Y&RULv3Cpb2Ha)7vpPF>>i_lEF)0;*bnhpJYclaX&x)h`?W!>CIC+o)<=XUx80eJ_o91NrjhrU|gL%c}|cpF_;Jqf+j6sYo#cDbE$7D#7%zVjf9sSJY$67M@Ieoas3rv9_hM7!i2BxN<)9G=GL)0Z(34RY& +ryC3^W7jqEy#6BG9|@Yb+Cv0c2%ZLtO!06}8JdI1Yi&ia>4PBYeA3Gk6d#X=#CUGN7VD +Vc2J)BMsxv-RH(s0dvwgu(j;8dB*r;`>Cf)3XT%aRGT)Zyb$T&O!6(oMIaC+ +WmAYb3h{sHJ`h^;htl;do!ExsP|`HnvWG=6gDXv5f*!KyZZ;&r)p+Oa(E({_2stGv}*;B)VK7ESD!RB#xc8M%v=?S{qWPVZ> +X-)}@1rai_QO5#-H8WF~RKw@rVCDQnRJD|aJ*oARX{=S8<7;?%+p^XjDT_ZqRh&~Iehl-E?9igB4ObA +~ge|4RQbd9F=!=(T?7(##EJD4)CuRzoH9j;=`UOzM)=EL)(inq3)x&*6uTTHMlqih0g!{~KmqZ?IC#k +pREb>JvODyd@bub7w_WkN)K=9ad?X)0Ox6629Qe2LDN++jSwCwS6R)s)}i$@%ddUwvINq^T&u&GA5bh +e8J(*!)0@X4Gow?fm{^akJthrrarx;$V*1@u7K;1YrgwVq7!lE +aOhcq`zvaRtvq$=mWNm+a!Iht{P=UeL-W2F1$~OQ*q0f=Yxvh{% ++I09U3m1XUp7)GyYyI0N +`-;H+;6%Ua+{6ztK#YPvYJfZBqEU*#PzXf{WCvdu4dK{F`T2L~>i|sDfxZqrgC40M3OR~!#|Y4loX`U +>75M>#sNyF&`!4$0!5a4A;MsxCj*Jc}(fG(HVbDRNgB1rP%b^eMf(|lJ8a)`y@$4tG_yPLb0pSjxj>H +x5nMOws#vLj>+HUqEj|>aI-_U#hj^{;S{w&NfaIOx-^$ +4a+Q2s15)%Cf(%`e?BM{#uU>cg5G+w&=Ig_C%%N@@dH*tMoSuXLqocXeOj@ +GTE5N0qmlG>wtMHHbu%4g_t%Me;MeQQLkL>fb6QXy>*Ftqwoz0M2FYM9tnz`dPKM~rMo21h +oZusmK{5xk*>0=sJ8p_KA9{>?z97ARwAVJ+W{W#dfN9Xvq?(|5VY(;kp7>S4&_28P4#ADSePcl4J@a&c)`dQ!; +FCS)B!uQzG`_+@nIC{$8e5`MEge02eEu69nm=|w=>JHk_!m$1=S~s*ty9GCgMFN)U_K1CxeJqWOOF9>}(j5rENaPo6U=OKf8)NYPU%6|5vCPjSMUht +!0mB63*4fwc6?8DuS9%+j|bBbr@aEdANPp3!-F<7F-L-Q3!JsFD1zDSNy+1qXZPVe8|-R3jf7taFxI} +Y*iEWp3x5D(7+92tUt)gd0M2L2s~c&r-u*BqigXCG3(^a*@~0W)X8>p32A)TO(*1yV|Hllyqnj&!jo5CU+Dx8{k4u;Uub%d9skZ;*)MkM*HoGRR(SERoalE}^t +UJZwFSix8YQvaQbG_$(By7GKT!rr;}D8K2!ih~eK)6@V}~W8;-helV@FdvjvSgs81bo6XGh-j$k~2c= +rQcO1~mJ`4F`o3{UIxR`=_BvETiD_Yy}~Esn|{Iz?33r4h*wg)-c=4xEMg55?;$I9XvkeRWOr2+ +ZCROpWNOniy-yI}l%l}kV!OYSx)+qb6HTsqTR626HUlP6>gMB*oYi2i=Uz+c~7*y|zb1y$^`IJ;e^ +2=HGi`wVp$%X^v;jNhd~bze7z-Iw?HViR@zRASXLyw7TV>GB-CK*d3?L`-P1R4OaTfxAzC^K|tl^A4! +dufgT3@vt89ay*!~_SHnc(GVc^WPKOEHDeev`IzE5(!9$_Mbb@y2f_0vwtPX-8qbHQ +&u!?tvo9h-{}S&crq4AsLwwZ5jc)H>52+&@SDnpT^f9(BK@R2CCMwYeqt6KkS-n{LaW%c{)|rOXPJ!y +}V_9-JSM?0Y)w$NCvj{Fi8$miN$t>6k&)H2J!+opsA+I#`2`RW>`{d>iG0) +w&d1`h{4PIe@_@DDR%k$hxt@?%hI$Kp_S_$rz>vTOJr5PW}Nn*7Wp?=Fa<4=1w+9lP%%vQJMKaZohwo +(lbF>tysHTzK$YXGdQ=o&Ui1?anU#%&+ZkxA;s;AC2_X(Ga%(dk_re$C^>(BZY__#nYo>EIw+U`+}j5 +2G9}h&_9ufrt}fYX!7sj#_5EP7l)UFWcqVKMjz=M_e-}KI|Eb{Nulv2D&I$Z +Ge(!L5z`x`74z~yV4ZpYPQgm=_ONTw&YUrQ`7629FdFCv0(T(BJxVXNtCw4x)v|^PmltzH*N#8=}Ng3 +vlFa4W>ln|lx%|4TT8Nh-F6g@U}AYn%H9Fj~n(<#Vn&3T8_x04+}K%5O?HjgYT`XuC@5Q +fpSOyEk-^=a1A2PlJow}y520^rxq;6;yeZ?)x;Rd1t_bUrZpsA{PT70u^cB>#Nx{PA33hMBLnya0@fP +*gjg_-1f4x8u&YHcU?!*?6q7LQZWZ!*&^GHF(8Vw2fWvBYA0p?jQgWL!Rk5J#qi`ngAT|MQsM{ZeZ9QOtmU$_M19O}F?+k;TPfD~a^5#N@|Z9(k1FXh +4aRgYWi;ZJ@)jQu!xdiI1L;{qlR5@^fd%CoZDtpD5~2`#_qb4+O3LX*aL0#K#F!cD2g1bGk<}IOM*K8 +RjEqsQyzi1OJ6y=wmy}Ut6fod$T^PBJc4UV2@9B(mBikNLI+-~%icVn{2;J@N9aggEFb?aJ67hE_6th-z|ST2C2$NWAdz>c_ +w!u{^2Px{fI-1#;1a2xcS-n$OZ?{B~eo~b$K@y;fbP^vV0PRNS$f%U><(b|mLd&%8b<$`CSY&Umc(`! +x&uXr*iWuuUn!L!9H>|3%cDCtn||j$JMMcE*^U^vK +1De(OMb@i64VUWHP!9)LHErg#BhiM5ZGdGH>3Fp!^F4R!IxXg#K>(~&wcZqfAd +;-o!7GGlbj6d7kl|~wcTuXOrVcx%m^y;L}gKlU_=qo9XvKqdIo`RHE8^&QTQ|7q>_;PI9&Q;OomE$vB +5AVbyarI*M7>zPq<6Ht|?0a6kjNq(XAgC2aVzaJGMr$m?=|JJE{*0YaIZ;TTW#c<&+eyP1q6eR<9_N^VXf2ODR!2b-!X_dZu?5q)fxwLA$b9h7*GT8Wz=35X3 +wDeY*1kH|S}o0%;jl=ZvOY$vZ{hT!xf=^MY}D#c#2KPG`9Bi|)cv4~Ge{dqP`8t^nW&zXk&?lNS|m}xF~!w6Jo{4XnhrLmj9yBq +2ut=wO8AuQ*vQ94Z^9xOS|`PF9f*wFdu>Eu~VYxTE1$|g>fQ)2l(z{P`$A>bbd=d2Yb_Mo8&ucgZr>h +V)qoQMxoaX05ADlmjj$`GsCQpk)@{cAa_^=h+E&Vop*30+fQbdj24O+ArelHKDl%QQKN|)q(C7&Rro1 +mZDC;5$uXd6cknm&T`Qw>3uR+w?UmfvtM(*sX`uwT_zV+Vv6E|T#L_bcUUlT +2agtM9l^%l!FJ1d+{bgx7em(}8iF59jiFD#Zz8$fzCMUEfRTc+uHf8ja%rrejsnoWF=C3}Y63~sPzL3 +TX$Y?i)0;>#s#9sjCoskyQ2&@S(88%*QOLu-qi=#K6lB$gJOLFPev +bxi94q$Ist;jh!d6~*(ba(BDHGm}B1YO8H+4~dfrul9&UVK*7S7+w><`a*U7d6WqpjHNklX+>Ac*9%X +f*u}&!%U2`Z@+We@_k*GmgE`feX==-J|}vkPA1NQb-(m!X(&$*22RmEn`FO|TUZ<` +jHmV{H^I|0ci*pOyR4$MPlj3ID%`WYeC=C=h2>o^uM|NQ)K1L+VE}SgcEDE +`Te;Ks>h}8B`{3Cc=s#~{XuAhH7Ge79n{a4TN6{vlA?Kj0R1jqIWmP8O5BXNwvF$_lu1flT#Hxz-99r ++MA`Q5Q6_yf%7V_JJhFFSN0m9(%{}z~WZq3IBwZzX +T$MF%`-9gIx)7|>3=3KRA9zV0v?x@N8W71Svq}zR+lZV{9$VWu4>Jt85K;2m +Bp7Vliw3P=$hGT1|0UWX7%%aeL3(*^wDTgJ;X49c>oYu!09fi`+T7i|tv^TM3ZdxXEEGHbR$0;g_y7GrGdG)ygp&lJ9Z +m?Ok?!>HrpSClO}&BOqg5>kS#d7R>Q*lrxIHKnG!quEvcXdN8>)||S=!L~yq;v|vCpl{rjrZ-lwht-)(@d{%;s&2~jQok +K{KF&To3g-ZJtf6$pnoBbtaNP*5G5_2C4pueNiyqffD37;-9Ky>svY3OPMXHvl2_IAwWU3Mg3O9P`KV +t=K&P0`vd@x512A~~Rhnt3LW=K}lHnIy@GG)m`e)+@-z+?2;`gXZwrFy-qtG5s-=E_8MlFeNW&>Q4Fw +a3e4Se#dp5GaIC|0aKqlYdT#XkbZo3M53|JNVj1ZgV~-%BQ1DX(k=;yp-51Duv;X#EQ8!Ut@nrf?o_B +2AfyD_c5!ESqDk91C+|Htc&FA7c1ixiQ=bXmNtj5l*9^xA;82jZO^;+eOW}yb7=8BU3Z9L3-gmFb8HX +__yXF*iVACi_w;bu5^(Y+rM`&d%%2(y +X~gPEAk?H!;nDMPyt*^Y_p#qu#w|MP5U!T|lk&)3uP)X47g>pGvE_anck +NgL2DJPA7r?~~;DictBPfZLgc9xKvo?WE1J?8r&r0(p+}mfc|b>vaTrsxB$A@GssqCdSx6n+e^~#eW%Ki5qkM3b1s(*C;K3(>3n~t5DCsl+98BXH)-I=HsRJ%|+pWe%_}znJxh&*`x+%Gl@YCWM-cyaA4>5 +cOcpsRViG=5S1_Lw`CW-yR-?ngiPDy~YTg&F>#`QG{p;>5LL_Nn~>xAXpFi`@t7@@}%V69v)Jiipcgg +Z-|wSje8xZTpsvqIq+Pl@~UtKoZu$4sG@5N&6;u^^r;zji1e3=Gv?g&}#B^L)`exSx +$QoHLtO?0H2z)BB$Sgak&jxBu0PrT?#X +%k_4ByIN}4(m9<8aLrZvVAEu3(dX{3FXK5-@-&F0T-BD%(5sgi?HbqFJ%0d`wVv}g$T3iSfSi?QASGE +Dq{JQku?b2)({U6QWN-7VhsH9kpwesAj}Bn1JCy5&tJ2y&u04-x?;vCVM*R{6nsGDVMAo17TVo9 +>k0>h#fx0-^n};^-sjhoXYVKv+~*#=EyA#jqEvfO2Xa>UBS#8Zt*0I$hL@ST51_h|^G1Jp*ULyGqH!n +Na;k>*$DE%*rLZ&curM%%6cD0jIx;n}9FCi8UsAO>7@>3DKQ2;-2re_0Vc(mR +-Si_2HrTMJpka9C4)qKcj^{puyRR-cEdFSk01E(T)uO8V^cohv4nju%5sW|>&K40%Md46$cm&mI)q86 +p(EhiIB8HjaN=$ooeoLd5@S!SIwXp6T>Eb4~lZpPZfFkVA}8pL=a2iW3_{)V#j67ohmKzJzeRQoTP$Eql6DK8w1yp__+BH^bt +g|-#rudR^!cv{z%DT+{Cs86t)i&IqB7ze!R+w)~TJS9<_7`t-i1(W0@W@>LEM^Ps?-GE5vT}u-N@8*w +^oIRShN$y_o(*Q#|yn&?_Mz5@C2pY4;4821*>FCf;Jlz&U2QjflRH?n4BPfLmnoXOVcv2p3eC6<#&~l +*4k+;RP(|XVM!|$_g+LKEu^9|xc<-82|+!PQUN_%t#Au~owOsegEiI=0KzZnh;AnLR*t;W7W+>cVqh1 +Yn7@l8{s7k0V5%tl6thy8bOlc}4W`48v9{DC0T&pZ7XNByfO`HHLl`~<&6TQCjL5VeCU5~q+oU`3BPC +m1DA9Koog(;J21@20chSgFgu_ +6goNvk8D%%VOgXOsFWl}Ig*Tz0jA`Kbw=dF%m^P>-%ow;)qgk_k&pi8mu|&_YKS~~DEE~oA6fE)J)b& +yN_G^szl4w<5l{4}lVZsM2ovnUYv`Y&E#yF3)IZUds}A@&j&%Yu1r3o=Fq>lcJG3=_NbZ618!2)Jl7B +%```KK+$<}Ki9GvtwHxS+tQr-^+-n9OrN)CJuJY>lc;dO24b;mxxfonEI8}1$y{VpH&Gu8Z;d{|>xu1 +E9k%3i!3Ed5dTDU+I?>ype-gT#TO0QpT}5<8ggzY^X5*)0Npc8`B{i@=}Vw{N38;XGn8{~AE(hSCKi)EBy(qwT_$|clNwJs=S`vX#>l8Q#*Nx95a2=p6TzZj<^C(5}~1yt6U +3f6cEUai)UhN~b>U8kACLsp3FNiU62yiPVsbmB&!gY;Af6lVlTkfzMQ)JB7^0!{fm1%Plei+)NjK~3(6q?Xw?&CvI97mTwB+1Hh^%?N-}!D53vR6lBnE +qNq0-w!;|t)L;qqB~Htw@qZ%~Am=JeS1Z;Op&W?DUyP=j@Gt<>Qz`b8KXV5XcM-nEDWOi)(km?R-B#WuriON)6z@cgKzliYZxwm! +$2b1I7^m~lJPc4yi=^P^=`z95a4S3(E!ms*VvMArUrn427p@1XHVAKkby`CqetDEb0?nx>34eyCg&NtGP@?pEOW%CYrYQoW4_(8^=&iaYI|bE)+EtKLkB|gI4NqGsM;5(bR4YKjLAOt!X;S;R{70*!*ZjI_4$UTx +^eX_$*o=eoemBE2k#vjN^&XjMVQX8%k9Lj+fJ6agw$%4<7%GdgGVgB(OCn-#B%kO9X!oJb9Dxo+yheq +2Fh%|B>a7k)IRn{qsyA`^yPS4Y;O;@}$cM%wv;&jtPHSC$I6}qhkph!o=>}SwLLNztgI@NQBbmE3&wUZi04YL!KX2-Uky|M&$br%T2 +#DAs|e}d$30(yd3y?SzIXZI21}#;gXp+c$9~0T=qnu7)UMnr`PMAzi-p~_GtOh>&!L)*!RsoDeDOu_i +JKIRVxiAnTW%&D1>nujv(6?1a1;+AYKD>h1@apVCrWnuT|h0xKto|Na8J1pHCKPDAl?1e9Fxo0+xPt? +Tj$Orbi10AOm40MHsp|4_t(+cjhvW_689d +8Xlw^oy}n&c$9)Na6SPR7?j7H1`Ua0MxwqUVKAb(wHVRz%oV8(lnF;InQPZwMk7|)@GPzSTB4T2lF*9 +)<9xHbB2BDULnpJSAJJ?^Ub99_S=NL16PPJ)jqXD3j=_W}kyKiFT>~E{7*y}*TmhiQ!cv6d_R}gL80% +P4RkO<@CrSH`#h~75Z}a{V$Xhx?!kP=X$EjIjLOz9onavWjmau1mxj&NzhY4|oO+O6`9cz7jw-owwSZ +CkTU-svkj%EL%r~UYN-M_(y|LVRzVB$~h=WB@~6kFjTfujToffz}U1V%w50j=A&jwiW(`y-r~rJG>Si +tbim7!e!BLy*mPlYn>FmF@mQ*oN04>_;9DWVQjgPh9#HsI6cygnv!I4G-e+#%9lmjVqt-7D-9?SqO>z +(Hw6|Z1nk<+5jw^ZSBf1+#06ouAYtTi)-ZW%d|d$+;J(suOt%a)&eD|eWV!ONGt0WJlWu6jBI3$o#r9DH-Crn@%O&eZh%}>)NKPeAo&7Ev)!S*yt~?;- +6h6@H5x>XO{{5%ys_RWdeV8oj-#YfzN=E=4;2-bAp4%Vgc33=lrN&tjxAm$jD)-XbVPXE$GfB%ee@S+ +9hl{syi|Oa*^yV2?%}8O%=?-a~zWATMhbnNM!+BUO^R32K9NK-{#@04B&b6WQA5P@6#jE?pL5!Bf*UEhBQ8Q~QDsOmKxHC<*)H@qDmhV3cYAEia~LPDQe8MoFt>kI2xTtCMRzL|KH~l)VQ;M +UFn--FbH{)s*MkFCH&q{arT55dmnsa0JC&@l8Wq)#fd!omHxA=(p)Ltg60PNcljPrWuk~!LtlLrxtbV +>K5ktD3l#QUQFRws0%(H&R|~&SHov2`0z*?^-`cC{31x5iLt3n!#bL%?%4>%l$1t}$QtRzCQul2%!AX +c>jx6@rL1kF1dXb$(w3n%FjiNZBxf*}K(aFuN-y)-3` +FEg^&h_)}0Hx$do`*Le823uZ_T4B5)IFJX|!m3h`(0nouxGW`^2$bc-g*Uhnb&R^0(R3Xe^{$rGKYRR06h$bCzz7&Z(C;$8!fo7a)70K)<%n!Ua#^ +yWHE0tA-`bz>PN#xbxCMQm!LXBw<8aq-*yr0eld){Wp(}{PiH*3h;>`@)n8({*<4x6pSdRn#XizTO`m +Z>+?F)@|5Qy(UGuuuz+jX8Gc;i8%yS4l$;}v9o6x})1QL=%|^;PS0@Ni>7B=BZE7H+GWf64qRH|E#vH +|Ccwzk|tboheZ!wN0^JUFU}|#Se5T!k1u%ZB{)1`H^MyJkrAknh}^b{s;;&O`+ +s(L!97A#;kR$$G8mr$obVNloM~vP^|CJM^Cv(+ej0_RwT(JAa^sZ)*6eS8%KpxZgV%(=eDjta^~WavMVB-j;J +nA`%e@*IMsn~2>S+wHEbrF13HOHrJ7+^SQ+Fby?0J8usAs&+$D)&!>Ac)K2V^yad#be{m4c#LAbO22k +q4N1@TRV3JaP+4(JRk7zlKRw#Qb_|&-ch|gI=FKDFj`}4{!O;H-J8oU_Xx)|NaN(_djj%^Fs&t-+nRC +Zvyr|y_1hf{U^`*Dn6qKPCzILQz!+)6po@KNMaNS!_aQrKoJB<5h(H92n~Z<Z}A-4r+|{(ZW#=BcSvdv+r-AfT@%52+90+IV#Hey3XZo%6TbI*vR&VTKz8L~_*XLis|d}Y_8OtD=| +_Y%)v~xt%2j1_jO~h|Vh=f3)ABd8N_liR{tjrY{HcdAX^{zU`eQ=3PaGGYg2-nYEoWGCzaAOXOl{Igi0zMn{ewqRP?LlsP@TSI<=oYGe8sW +o3O?2`L-W7YArWn&d6#0tpyl}Qk`Pp*{Qq-5`Dg}Z-DA-#0nsE&vM11;z54;qnn+L;ki7rq%sCF9SwG +l8tr@};~Qoc_qMO53tl?!7}uoFGZDZ)GZeAULGTQzQs&#xxX4Y+7aLcf%I7B +gyq+5A95RDBYI$HdQZTTf{@iZJ}=y0)ux~^Y6E;H$E-8HI)%?Ye$FZ#_UhCP27A9XW4#)73(F*Mub4| +o%$bb4~5|m!WOi*xud;#zMc<~Y|ENpwztL8EgT}~7W`JYyJ@#)+u&h_?f4VgWO_E6T4Ym5fRJA^e53h +p{dRB{T%*=={YzjeZA+1%^(Aawg-Su$>-!D)7~7<3oK-3;j^DDu|EaJA{r3%9e>k*7TsqbAvddj#Z++%?eNxOzduCp0g8H~SdqJKp7GCNRW3I#vp7LzR$Mf-mFph` +q!P&A|v9G$ZdRa61oXbFZx%W=R~^3RWFvja%DxkldI@pnhJb`CF*$D}v%By*@2vXc_WxGx^}Lfdc)*(dgm2`1{r!d!Xes#)|^6QpkGdm<(=HV&H)U<5<7o$jnKntNGnPqwAWl7 +<3xo@Xlc&}VSQ72k0g+ZSy(9ROzH`%KG?JJo}A_kOyf*GVc|(;F@ajI)4>{+;7KDt9S5yG4EtY_^tG1 +1>;F~QBx&=zK(vdaeD_J;#KM1RM<4OyOR~PH#}B+MaG+(H3sfAEwn +jYtpE)9zA;2XZh-}lHnkHB+NPl~YAa(mXhv*f(IB|7#MaogDGl%AI-9Uby4J-%5>koxk{H|?HQ4Th8X +?_l8@VAj4+{+0;%EwOy`o)ncngkMvJFbFIBpG#o0Ma=4IQmvcv~shg&X0Y;GJ!QI?((P^>|t-i +u3o!pu=ybpwEE)J4bFdA6*AAZ&%;Q1JRwg%5eJ{iNbsR`qr#&R6mCfj#cbL6mGy8c<%dzOYN>-mG0_c +_rOEH4wst($)~8dY*A0&HB)j>tM;fTqn|>dynGIYqgQ@i0o(WAJ9j@c!PUX5CxEhORzO@Z=fE?oxSno +NZB|jqzclvCm~`=Hm-Iy(d7Gs^?S8B4%`E=lUe0`8vAxjS&CVa}C)zSPKPuw_#Fwt~h2|A$*4;@9L49 +2`tF-4%I4)cl#}`*i3;OneMUr~OYP!fu!_27^N<7{mo(IVHtI(a{euCbq+T-z&dx=$;K>{3Kv6)g>dW +x4rr0Hh}JwWV)h}}%8r$b*ZcS2}=U|PsDrt|TkFG2@H11Kvq9}ZUT-Gcmh?u2b!v-90@_iW!`nE%?HnMZ*QaEc~#vMl@PA|9JT)mepZ +nmhaLO^N@(g(=Z)X_!<)OtAaX8r#wyRCkKO?cZVNz62KjTOq`QUxP{Bn0sD9^2qv)$f+&MmCUlV$!c) +&CmclqOF;$P9wW6%k0ktI3yb^$(FHexL)rhGWC$Dc(#Iyr?8e)OJY5gc9kL5(c_ML{-_y9D`$*&QfCcfbY~x>%C6F!>}QD&Jmq@Z|a`0 +@5?TH7&s(}KCIHer_c%fSjUM5YpTk#wv6C}=VaK^(#^? +A1PDNA9n#PdjrB&NC6c{BEc$v5)N4qcH%@8jp*D%?ey_hp5oY}#a)3+a7mxzJ%BMHdQ47mzOt6J2xdq +LOX3VZg%te>hIadAcIVNamkok#{b(8wATkM)a*Id;Ua*b^(7B}dRZaaZp8(DO&>0pMlBvMULVt8d<774 +h)7ipLsAp0H^f{SV+6qPVH!1I%cIP*WKbaqWF=I~goOGy)>uYlH&-~K_Ah#|G-?ke9O)V-DqbQXXk;?C(#opZBGo +r;X)xPBk!aNBD!k7BBE0YpoE>OjQN5Bvy$UZta5tjl^%Bf_AZrUXWqY>@s-nsq4W$juT+?=A5yjODen +mg)O=+L3UCK~`yC_~6z+^og?&)1;eM?1Xx1@QbU$m^$e^XIthw_SXTx>nGIe7A`aZ=H&8*E~weO}!|C +Hs0B$#6)hj9kFXOt)OWw=As|S*Wued3XyKeXR9frt=?O|UthH19AX=n*_N-ObOT;6weLIGp7z5fGIVz +-rJxPRq474DLt%S21mCL0O_OzpP%ENZvDXT@(tQeMtt{c)k^Ci~(ov{kITza89G6o#N&FPMC55w2p+_f*3IPH{yG)%MOHTaO)hT!O;xAj9#Lz=d4yaBJcF +6`|tWF+5{MY6Vkjt;w@P^q@}8NCE`MBXhk%r9B>^HOG!?xO{;((s*1NA)A6{Zs-zWVvo{SZ+0Zt)9cy +!Fyg%^apF<@3A{2r4cDA4au}n|!jX9N2{VR?K^jlC7)Z6m#d(>z^Ux?<^4dm($&}}pAjrXx +q?H%r~WzSF7J+EX@?CgmOq7fW&y__a={1_8>h)xJj~@gih>$XYNu%|=LuSLPACPQxU7YEzy`N0YPjG^ +It?os?Ev~foS!d4@Yb*jvzu3)5U5I^(Ne^BA(8{zHto~_6H+<5NF(EID82O8_*;Xx?1 +H8#GiG{hY4%l4u5l>yFKonL0=h2jY?XI4#}dXB{wwFy$_OeY3HJAA{Egcuo{O5`*UDPuE&HG^s@NioW +@ZiE4MyzGnH4JFxm{jRH6>-(S)AYGL+*zi5TMHib>L@fa3E*St^U7_~X^2XmC)*lOG*nWwk=!pRTX?0e?*2%#AxbaTwXIQ`y)#;Az25GTvUgv^E^c0tU3GGSDYq +r=sd@P0Kr*V2(kHSsw3?kvd+l7@zdl#gB=Trf3|5hv<=gU1~mZSepgLi#>@MZK_dNiL@F)u&%}OBt1r +*^G{V`wzM7{si1rjNrRj?ZyvHz7|xh6iIJkt0Nd)C%ga~6l&?ebBHxYqK9VB*5bbO0Qts@($zY!e8EMo53kC*jLnYYKfvzhdkHPn>#c%@(jzSaqb6;2nCgYiOZA3ZlmkV^TD=WDp*5{#S +|F##DM@lzp8%fU(c*NDirKK@^{ctQQy_~PLGB6n{Q6onNW(hxD#|lqWD2_*z#?Mm&-#A0kOhmyy8$VR +XMY`pHR?@(ZGYlfDHxl;J+TyB|IO3`h`Q-K{y^R58IpqZ4p7)IHxBd6)7XXo5lscibdOVHz82DneJ~n +0fGHsrH|)n3H^sX2&qyyjAxzmtUtk7A^6aol7QeQ+LMnMRMyh9%-1E56vgy}wHE`=TX9Yu9fMkENQ=~ +B|$o!B~Img&(Nu&tLQvrb1 +wfBw+|dPzuEn6huNTf9rLZ3HGv|E>Y5!R7*+)9W9{DQDh-wr}b0IS6r# +`aR)GYprxY$X1HALX@a7=fu}R&016W#}fI3DH{p{TuFiAZJ`KW3mDIxuWa>CVQd2(ux78 +|s+5;cLmtLP|Nq^_l2QNe83Es(($AdH-_fmX9HvPx*qwqnT_ioqyk6D0bq<#Rt&*Ew*#KgUk2TJZM;v +zzL=6s+n`H8fG2Z;-NVb_95V-{1tpzW|ONG)~O)Tv7k$I&`J>G8zIHb3jeJ{saSBE${gAPWWZ-;|5oR +H35)*>Ax|*kYia?plS7L!6gB4~U6tcgN2*Sh> +$H32dg}zj;8XqK@VmT8pgMC3v{Mo5G!A@U7|RYoG#&w7A|iV=o}8`N9djWQmmzQv1Lc%Ce16z35EAJ#6A#rb +q0a_{8gkGsOIMnSA6V8;B47Ftl8+jr|Jj=zJ2Bj-+!gtvosdgLBnppi~k!s?QbF*6%8O@wE!i4l%RI7 +7Rc|%yvE0G5=)H^ubC(lFZxiS0WYD`z^d<+QMyoMT44792aSf7m%vhc49&P{J3B`P>Aj;wa?%;w(>u0 +3w;l9eXU#R7{RDtM&>cRpVIqayyM!{inHEa|HJ^5hTnJY1V8URX-e1NYNCy*L8*HttKqE4_sjhW;n;& +ciw-T6!>Pay4y0;*HA(>fDDe8)8-sZ!<}YrlRyRCOqH={$P|nI{14J>0bf9_^Adm*xl6bg>@kSv)Lr0G>jIX|{x< +uS0N`Uo;w&@?s0|bSNfZvcoF5ZzyJIA&q>3Xq4@|wozy)35AL4d<}H4cp%1f?LU$rG+`%QJ6@p?*~+h +2~{l*Y34kD)&mm5M;2&qlm5O&5_~b)x4T2;KBY-7)v6kaXwE)r9_5)Fr@L(pFmo>fo03LmW);Kbm7s$ +@w4=OxIvvS3#NGopEf{`L+8hjh44<48OMW1P1lD^ui*3LA8(rTe6MdD{>dh~%_UH^ELTb#DhDNwugBd +!wLk^syxgPcNX}#w-)wjk270khDfH=03&*kFN>{T=w(UZNz?Q}52-c_43VaDR35rgR;m;%3vx +b#l|tIIp8ig-mfasPPzO>FgZul*yu`oZh|8eu^cv4UHiL=g%>aEkmM!a|6BO$*!FcG*5&K<#F3+gxn4 +^%J3R<3z>DHY59kHLdmO+gcK|L75e+QRHsGfbN~dY!i~))Q+$X0Kw^|Z@E#clFfZI`;o=`3WzoswYL# +Bhq!%;0>-zA3<}y={MasW32iHF>qZFN*3C$KU%?8u-Xa|D>QLFX7`6#4p?eFG+{QBCzqBI~f^B{R#J` +KM7BC?H1Yzla6Jb3@^~1w`7QRMUj^q}RSe3G%S69Rw;^NOxRt#y2Hg6~k*kIOI8%sw2J7)!a@3emQtT +v?eBahN=krpgJZSu(%1I{NecCF)+w>@9b2LYt_N2gh>Rz~b|T!dFECGd?6;g>A1oKe19w;xqdoU@{Si_Z%)2R0@;*VuUzJpBPmI+4*(m35%5bCbe$$VGPeVVq{Mj17i({!47e+ +RTdB>oislVkauJ`5qFl!hFP+ +gaCC#zmZC%s$Vb#hM1dr?Cm5JjTuSE_SMu2xZYZB!N)mnR>U3LVSH874LUJqB$HqRc=KxKG +@5NLl2|SJSvQMR?7@f^J%)%unpr+-ti(W^RFBZw-2?q6H?Jh>F=EQSAj~Z&+m9=961cE ++9_x?ey{`;T@rEIa_Ncgy~p>ZckX@#ty9n`+@g!da*pxnWG*GJFM+o+7_%=_p$>3&PqS-yLb>`DsYcO +!8vVE9N*MSuSo8!XUdHUo$JMzrsv`LhCoqhm-u;to!KzgJpo=QNG^MS=kqO-R*>8xvQN|D*-YmXT542 +AJpyyZvvGIHs+7xX#4o +0xYF{BO;5W~vH5&05ju`F82R!<6poBU&=L#}{{9Z_|Jhy?;T)hF8>DawKgL;x7qXc^Rk;p<;(VoHxl% +~Lle~K#0NHR2RP+lE-#HYr_@DSO>7*q*Ma3Nzb+xNXafj&a13X2Q@!s>xVdr?qMrSUVKZJ$mjdG*!Se)K&OZJr;!%l^q&~)JIeV1wdvnJ89IJ`?*Fm +5v;6xum1?EwFPlY6`ssmxZ_@r)rFmHWTc5t_?)bmO|NAd62vWa%{mOs)C0lV-_-Xe`n*8$a(qA4;HGh +NT{=1#q2U7g$^ZJ_0h2onICkB5H6>i$&@Gcwy018ZZM22kBV%wa3xV0N2_`9f(++P6`yQ +k&u#*2g-V#D#B@0IK=)O4d*ttc&uw!N;9j#yFMkA$F5WM?4klf5fk-Bt#(?Zw+P8M^Va)?KV{mDpKY8 +MN(m1)ST28@w$bt|x@18~EH*&!G)7ZpL8YK76~mdi@nDK_bdx}DHJd^5NOY}_TG +q@B-`TQ=vo@8lDt>SVrpUuSe$cUFJ6T}hB$1=eTR77qh~PxK?~9r(r&iS8Qa$3EHGqrSEc$|4^x)Yx0 +8TJ)@OG$!-E9R&D%lx@1Jju1J&ei1}}RsqXEG3?|KjCJWYlFQK_Qsqx`J^FU=t=Ia2^!{93odtKd`W> +Hg_fcPHWQC$LpxX}kX&I2-Y{9mT(7vtw;|=@X{Q~~Z4g22x0{+eo``-Nm{>}~i-u(jp?1tqz|09V3<` +Z(}cZq>@Ba7co!3<-l79P|9w`t~yM6LEJT*G`Ra4noY>2x^`A)7|jay72%)5@+LbhH7}LF2d&&f1{NM +Seu`sWHL_OVhlQc3RfdFVb@7IDWwSz&=tcth=*c`->!HE+l)K$%Y7a%c&{wle<|3cTs7XBypdehCkz3 +dVoyIC5RChiS_6*&O(0SD7mNI^!S9_JYbAfr#mVk#-?F2+y3-kjC%H1lw8<}_k~hPaHj5BJ~%wt8k5i +PF@hLAFoyKP5Jw1bphJ8a4F7Zvo-ZDqZBaq+SN6c74jh>J^m#?vuTD>skkBmCM9t&&ZBEUh07_u}bLRWGk8P4vEQnw4O1K%ABTM +v*1WKwk@oZ4hjUNiePYW!7vzUl%C3STo{{Kcfq%MmE;`)j|@$UT<(gn=Zq?;~PST`Z66(p%cQorTAS- +y*Q|YMR)+9Oo!Lfh$y(cXuR33JA)cfISTAU%|UQ`JbSYcx6msN$xFiW`1v8mFGfGx3OX#P2{iQk-UN> +ud1NDYVNjTq;v0B54B|PQJD-)bMk+Is;HzB5URR2c9-TeBxvE38i&#r*rF_1}q-q}_-gq&tLnkH4M56 +NWSLlvC6^NS7Df*Nnv=^wq(@OivoXWG%KcDO&_FHBl0^Yrq@xRH^$A*GJ= +Gt`Lv97`eb7I)~tL~@(&|E$__jyPgb0As=wUacT}(7;sj4s01Ms8-^RqCMYC7%^x@#Q(2whU&v%ujg8 +9Qiw#xxF^-Os!c@yzA#C3%So{_Ils$`LRN78*`Sxq0bcJ=<{=)V!CHrv$D3!Yb4Sie$lng6mgFx?3ZE +~nWHysaEE^C$k}HWAHOZ)Q!J1wg|x&B%s5CoCR00)f_xfkSQ<4;R0#YjpU=~7?)qhn +G`;?T}^h(O~EpekOKf@{yNv^x +?KWP>kH$jcT`q1nH%0gSgr!>oz|igVK=iXe_2yWOZY~sCNlk5RsI?@8;$8bB-E@(`orATW(>9BX?d9{ +vkNV4|MY$yakuuFc_SoC8Mw=v+`GphOAtk-btVJlu1x<8Akz$b|fXXHO7bm@ +sRHg!Gp759Ha5gmH~CuUK&}vS_*O5=LxXor|mQ^j +wpzLVx0EmU0(V_IgZcXxeiAFBc>j)(K@@D>)Oa;WUNR>QJ5T!4^5ATG1mwV +s)S0yWf2=zGoE6CNZZT2L1?B<9hA=+avV%N`BB}HlN6X}Uv^Q}chN0FAG~Zj&*VZM +8ih?bmY9kX3)>YZNL}Uv7xmItq?YQJ2YN8_GfFavie5~&ekpx>bDViC{Og#?8wvz3!>!NV{Oxm5nGYB +b-3B1`);H~q#YTr$2t>|;ML>_(RVa@7ohUjA6@MXZtY!K@sjtqXVE>UwqfY>qZV~Ue?|vWB4ch=Hu~_HdcRm7t +C>xih04(QN)%7Lhf(MDPVBu{NfzhKw2JqXSx_@LA7bz(ehl@Qn|vRYt4^MaM8K256H{eFhY6CvNz1MD +3td{=W?*y^;ZUz=cRXQc7D=PYrh9DoEi#0Iw8tBZQU=DVMoX;8N!XL-E(q1opGZ%|ifXSf%qRWig?5&BFZ3Yg?h=S|9rXz|T678MM +=Ls-J4-Aid<(3w2UYc`#)YN>l={1wlN(_a_pG3jgsRRXG3SKjVM=XZMf){6)exWw+m6%M? +{!{PK_gr%Lid70&J7*_%4c!cdd~173eM(y!qH?JLNsu9 +Vd3f*3I-D*+k(Wc$YESX0H!C;fJCPf+FaKYCm!0S9qAj+e*SFcehi%Ha}Ku+Y-UQg5>7Y8j{8_9X;Cp17U&y6doM%w2e +gurOb3LD%^1Gk%+RS3Aefy?30ogmzhm4ZW!WLW^6UGF6G#2n}5IvJ_P7IX$C~pZSa%)@@NeJtu{F%KY +t_*3kO=X|0&=Ibc|X&=lyjE#7{xu+FZ{HG*<-1;uqBBR9RN3K4UTVC)&rjQvschA^K4mRRAD=Yq1J-_ +|2^SHIyq@4|Qf`p;ry{ew)l(BLLovSL}}v%}fEZCi0{{$-;ki_cx!^2)zU%6=xI +9lW9Wdx32fhsmx7WAP_x7~x}DQngki7TFsy)5*=JgJ@BsH^VdXOldWKvKK!^@i~ce9u2FXMNEeS`2gQ +y!2EGTXp=Q3xIv|n-GBY$*)9GhN!My+nCR1ME$z1*B|=NKJbm)fu;2T(=Cmy=}KBty#AByB+oQoxA(=`HuN+?&wq~9Oer9zmXChHMps=@A1qUUe>{}rd$BRXgV|7Rlvxtx60$`4Qp#&3(t +U6c|RcKJhldrvG%r2*_?4ZUtf|J|cmW!6>tZlo8(S0{gRUdA5i_k#eb|(4vB~l{w!Cqd0i6fY0nVNw`(I-&V^>HePg>i4n +RS}-Y?kTjhSSlnqo%iVKGanHKrjCc}EbLMnVv?i`=0y?=XOIHMlm{&Yy#$x}r+-eQ95Pf{1PVtUWVt-{pI30mlqSzeCz!G-8kApsUWj47S- +l&!a|daVZ>+MYq3H>?{2T~E%>H!=R%M2i3Sf*AjWr}M8u4E*b%TM|Mx2L+0Nap=3#wb|aCNYhO}5sx- +j_co52Z0R~9wnoF6pVQrR9Z6UG@clW8a2H*SclOf?N04nD3EYJcqi_QOD^}RXTk+4<2kEYY3unKkKa# +!OW-o|cYX{rc(e^nCVz+`P!A&%X+GWS6o!Yc@B=GIMT2Ztuaz#712=Pr_5d{AlVr ++91m^NKB&X)IWf +L?ytIBp)CUw0%-OEdP^yxj+hqXQyMcX|H*6W>4Oc(g(a|)$`Y}X7%(L +U8hlHAvFTXrr84DviTHWqTsLK;}0L1=N?t4uY*u-Mk}%M((2&YPlMo0Yp7MQhRohe*$HJdT(EX9X&(i?j>*c({BPDp?`pXQVY3h`#J(RM#;f(=yGy;>& +~vqvP^y+*VD|aOP;;n2{z)@IYNxV|R}FoIW8A#FuSeRpHA$@j>Jck04#CeGRMrFH2k{Nf=N>xaZuF+1 +BqPxBRRwM(l!Jtdn)*8F*t0L2TR~!8CjveFzFPAweWADO{I`t7x0KmD>Z03ZJ-;Zj{BHBv`9DDrgnvO +1WHbH-k#9Rl|I{A7w2!{?>aTM2ckPSNeR46`GVxk6!{pZ2N66jKXm7_8>96>17qn%&?7LZ++PgAq`U9 +aYD{toE;Is8i0D`xL3ozZ9VDPTlNABvPo50^+tLNRftc^b{=k*_^+3|GV^P;u@ +-)#JYa-LbqztfI?*zEnQ15JRi(C)`{0#|OLmvXLi+H$t<=q^NRf}=QoFpo{{)2abBL|(P*&G+BrX8wk +9o^ETb@#rqt2?nysN?B|U!y80v;u=4D@+{>+)Ih9&cd*`qdV{<;JbSQS^Dxo-z4Xwfc`yH8dtbKXsFG +#-&R68)ZPV=%^Ki`W14xV#NFWBm8#9POBLeaD*PRGOMn*=Q%u`)eU2WE8HDn-g9LL#v?P=}K3Op^Vk# +(8+^l5WUsN0I&aA>|DfPR``c%1UBthSYZ=y%69A=E=7ZCjUr%;$B|aqXr^ka5qc6GCv8!PF!1~2&%#izrGxGyCHSS*)YdKAcG-vtU+MRWY11)KF_rEYdU +in7A|>WNNgtj?mdCfaLtw7WIGy&Q_R6=rn}T5h?+ubO+-QEsr +--mO=vvD_@?Ot{IV^)5yh5x*kw#cZ}Mno`Fib{|XR+8v{-#91Z1**(%`w4K#Fb&V`Mo{x`K@tRzuH+! +$5trF?4`-T(e@+@G(gRg0_e_45sPSZU4=rcM+vcW~PB2rYOF*HQI_#KTU`fkoilje+PwSHi5CU@~f1M&}-z#S +XLPGE91q+m*F{tO=E>sE>!G8`;eR(qeiKIfFG<(?rbMR6F0x6$uFthD07yYr(!>~KfX4d-R)-31fOio +vMqg^@5ZD~u&51HGtavvqtU&`UpIOmp6dIY&Bp_BF4&k@mwENbQh#R5)qtg`fT2mjI45c6 +?d25^i&X0{p*9m#?SXSUuQwh=y>J)C&Oi#%cNNO1@RfCMu5{G~w;OuVaN!6HoctiseH$8AHS$n-=I<_ +tcoUMRdx?A39j9j5968ssB2s)RxJ74M+86wC6NyxDczAP@-|?D(t=px@&clE5@xD#gRW2 +FpB#V=Jf*sXR%c|=9UZ5kiV9qledIiMH^QpzO<=ZRohX0c@=?6GH}>Y@x?$gjqSa2I4=D)<(gFO4nH> +ha^U%<7GWH4MpRTLqOQ<4|?AH}eB&yn9G)wy}B}yThdw57@Q{nCsZ7xochLx6t0t6BCnJmKw;|y%d!y +caHdH0PM3oRhYyH3xvB%3Zc(Ez5GdEp!e4RZ1pi0bg|uiE8F;ZIsNTh^!Rp3v%h`&KQ(Mhe*IRLVf45 +Em{LSBj(aOsnTGnj`T4))1V7}fem1!uP$Y*lG=&n(=V7F&#F<55iAfy8x|5WK@Dco(#SqVtIBa1FFdz +ecIG>|Q4th@@oeVwE3Z@Xe!NQfP=Mam-kP^5Wb~Y#BsKi8QgHf<*<#RL%@FJKMId$}4r}R^D>RFVq5D +_v7bl8v+B_KgVzYf5`Fa92Us;2??GMV~ehTKF&A44ud@KcsS{}T0U9}jGr4t{=1Ml#UL&iu)qbEXhdK +Yms#^VZ4-U^Vo|L`mJg_8aq=7peVJ@`1qYQ(&swDuAIr&OPD#v$2j^@{^2fDC}kKTWWF2`zz}@))8 +YoB{fI3;?-dya^tBIi^p?bX8e?Qq%3|!V5<}0-*T%!_ +Whe*NKA +dLB@T0%9elkx(reWWH+V)-I +?kG>szWnO5aKzaqKPr=;vnDox~r&0xgY|CI__HLF~-S;2Pj<$+DQ>1v9i;J=+imaXaTavG$48GR+V5C67c;_GHRkM~w-;8+x-q_$2Q0T(O~rweS}5j+f< +`2z^@<)ZzsgueGL+CsFzx`1j=h(!u^nkE#+O;D7v+s<`05?$0*NSNjF|-3{~AenEbB!+f=0kl)=fU+o +v9*f*Y!jHN{QA`)_MPnT#TRxEguIuIyu%7fiHMlPUFYnIm+y?D? +)K~qD^cP2ff7f0YI=KFYtX2-kRth%nqEh5H$YH +j747USZT6jeUYz>zUS|!D$!T%;_R|2u@N(Zl^8>gZ}dL2t +258`|nx~$vIjD6x;w3u?TJseP!Dw(qyKe~2}Z#OE}a&dwH@SU6F;4jOSx5ih8wJ@VE=Kg*jHL{=uCmt +GX&+jScK;71kv*!A0bmo-UnN(wa4d|0c!rB%z$=MiUP~CkzC6)XrW{ToFb;)z ++pv|-r)l+xbK#C*)mW1!UV}-tP8|fN4PHDZa$X)%tF{(>7cVrHTT7&v{qaU-gcjA +j^nH*Tfk3z1UEo`Cr +-zZcL)D;vA$X>#Maw-WE%hv(MvKvH{^rX-;ruvuTwT72Z`Z&|HkZ`$)nw6 +mx5F*GYoFi8q3~k7+8$x6)wm6TKhD!}adS8nbg3i=A~@)byAc*lz8N4Q2!!;?>P5NGwf!pp|V6X2k4; +!Zn$Bt5hg9EN1>PudL(B8!J4R>vMPCM_b0q0!2qj#)RawNi{Q$yZIQmePk@V8OKB=b>d!GQ9eGF@bXv +!zr4-C!ru``+XXvMB{u@Mo~`!k_M9&A%)bn?gEV$IEvoCa%r7=}gdaU+R;1t>B{L6u-R+8v_$VsK +n)+G=ZyhdOed!j%=jUWe;3d4!GFFA#6O-E;w6$2qmSjll9Qg5 +zw>+!FD@dYoG-=r;LnZDFLh^)ar#iNooV0+sgd|GbFW#eaOW!?wGYw|m$=sxnNDK(Ig0R>Jx?hPS93Z +^!l;=H<6lcAEtK$BRBT|NU3o@2NdL-0R(~V5H?o*8ESKvjGD$jV8%HRWrtunGD&x5?E#fGc2c|1rb9t +GbTT;)0xO7C=6PkXb3r0vxy-en%y*HR7L42eSv~)gHjA~RRCcRGz_>ro0B@Wak*jsvp8y8h9fUM$ZAmqw$e?kEirbgdOPO5lok_9=)2i|{*Ow +qN92*7_J0de1>s1UDkM=&^A0vZDHpl +g5zTfBRQe77HS*`=+=FHEDxg8tYAOep#F7GZeZu)WQ?3?J~dO4l&OL4`ny24r@xT`keZmpo@QqRx3@S +M?Pz7Lb|lI@JvnO%Kf;~MIgRWy-yk1qCYTv+O=X0I>Fs`n7E11eL~lZ-}RdEGY){=@>~a}~YXl+T1gR +R?_!^)en@^;`6~B!!n++iZTsBx +1{47sqlg-AR3(Fs@Sz2Nqu@g+V!X<&#=QdL6AfUpu&2Rx4cEY{AHd$MBl%RsjWmLf>6*hqVsHSQZ~^; +(PQW0*3;DVQtBe|z)swo)2xt>)0#@9J@*oTyMsI5!G~1`4{Z8$BLWU2jXq4u@vI +ZP38Kot%mv#O%;E&TJn*ecCpa|~-nrqxBf-a!I^VnI!MjINWr>F8fJb;f(@=x8c%%*Z{&(M>QI)YeAg +p?NlpRD##~ciBhWS?DhA@+-egJ4yyq*YWa1CV%jlgWCmfGTQ_rW^t@Bprh28{PQelgsSu#g+zGU4ol* +9M+z!ddZnyswGL*U-VdBDg-UzJ?0?8_dW!fi>z>@OlHH%8?M5{ULZRc*nH-@li~fg2~}<29xow%FYeE +fm5^)4xxvE*GlHd&cRF@(;U;GfN3pEt-(X^NhcmyINZr$YY$bij=}C(f9``fRlo(GKp^t;=z$a9L2#j +V4m<+|7u{bke76G)(*ZLD0_FtPs*GSCa=0Nv#X@66r`Hc|@@T^8Mw5_vDW?aL_y7ingp1I}Qm;L%2t6 +P&z_o}^2tPgR`ll>xa}qSU$(xt`e7{_-_{FW1*?r?9w~%ngNXG{)PG`tNg)6&VdRwclKsJ@lhqte1YGeS(HFU>Q(s%i4wk-RFpix%Hb#(=A2yw&p{1WPkmCZ +9z^3p72Kyt-zG8Zv?#@K8?KnPFZ3ChGgVEDh7O6qc6Er;J(80G9)wT_01+904HUdqpw-=z-vG4_w0j7BIslM_jRdjB9pLZ+0 +i*Qb065_WcHs$&6th!BF%RW>f;@00!CnV2h`Xkqbc09_fRMLYA@8OIPSkFJcWdB<;FBF=+-=w1%eI9B +O^8Pc>Oiihn*?&*LN6P13;~29UHu6b=@2V55uSig7a%u}D!^2m?~eqq#S5Oghm)faJQH}%E+RA<;>Pd +KsOJFkv`_Q~7w!e=JVDyDCIzr;#Mcwy42C0k#=9zu`8$JUvU;GyY{HroBr5Jv^8#WK@Y(>9E6_v{#_t +i354Zxi?ml>1K3?A@yxmAGc)bAqYDb7@?@w^~?os#;XeJMK*bS`F^@-*nG_+k|i#W9<*tJ=x(uA8%00 +Lu>-vRs^fOQiBuUb{y5&V4*z?%xE1^AlE0Wkk=Lf|;Tw2a +$>M%dHg}Vap++6jG{c*F}Ax3#ST%=qGNB!ie;gU5a^NQ5Hgwl5miOl!Tb;Q?vz;S(NzY=Srd0AUP-N^v;#5DF)<{TRX^;! +lc;qZr0^vWd}*z^3eC4mLjm;4O-##FB6#c+FtlF^x^^HyjKB!Q_#NS0DbG!sL+*gCnF<6C{R!xz5}#d +qw_RM^W^D$0*7{9d+zu6y@dMe`^%w*NgRU6Gb^RlI$s)gL^eYA*{0{7{Ig7>?}Rq$58@i^xDBQ!`U6z +xn&4wv)U|LEE%)*M&A;cUMp$Mme5x_Hcj&ClwA>AJj8caT&TKVoxm#U(g}|uDP}n$Z3_XY-Gky$HzA7 +8eW#Kxb4JG%%PE31V6l1j5lzcaC$tVu2|?aaqx7?_P2L1|`>QC56f%5Wib&AsS7Mk)DO!zOVzh0xLl? +zje8kR`JZa~6pSNtgSeiF|Hqy1jZ56*NLLD{j^^U%4NQ-*iRz07tia74$gXD6v`+4b&8QCawn%C8(m> +2tVhh6&A!18mzHrDt!3)_y6H_4nwwnY=mac|qcCfxinC6`zZKJKlxr!L2Kb~p(8-zUTPuLyGNU!*X8b +)PR{?%40d+-VA0(UAX=+IY +t4LX>E!c_wnwyBT+4Ku-kxkqa0onniz* +Z0uF^5jGQWCQ1XAYwh;f_w1uq#n_WjYKg8U>AN+6C7QbGse;aM#d%i}OQR#JO{|;v6BkObGD16Xyo3p +W7_d_jYJ&V%p^^#*%8}{hRtNA46`9UpZ^FYoA@zAiO!bRLkE~6P@cdeCC=+zXkAe8B5CY60_oww*X9| +)n6^Dy6#%S-Z*3~6CT&5~FyXVs!vcA6)ctdH1PpXWDeboVj8yH*xRt|# +8Xg%=Br9OCd9ActT?5kbR+@JWn9gIwyF2IT&~V~ykF@(8aklCFl+Ey+soQwD)|tJ$SW)eEbIGvve*OF +Ag?R4DEF7LG+v%H6bix1UM0xzOp+n0Ra(=>z@1u!Al2yzO;JZ)ks{0Ax{g;8~mfx`Kvw>u15Gmx5yg))>)+<5NW0)?UIwFDTM?d7(RxI;;<3qc6;73^#dy9`Zafa5U(!>R>z2=6h*-_#w#_^cblbkJ(xm=c;{tcc4V +jqd&;Q>*Sk8~jmXKfh9K96y{GKQ3wdAkiN93O*5-OY9`2ilzU&`I($7~tBDVM0f%f03%YuVYeH|G7xx +fs0sW5xts!@B>*M*Rm#1pC4s)b_}PzOxbTPAMGCnXaf#RtOv6_PHsotWGL=@6s@D>_CcoGoI|kDo;ar +bwEAc|cw8gVNA$pd(|}oNS#pn)_A{ytdKyk?uvA=jwVg2F+DYaI{GF`8FF$b(M-ctf<*^P1QSb&L!3i +@dQdKFmvXuWbBsZXNFMPyS~M*PA!wSG!JL4m!6JoqYScN*zF@5I)2coe3>UZb!8xPA)BpE{^jPan$rR +2GD-_Z_jt}PDv_Fhg#!OaDJR#*D6Ibh!uGEX^o7j*WRPEiY$#(B*q{*LQJk63F$=*mHN~8m$uW~m@gx +XjKc|gn(upV~grX6PVQLUPQL{lG3I=^5u(u(=##8!GJawA}Fc?Td^2=t@8Dw0cahSCP1uOxbMzBdD^# +?v>GeQ1%7P@@^s0Tk$9CQZ(M31v@Xh`rDLE(;)uagHe1EM&4!P(3&1#bnbk+bGc%D&Cd%D(@S;JxXK> +r=8-p9)?JAMQSYY^v-oV9+OO+$oXB+@ZsJn5)}7I@OTB(4j!V`@_MX%D!PKk+S5&XE;hk-68Sn#^2{t +eGW1e=)6MNwf&OG4?|0u_~VH$=Oxz&*I;w$+JvDwj{*P_hS^Z?jP^@z&#zK@x-Q;VyjEXr%iW6Y0&$X +kcH%_hz$tCMHw33yL~SVUwYIzsjB?aY=Hr%-(kh*jF`^4RXp5cgkm@ITpo>cW_v4kNz8 +)g?9;2k>eVf_v8+v@vXOcUUDfJwR*@>5dsuOI^x~zVQ|KHyQqiTb^+H*a>9!HNu26{< +R!;+S@N!Y9%iQuzqDpxvORWS!lh+t(Mh(o!5kRYCf3fLWb|}?tVBa)cDtEX@kqd+!i6RBI2*zdw?$G5 +eRO5;WG=6mN35`(Bb1eS6B-wDt_vBgOtHs@%MyQd3+r)5*t6;zx`mw-J!X9(W@v)C5+Pb$=5cND>HT_ +FH`rP9h1#oEwfp-tUPaj7(r?>K+LT@My+RSvV!iydIJVcWz5%iFEsmk<;>X%bctshf*Kf=6US7eGkHl +R6j2paBZGAELFU2*G(p&}|AIy}vK+}`^0Ecu}?8Ju^;;@ncQe9?$5TAFZ1!9%SVCDc2+Cbz3X-X3?|3 +AT@qy#@fo_7*f4ZuET#MB2Yh2D8C{6btqW_c7=L=aP3kCz;UaB6@X;}diIq-979;&L!;B7*;mhmcJKr +=a5lBcOjLp`fY&lLwF+x_DxkRLcA^Utu}XbDkEz5Z4P~{2&LtN*oZ$=Is~xmfK4ysbd1BVgV~0m-@i| +-Vat7bZt7e6P$=hx+nF;ONWcWaza@m64?P4a$QWotTKQ~AHu;O#iPFPpE3N*d}DSp3h@7T7+!>QoA~6 +$cnD&+4^9Bm-lKz9ydpQKBz#vciUiC~m0&Fyc1k>Ss_sHw%e#cvo*M6bLX{vDbssnGE!?}e_5QWyvVs +x9X||Ia0D09WxW3GLpg8*X+C+aL*cuJH!Zt7iH6}lBYn=q-9fiCq_QM_~e1J#lz^sZ`c7XNIn{P=W&U +7qyWsU%knCQawC1V08Oy}(xMFVC+V37jZNaEbb^&fkzpr2H;y_C8^e~6x2a*c;jY2xIdzVaqO6(&p8( +cdR9E6sea3#>&&p2eu9{qnlrNmGrt`~ar(MqZ6YJ8Xn+3;dT)US|uPFG%#8x(+?~czC?;`?^cBVDu`+^P-#p;pq}*Da(|^!YhY4NlYy3SA`1GJe%{I;^ +$)B_S2^A)~I@Eqbr74>T>JLg#XY8qop4bYocA|s7R5G8gC!wcEmiSN?TIQEw +t`;VJO6mbzCPu#WB!#+Sg-Q?pQd&GDca`uwG1rFpGw8TseKbQ83JhhN6bPX4gO@YssDL2m7jg? +jll`%|KLdY9}0sMkFfL}`-5a*5*n}tps=5c>%+-^o>4H3jfHybt2iwQuSciIYKlWvfOKkXPEHM@z-;j +hI*39NDik(+?QM=FQ!lI-DzK1+ijA7um|#=20}720NCA-kveV^Kgj%M3{8Gyd%l~OwCeVfWsb$RXTIP +F!K9GqG0zEMwgyKGaEiPV99(Zdsm8W#24iS#N`iXqV{X9(mpm&aI{Akwm)d96IB`hK*P +qdw^6SbEk;hUAB)6pNy9k?sk1=JkXS5@y&IG1*N*fj^GhqJy-~29Q#f7Wbs*7EzD1P=#ESs4>H0 +Wy`{Yq`@{7ToMldvyC`&0Bah{W=v#6jUki0x*UQYAx!X`)-}+nGC?~AE;i_HHDPkJkaa?L>=ds4nZAO +c~2W2x0S3wuZi=07IgI{Tj%ST4|&^Y_tkb@mUo=On2q%6+*hLHfLIJ@7Zx%)bAkkn3W6zKf80esM>i#^j8H4FjQ^qzqu>phANPMc +Pj-cKNC)XGZT2oMa(i0O6m=>7=h5Jjd)E0WBLT4c=3z`y86W>+n?QmG7{Z{WTKYcq37!KZl+RX5c)$e +F8Yapqb+77*>d+W_-$G!2Sl6g>5;xG_>{0J-$%x{L1|A64RzWIBN`Xvv^t8Ib6u7;Z*jSKR{;P`G_?8 +i?U9>2~O`76`?Y_`a6P4`biqR6|LsJ54ylr6dyZ|zXgU`5loA6%L{Th3xz@ckOKw*hV`TPD|h<*_GL= +R!n;@N(q`j?5_9?t&wKE)5PlKcr)0NCTm^?F+$QPKLqS~l9=c*F +?LbKb#R1x&ayEoZE{VNq=}{=xUmFy0Txhb!w;v&yK`oX?`<(drexX}ZilALap%RsSnn|M+)gg@ipUae6&2BNmSg;#S8gqrp^BZ(R%n_(fZ# +bTHn%51mWSFD@hWn2TH@l?XfK7U37mb;)FJzMK#Jcr49-m1zC;pWkHsNl3_k`!L*pev>}$sy%<6_|2YLY8&aTKVGVTtf2mf&+We`_NV#$f +U9W+XDNaO=ou$44zk))7)FsK!?Gv~;5Ex)H2SIV2lx~Af{ma*1R!08g}#)8go%{^+{PG`x@-cWDHTJP +$fxCw6R89SX^EhR2Z&)HWr0WrC>Wo7J0vr8-$-HJJdn^S3;Vai2=iCvjw}H$CgQ2jI0rE{%%zz+dXX% +I`at+|6YV#eL4CtfFw~1pIXz%1K;}~^3_XB@Xgb*i40QECwn*?ezoao*@-WS&xq{D=2-RUV4@|_LK*kKR9^ZMrHqu`m*}+_;fXlupn^?mFhr@CZ2W;Jw106?G$;^Bi +;Ri7;)-69Y5X^!L7wn{LUV?5PqIP2`>s@xpa~2tz$%JCnRm$>RCJ#H3OwvuZ^E4_J`ozAcFJSOdQr%6 +5!&?le_|`8wd8~_)~QMT(pmChWyn<`?zMvUtP41Yli&QMfYV%L|zPaneRL^w)UB +V%M4cUD%RQLD1s4rc3z)uCMCNE)ZOn}Mw+qbO4!`b^_V!iJY#qVEFMe5E_JIyPa&HDjZ24%gZ{O**4K +HLk}*b9{Gjrn6}$&;*W|iFw*evaP3)WAX;&c*iaF7)yDwdgFLB$(W=!ffz^0%hQL%)=xan7I9FHrrp+ +wI@$F)1Q!=Rp{q2N=dg!IxniSp{EXIdJy#?|REgu(hATlR7j4#SBOwPoMGWu}-?pSy5r|bXyEKBGgKKN4?eLe6G +sharb;eil}=7fNf8rTm&~C&lB^xsSP=h)znnJ4%7)SH(=0VYU2QoKx{u +bd0-2342pLqg)V)D{K|x&;CVPTWq>9yPY6R{5E_gN)9vvoJ)ePjrBH25Z7hJ*f=(2_FjF&vaqBFD|Db +8;S4ya{X+`HlN=Ul;sm>eKf1j`z3~farY@#qT%(fRLnK9+#*~AS@l^RZ7|sK46pMz183H>D7@h-Xgf4 +t$~<8)|M#?X=;t}dztMEcS$dBR$9cga#4^{ClaYAyQ^lK@`!G@lg*bWTM@3MS+gY>2q!vgde)hV#7Z& +pj9KlSKFyqYee*PXhg?YPR>~<)b@-!>xrZK~YeiYndw$&p;<}xM)fGD&jf;vc&ZQ}A(lFlkvgG!dU!Z +#uK}qji;Z;-Y1vOu?J1I`6o4`uz@m4lpWwt*HXJz7o$bEa--)alT4oaR>$)O`}bC>Y(Cyp!Fb8QphHH+)00(ka#3mL5zk* +)vOrcmI^;(A1?n(Bx?C|dl*l0VRKOv=}sI0#Pt-imF=LCM4#q$f$oX=!Z*>()v`6I4NA;aTVLZ%a!11 +E#Q$mraods|ByS!3sOXG$eeUdQYlBXGP&zDdxsl +#p7kh`F_X$9B;%~Wm|kFabcXCe~~4!qpwqbO)g=V0M%M+F`hdz=5WMaZAa^Bpni7%V2{R +(GsfWMf;(e+%VNxKPB17-+ApCF@Ci^$0|XQR000O8HkM{dw^<84nF0U+mj(a;9smFUaA|NaUv_0~WN& +gWa%FLKWpi|MFJo_QaA9;VaCx0nOK;mS48H4E5bdGqkQhU983GhLY&-O@bwD@lFbsxb(+OKeQuS!#%Y +OSP*^ZMwhIN7g^YM|Q_)$8A*_#lRC0 +7Jp!4@w(MP?!d>jbcHDI(ZNLuEm-nobV<4~3|#IjDt7M$`O>y?Mov=1&$qwe;sWO9hq%Qaw|InGBpiG +(0hjOt&+ZYp4b=u~Fp+l|RNN4F*v}-35Lx=JF{UBYN2VXESxOU +m&hYpQU=^_2ukGl$OfXQXXd~(jXY2T%+oDWG(594dYL}(NCHSfDHpQeJt#&H=S4>Rra3$Sy-8mjz}T~GrZO-qrs$wL#JQnVV*e;1j9DMZ~1`Bz#M{oXiePN7Z}O +<|3}I2Mk%ZUzlQ#mTtClz{y$}U!qT*Jp8tjGp5;GKO9KQH0000805 ++CpNmR3|!hI6}03b&I03QGV0B~t=FJE?LZe(wAFLGsZb!BsOb1!3WZ)<5~b1ras-CS*t#S(ohf3;;zmGl_7hkpeF7K;tRagBH=}6JHVks{J7I&)Mi+ic$QfQ)FAiYuS{!^8M;s7Jbz=`hunbMv)!i+Rd_;Vo-ILD=q2U(3tP9TliC7T=eR=x)AWOlin+tqe$uD3$ +asbDZ1lboj*vug60bNsy<3BE|o0hUDZ^$3enz)p#h1NB5@>=OCsV)%8!NYdhv>;`khj(ismkd{r+}=x8gQ_{P +@A6{@^J$hs)$~%`1x$!sY~2^98KBgNrf_Mj-RIMcP +r8&nuA`=!`bkFtR|C6O%KeO@&h1rCp_7K*$n={JuLIBHe3tD3xaJy~c1I6%=}w@rP_nD@GpjcL#wXjX +-WaMvoQZAL3_o<<%(wR7NFi^mFtx|97H9w=CC>aqI}lNLxCP5Qib +D>IAacx$p}0YLfx3Z)ZDrjaGP~)_Dzu698ntn~PC>KpmX=|o9{9oM*;DPkm#{twUSOQ35P>m-TkGO9^tLI0|Pus}8Zi|=*@Aw*6JV%enxH%Uw32;*N8YUQz +eIdRDb+IH^|43D2qQ%=c--wE}5*&dN_j%bQJ?bz$`??L}{lX}ZdjJEQwzoT!nO(pIrU{Nrf>n&UU||H +bU(qU#qO3}qzUomMdR56suvRt}uu@oeuZDt`$F>dH#Rlf6p?F}|M+9>%+?#foxY2Nz>^x?ThdaO_8|m=`{0Ml_uBmg-B-uu9H~2%@AlvYT-*CVGb+6vnn$Usy9#6E3B +|fqL!j07xi%(ctg^}Xaykf~q8}ZJ8NAo1DKOEI>5L~Ke~}M$fAhz-nVE7<)p*=wrl8HxTm)jt%QBw*K +^~XlF|UI;!B4q}f-(VR7q#3$?A(JNB&dOomIBKjVnJK}2I-=*Zu8;+&Ewb(5P3m!ftw8dp5rI4VE7-~ +9^z^(arb0N!8N_)*yS9xzHf)RB#cv*psj>MaQQ<6!Msvr0G5}<<%q|*PNBGg<3UcmZ6L;X*zY~q2=$D +&FAN=L9M*LI{|BRqRQ=JBdxnk@t+6^UP7(Y>hdSNDixdNXBMTI`ssL8x!XR?(IxRvq@f~fpK?Wd!eq5*x-l`LIK4K(j(gWUd7F{^N$08AE=+&5%V7G91K9#)Y8GBJZ?%^BBk +&s{G(-ddT*K8a?#1@aGehybLn5+NMm?Xd%mx)-q(>0!x&b?aQ4k4)(PDBAi6c-b_b&2*LaKRomRvRl! +x5^v%#VTwVXkdY4fFOih +3xe-7zQbTSvpcukAquklBuvYP0#~`|pA#+JM +dG_f;)}r$!cUo4O(ts^o5{VLt=CpmdIv6TWm+@c`Bd`sTnkU}M!_{dz@`0}orb}eh3HE>rpWyV +c?>GtBf@4!{Fdp_mQjYh6fa*s98jL8c1Qoe-kmv7zi_T4uyE#JV60-j5O_l{oNCu#MFY(>=ZH+AiI4+ +5!M(=zvApMCRAd}%4lHMeV*Dss81o35@IkUz%BgLQn0dneIu`yk^JQ +LtOjm+i6$)vzq4e#O6Lr4l^={Of_PEerpkVwg+uu)wR7OfQ3;2gb3NvY01g}MoM)Ywa2`v>N*$QvA+j +k!nm3|jtO5~UMc+yT{%V4Gd`|9l1TWdM +U)5Vye}Lo)6h%w@CeXz(P;na(3IP^IJ3g+RkjiGUk_k^l&;8TN_XlzFbv#H`0y)G$sRJ=+$kozZ|d#$ +xa=&m8KSQotDIg(7ei?C{@%{z}o}=tHGtScEqPwr$(ivzq*KYSFl$Gip7fU*VbNKdpBx1+Mcd0;+iFg +21$20?02u5hL%yNcA}>+bv$u!INaHgR0#?s2RSW&IITX+&adt4iCLsaKqolo+|K|{3%(^~2s16?p37sS_EXO*S~=s~lhNf)I!2p;3? +y2V}*n45NeNr +ik3PiW}3c~bgtyBPrTo=|4L06kFk0oNbnoPWESd)ufOMg4UmbPfL{D?JxsyB5J6B{tui_aK;T0P=9<% +dNmT|Fb+>4E%6$ZpWjBx0^ydv!lLL|3;Yl(7dgB#a9T5`<6~&=p@$?`jeDm#* +NxbRdnGLf`WHxJ^H#hcz8!OUC8uq2_0U7&oIZ%CaB_9a)b^#jmMc|N|9RBwwNJdK+H)ZbUt~W1R<3f0 +&IJ$c|h{%`TXcq_h#-?*YtZfWSfpQ6haVp0+h{<#gDCnPO1&mNEhsEK|f89iJL3sECIig9bBnIT#32U +fw4i20{W+#*Ox6`Uf2*&T5~{i$5ikLz89RQ;%)t*Aq2VN6Szi(MSHrjkFMgtA-r*Cd;dmCjoYXFfs9v +6n;71;LvV@54w!?wCvxF&NfbYv6y<%v@RD}NE+0JAC>{GJY_M-R&4$<-B`*JNwuvIQtOl9<3Nz}n+Y# +iYU9L4>O|Tah&gOY+@pCsNlH1eMxm02)0#7hHEeb!u4n|-J7&~BQ0wxUB+VlfyjJtJTQJ!D7{EAFtuV +%Q=6dgs`IcBpo+xV|?b?Bb}2=&qc?h)*=N9TOF{j8Jo2<;C3ChIlBq435%BWr#yq4A`|n{V3UA +-nq+tDUXbmcB +VnqijnLVPb1@C2pIYm7jApT2RoOi%z5rpEKptu3#!^E3e{H{i93ApfwFTv+iSQ#Zn=1Rw16S<`6m?a{ +M1NJMw>Z1<=0j6m>Iz9h*%=V;npv@$oi%}V&DL4(&K-EA@o|M;SuMI>LkTT)9?h_C2GYlBl65JdBB*n +{$GbmsL6S8+`eBF0y%@P0vqu2vo0YjSCCZfoInD!d%02~)v}a&bwi6fgR6bp26DjTg9XC^<}>P=Pkyr +nvc~FD#L7CHeSXxb7R4mV1b|B^VBlisLs)67)i^oO~8M(XtqnyrJr|e=0wA6|8Ygu+l}Y${Q@(`KLv@ +$Lj5=E9nz>FRY +=D%ANT*13h);gz(;z0&m{kB3&3t}d=u;z}o@pm%%h_yS~#M6dV^%}i*68ZXCsq41ssx4cVmv(`>~6Rh +sy5l0%fC-37iyqo7nnHwqdK8GNbJ1(-fXQ_t`}p +hmx-ClgwWNmcyMXt8s}@R4R&8mNDOAHmIR`I6*L5}uk)#XQylOJ=zdOR(HEWPx4HfGD}j0fLs-SKI5W +AH>zytE<Uyn#I&5n!h6t&EqnBsV{c6mLQwRS${osjCL@-&Vi?a$@`OTa_rC}Iq-wvvPZGRh9N +uL{06&+@MvO_wPJUve2sCL&m#?>!tYDp!4xa-I^Y4*D+(jt+TXZSMvq>&sEVHXGtPPZIamDpP%z_4{M +KKa_{`kS0fzxd2%QNz4-YY?MCeVVpoH*+e~x7EearAgr@oD7IPM}EukQGGcgbJ_fwrk_Pl^KeaKs;jn +2b>#(6{LrM^wQEOtGqOnupCXi8Wu#4sz#6#Wim*Qwz@~PrbJhAIQ5G6M~%@ml~Y#P|pYy+MFa_z|66! +n>7NYGaxgVpWifH%!MrvRQFQtq}O8ufN1FZ;zAD^KU!Sd95aDfg6hX@?^p4L9|m`%Xm6IZj +8?CZS~eIkkbqlpQ}r;aB$iuo9qCO@Zl36Qtl((I7ypDPuhF1>}s?cIf9Yfww6@Ze(=Mc4jW1%xix*{FIXa15ir?1QY-O00;m!mS#z5aH +4e80{{Rl3jhEj0001RX>c!Jc4cm4Z*nhkWpQ<7b98erWq4y{aCB*JZgVbhd6ia8bK5o$z4KS>I0s7}n +U`ETp6MZVoQY@RHe;*p(SnGjh?oRed{|Zw`R&~W2}+a{so{krxOngFV)2M~aD8ry(?H&e;zg{`<-yj +qTE5>Q1l6?0diXq_f4#HTSP%|=6Ap)gEX#^oIG0%N(%i}YA2DEhlL1{sH?PnltO-GA5Y1Apf(dRbiZl +xnTol1tl(4Q8B~%G5YbpO4RCKJW +vj6IiLojEMUAWrRtC!_0J5!U^x~fHH%DY`RmuBl<@9r15Psp+!5{FY_$Un&!i*?XTC+T0^rPU~HS~ +gN|WKY3E088Vm7DN?Ivbv*eDr?AAOwA7|)JrU(xnONxs?n60M>P1)=SfNRXd7Q6i&QB=AG|J2_5{O6@2?s=((zY+DiI0+`0uX3ooZ-JJ8?{3PuG#&Ja?q0`qe~Ru2k^d$l +)TF)LKuIiJ(K-R{7z641$!w^fUX|qk9Q_cTX|OVDTJMN$AD#sea%0e#MuSy+q0*jk9dlCHa>l9g?tjUzhfUu2Egqvx#)05hU+bgh6r6CfA| +s8eA6DQYmXQEB6`8V6puDFLCXzCMewl~kVTxU=xuPGPGxK-3LVsDr3xrxb{*C`_*+;_6>|G$FV}yV^! +F_&7meh_(I`C47)~)Q;S6}6i0y%jnDF-SXYdhQ+S`JaA8>tulC74DVOrF*DC}bR=J||DXA16y!CEDHw +2g{U^tx19*bUUESH2o+`wvh{0|XQR000O8HkM{ddD^4OdI10c{{jF29RL6TaA|NaUv_0~WN&gWa%FLK +Wpi|MFKBOXYjZAed2La_YJ)%!z3*2H$w3W?=OW}#$e~cE(B>9`+32WC%&y&CQ*!CIcXrj7v>njZH@-J +-o^x0&R*~KC +%i8E-TEUdxaCV&EKXlsS7z`*-Zuk{LgW5R?@B1iwNods666S4fjP~jIV2RjrJX<@>v}lJy?n?3s82y)Lmt_7zR(_f4MwR$kZK+VwcLo8%6% +8JenHCC(ixPp1>baO9KQH0000805+CpNt}1y4}l^807Q2H03HAU0B~t=FJE?LZe(wAFLGsZb!BsOb1! +XgWMyn~E^v9xJ^ORpHk!ZtufW-pBbCaG>vX$0waRXq$JV=T(@C7`%;ho?EJ8MGiqsO69dD=ix8L^wKm +a8DxY@Zo&9sq7-~;fz@Vx*Zh{MN+VpZowbv_fjc76B^pX}}J@9*z5>hC+HTb*s{T$Ot7zrxSn-swf51 +-#sq3Sd;NEGjM93njKqv60PFfQRP&3IG=!B>wrUY!>)>kprZuI9Kh0Uo0+^%vCcL@Oyh>A3}2jZ7W +xo@?7a`*OX;(_B2};s>~g9gTOcVaJ)yUwzY0;A5{T~)nWr!D7La`7wfv&0D|QhfL&XZwlj3lY5{M?8m +rGMwI$lwF6o|t&ntzazHXWt7W)nseG25PcddEyb5pl95Z?U!pc=bq>VQ +3nV}#H;Ul*8+HQ3xmP?s=xtsTok +w!f#y`E2XDqCco;sT7Y0r1qchaRuuuPBy#xzhK8kcZ$RGa(n2K!7VXW%@%Uyd+ixGD?M +^RncuzFp$KKw-Oq_z6(yA5pn)pa?Yi_{$s;EG6K?w;71MJ#*0~lM$vb@3W+olF2Yk3B$uTgo?0Lx^1? +_R$;dH4F|>EiwAi_;S^cX$Gzphd4#J{95TKs-JA(rdJ?chz8{W3N#SI<^^V^wewADqJ#X;f0;wlpFog +YXlszkrfC*-00cfWN+`)>o+ex{BXK(%lhHu$CFc7*3+ZCmv4VMef`tv;^p@re)`+u{mFm4hUZ@%iO2B +28XR~Yga{Za)v8>ZR``K!M!_ami6qH>tpUf~^8SnrU#vE&y{L1C>wrvcA1U7;^`5*ROEJ*(^`u#O*{LK3Pb1(wLZN+>Pii_>QG>XWV9K6(#wo_G)>4JPA +1W!FKIKI0131L{M`ynT-^ce$_I8enG6x$?V>3!V=D4mtG~}ro1L0?9HG@X-`qpy(Pq&p{eLR@lHV!Wv +pT;a;z;2v$|q=19+ChWx8XiofChVr0(hYK{}Y8D?F9pFBX7i+>U2xmS$p^m_OZ!SJRN^KC1(jX-J7jP +KUnWq_v-`ScN**wW2)&%sG_{}r6?JM(MfS +B^Gn`<=WEunc8PPul~MZh^+jYXth0^0^nyI8*)bNlXUx}a*t{=$&DxtB?(uHVAqX(h(J)flLF@Y-eNe +F<_&o;Z2An{&P8xL%Yz;aTqj%(^O@+DwNPr1=651#~lhX+Hh3y4f47SQ*)14r&MymuleiR(MV+TvTh@ +%0aw`x_u%0ca17vTLFz(6dq|48pA;*m({nXfuR?!%F%egrgo2^twA3lZ~m^ZZC4KUvBVB8FW920pqE^ ++Br7ErBGZb%E%?*YT7`=4;l7bORoJ2<2WWk7V0MT^03CdxQjp6Cquncf?#;pb?C-L&KD2sy<@}pvN1D +I-57H5ht#Vz3e_d8ijG22*nftH3wjs`F-Ma-Hj)fo6QGM@#z6EhB@@edn*@tc +7cGqa%?0GS6bjZ&MD(G5IB$%D0hJlKVI+^EBER#ncd;SA{b-I#*_#i=dL4+hA!7 +Sc7HsWM$+ygT(AjulcQ$dc9GLbD%3SeBdpqItAl&cUU7^|Fd0277n&VfY=%!>+PTtb6RK;48T#G7 +)MA0&+)<0NR8Oh;C%oEqt`Qm=?>5;RbGOKqUnPyIVHDk!j4hU$)rTWu^aJ{9{*J~I1!sRiPlSAopB+3 +79j;4tp)AdGr79tw}gC9S+K4OjO(42=gP?fe4ov%=s$n{+=hg0mdkqsk6^cR=`Smx$zNWdCZJ3&+IBm +8@&x}mE2^w+&YzsC*2Uxugv^LtYM;kKCO!hZPtUE8cd8SVbyc*Bh0&QTQggHeDWYz^Sv!D#5nJ$gr*g +=I;MdFv<_8kgd^IGnAQ6e?JF+Exoyo=g=5!FyvK|{Z=3 +hZ;dgPj0%`gW~4m;T2K^ODT3+LkeTp#l@=)%vsVJMI22H~t?Fa+fkUHfkTfKEZ)G4-6&z;htKl$vC)M +{l6v&>kIbrnEPqm59IQzI#QDjS`*)augiXdEulTLSwAaYfGMx3iQfQIiM!JAk8)>P6}T*Iz-r} +my~Rs6O)E7th$(6uJt7bM5{3puKGTYBFVE&JC#`;0~C~NjcR(gXeO3YP +(rfrPzQnZ;Lu|Y>Ag5a^u)@hW0J&bzr))TtBs4*seeJDXS?Yk?TiH6}p4sC9BEoB8Cz$0v?m?SLMQK0RBo3 +Z*VL9vos%2`P=D9+TlRrVKEVJ!rhev}4P1ttqUo*lIsaev;(YKJM#|D#=#``>%#^tx()==X|5E%jmRO +p}xAV7@bHcJcA}=;+RE*i!}v#?%FrpIOT^ri5)9s^cJ(W5IYPabWDVbp(bLcMK!6hX|q(<*0k7;6o4; +*9?Dt%uzWniIb@fIAj!Yx2v$JM+NFH9B#IgbP<1qsdlN(Pp&hlzO}{iwA2G--%{wco%~1V=#t +j8`;bUw~YS}#+n64;Sib{*JOddD4LGFC|ZHf&x+B5K$&KAj5J1crnIeyFx7tmj6>Xxm1@M5JDM=5c_nMWT)q~!PPObS`E~6<>Fh5X!UgCu9_dr{0eSH*H=cR$d@~3VTk5fYa +?2Pv4RLOu1V$l|fnXgc8k!zM;FZdFel(+f=7CYwsXjUl%5*Ls8OpxuiTh*kKzJ7G2J0y5cJ=|+u7?JQ +71zP>ZiXv@6f$4?3QYND)kfRmaNRmU8e&1hI0*Y|QatwlbRu)wb0!hg-Q*`$P;DDS~rY6`s3mIlrBLn4=}_5Vk(}_#Ldnuy!Yme4f@q_c9vF^XY4PsOOY!vIo_!5;Kr7cn +U@}Y49mfTui-wYbm@2VqIh|lNVbf~dHB&NW2P5fy-x@zG={|nmdx=4VTfi2qzM|BDrWs(ln8&#NST&) +JEd(?Ns4x_uPO0aVi^yP4Y~=X{orQT<$;$+DROhI5zW^6`J+3LCoJdz+n?6>VY|eF<-JqBxO)u=N2OHy~BN^tHa2|&#JkQTP<$t9Vjmet1xcFZ%4oXX@4>Zoc_%)3@h8Tr>sag4ByAeI9 +gj!N}MV#_l*~a*uDcX!4e-ev_9Byfh)zeWYZcdh?#2E=?zqPkG{T(zahdHRu +VgZbbLTPnKQJE-r7hy6CAg#uERv}}WO$XOJX2+s1gm)o%A9ST2F5n=6IuvpH4^30@SN)eFW{Mp|DZ>j +BmwT}bvQlK<%_vU{+z^szF=JVFi=KDA%GJ2f>au|3KsJnrchW&sagm%oFlN#Vh*`qb*R&&x0RY$LB~R +beukOfqK!dc;(CT#;PSG^;5th1mj}RQ^)n3BR@A~j4}fS?*)T|3M@#=c0H{@rV{kpiX}|WMkLl{wO6uTM6B +mnwIJrM6m2|Jqy?MSP74V){?I`^x$22XVu$9vM3dMY|3P%ahFS2-RAKKA$*K}xN=5s-1PerqyUW%@C+r^ZU`!=ytrEpr^8D-Y%3ys0pidKi=RG}tF^Iz5Zdafv&>#kKjd{g$2ry3LWb7 +ck`l=w^Qpos^u64AWyqhoIRI-MZ>>uggF+B!1YC1o1gRTB9B}=jqaf580_4!4}2=;+!LzU7KA?X$f3w +xzoUdfu(6iM>#E)2&a!6$ +6`HL5aNVXK^%^=hG}!5m3UV~~?{Of;|JB{Lhg&g)(nhUiKr7X>w$QY=XTIT8Wb_pg6pTzudv0!6eTv5_%SmCQ$}$~6CYp_RyX#no?zxZ;X +qwN3>=ni2Aw?Z+TY|O9PoBen3(yx#S)u2IMGU7CKFms^rls18MDD^*EEZ5t*wg3HtD3Nq%wq>9!U)tM*B{Y*%TF$|fIWDs)68%%aU8iCHA+XhqfSkaHsM^iZ +mI=azq5Dkz9OrMY#ur%c^y<_6uaa6yHY3_O={OTsPzb9T+Bc8);AqK`BStm?KnVkSxjM#MO6PCMibDGciwh3m=SsN(TTo_nPT60~gDZ71@uIo`6?~@gMa9RgI(G_IzFbBm1YFWGDMtm +m1ylzhUa0k&&fM=RFwB^S`;7c9+hxN9SQbln2*BE4ISNx6qbL77*|t?u9)Vo7$B+(Q^b76m`@Ru1+#| +UAq)Xp>Ua@x(iqU?-voP5@6)fN0`a%e|XD+=>1v?qL#_K;2GonPfi5OA3{4Sy63eF%)Y3fChCGkk5JK +##$XA{x4wfSaimA1yE@Jk6yZdII8EkB(w;V=fu0dPcPf@HebV8&pl>COr+(M7-01Laq-(m8~~E?sSt) +%-6AjDPwPkFfE`X07)tQZ?u^rzs}hsRypU3J?64Lb|S0&6H@lVy&)N&YVwh*A8**DHjGMC@Q8a=247F +464fAj=xx-ov9ZKEIxK?O01ej1IN2bgeuvXpYSW}yY!^MTBw_(3koFm1VF+*42C`6n_+1Ds!F*9hT!) +!F?JF^-Cco3#$Rf2Vx%K;t>bcFyA)U;A3Yg-i~rIMH?CR7HZySoZO#=I@aLpI8NXl&F>2ovhQKPy&NK +1V(O1Yl$45s|EtQAIUZ4TSz)0$0(S=gQtDtntal`jI#*JOUU#=ws21e)5V_wJSaXLq +v&{nfR30yW^kG=S;OLy+zFzdIQ@tP_l}VR6HzgS~9 +W(btrdfb-~s*=?z~GNTernh+kx;^T+T>8Q(`%SGwe2J^oF8fn&}D|4usS9lW+-iQP!LYsuO)m=iq{}V +978!W`wM`7Q8`?vj=>6(Wd7vs-;%&tF*Bh->q~#As;>T_n +)-ifG)}J#3`JofE(GJl#hw5QQ;K9$yJJHUa6{1a%j0MEDzx5RbLPCdH-q7m;*`+BTM!n!_=V7s~yH;gMISjj*I}?NqL@pmkX>jmJ@0j#A`mO#Ah$4k;Vuo(%Y-tY +LfZEh`d8OR^^m620BD2giv1VTqrzvPR>v;^&D7;^BlzdoH)w|g6-uOcA-0Woz3Lf^+RBB3Q5kveZEh_ +b{hwSEEQbuq1j>gI8%E3Cv(zJGAjoYDBqdjBV3EOV!LfdEo&>qCsaf01>hSz2dEY`Hh;6ICByU9#Gb` +G%T&;|l%f|{5hUFhN;YX0Ta*zoq|(>cjUIQx^<#3?E65f~^G>lES_wEaDQhwm`3-j25j+UBQBeR)+Ex +uzYqzh83*5qzB*47Uv$&mc(-PzmNuHw!Sd$XKCu30#*kwM4bsoGCJR`8Zzzd-ny(oi``=U~9r# +m7*(0o1$b2nUp;MRCstEcgKiC9B<0a1-BH5^6w((;&F}$?zjs|0Ocjw;=>IMe3#DDqaYSKE#09To2f&(%p7rI?%(&=)53YkDbdeRV=(@sd&{~Q-1)Q``S6T~~4WJ(c9df#{!9XXLn!3 +~I9-bToDbQvs4Gldsovb4UMF==umwb0;C_fjg!ar(1 +Cc*nHfQu8S>Q4Ma@AwFZ*h}bP9DLmWC4Uy&cfe9Y$bow;B&XWeh0oILisQK^0$LIG&Qf!Rv$=aIcNoT +!R~=2a470hwDy;E`m-~zfQpb_inGg8}z_U(zk$)@4~(heE&}B81!&$!vQ+%RSr6u3P=1%Q@=_O+$3N| +B+2kRn85RnzI2;aN8QnK4^&*#Y@E_(0IN@9{P;Z3x4woVm!0us#vf^ko3USF?YF{0g}NNP&T!x^@H9% +5d%Dy=ZD!Au_=y=$HbBh|4(N)y()|G?P4)LJ7B%8n2pBb{6pwU~m8Qq)|9u8iZMsxqZ@fd|ZYeX8p>)+|Hy;y(Gqrt{WX-^?_kOKw?HFi`%V#m7u26o1wOGEYTpl +(oS<&;I$C2l(#C%PBAXYp_%CkIa2Aee!A*gFiMDcP?$IvOqhqNq1I +Z!hb9}CYOHsEyNZ5d!1$@SRoXDy02ve@5<0(;Y=!oaR%2@wADFTXMTWJkaC4o<5sZR0P7lo&CmA#@)E +F%Ski$q3;q%3bsO=>Gu#%#;I_lhl;zKJeSe!!JM4FJ4CQoZih1RQxe;#>3HvdS%;so8D)_V|2w2@f0# +O-I!Ail|k}mfiDC3zms0v&omoztbC`XcQFiyMZ?fAs&qE=dzTM}NjaN{jjcE|5_}~b)u{}cW1~v)Hsj +*mu0kcjyUge&ot%0u5m!?bUYhk9LolXN!-dKQu6?yL3{rt}aWp)^IDI)--8o*_8Fwdgq!Ydhzpo(rf6 +`z=6{)6MxEN!~g_YJLRd?|U_6Fbf%oyA1K;(3uwo-gCN25xGroCYfV;O!!k(|T?jQPAPIrGN)5B7dk+ +1GfSru02pRjDiilE0_FpUXiJrn~Ly8J+OV~_E+m+IUviWiApS&LD`e% +XvH}kPY^MZ(QN2GadyXaT`KTmYpx)0@a$ztAP5+iM5uVM`1tEDzqX0EQndh!JWq^SI@gN!~B%57M||8=uV>UiVjW1m1AARiJE8$S^XqDZmWG$H@8N_I1#kmYcFInCd1Llj>GT?`za-fM$2E +L!StD;=PCMp3UzoL{x!zTFIFEj~`!N)0z0;TnS(q8y}jJ1YKTr?WHuPrn1*lV&)#q|9t$P2L4RErL%y +tbQxAx??LCN=oAS^KcZich_x?u4$m%B?aX{r5*);M#q;V?N6i}zxw+4kMM{?gik +r6r;${wy|Bs}UPjBTXe8IEvq(rlnns-cvP66G3x<(6uZ|)ZXavTD +`HPwc$>-#LG=7UTQ+%Mi)oWB!%=?FHf>D?GgSJt`LE-8SeA>xNk8Uh;yvjounfU7&q$t+1UF5>?9@~B +MXABzmc!ih6XbMD|=|2XY`FI2zhBAi#vI5qH_O(k)LdTq +*dKt6E=nul(maU~fl+|eEjt*0g0W*zNP@ped&2Imo2SN$=Wvtnv!)?*2=#s8f4U`Z=iVnII9G&U^xjT +1$dB{n;G)`h%ql%wPb;Ew?CC?db>4c2@?h)2>_L;l<2wgv!zP;_hJ9gg72@engn`nD~o-J!}sp2JJp3 +;yjJR_v?hy-oBUCoOB>(Oqo4Xq~M~>WqFqYJpwAT*N=YfZLcYMm5z~!JqzF*}8& +rSyY~t^BAw;n~C>q6j0iePU6F6VEy0jXh(N4D|_rOZP2>8PmL62HW*)hlg~?i5aJLH-ZA>$P)h>@6aW +AK2mm&gW=SM_9n8NQ000SO001BW003}la4%nWWo~3|axZdaadl;LbaO9rWpi_BZ*FrgaCz-K{d3zkmc +Q$-z&6v7l#^+v$?SGDRc0K=ZL*iIvz@)$%X%b=ge=w+sS>0ewUhhX?|lFu08)*YS1>fcbkG*Rsww(tI?(2mCq0A4f%~OIPKh{;8)N|cqUYB!dF%f4PFDLZ=FZgOBt1 +D?5j`c`D2ASJ|bgzkcS4o(UOzn&3r{5pHe|0fGJAMB0?DXVf{_5rHmlqny8em!&sa(ZPUeD>}M5LJlL +?mnat=l(s){Y4?zLvZBO`Om342QA+WDKYR5YVEC>+D7%el3k6`7x1OkA{q=i?Vzj7rQf=W)%<_0K6;! +dX}CiYq^Oh;$+cOmS^>@pDPW|onIVZyc`Vd?~~(`7pL>{m;Ze#X5!J&(a~TqfPpoqYgIAQD +#HARb+e*rU!W+>lN_)xbHsBzB~*a=crF3;8(0shoh{<Vw +R0tG~)u+O4h_rff7Ko8j}L=q10rYt1mg!v8l*)G_$v;Bkjd;16DaQ_G588IaSD$3ehni$FGDiSxc%2v +Cv84g>GENprSYXn{`5;^J+Tr2xA;(1@E4%?Vc)M0!-L@?ql5@rsojRM6N&T>5NfewiioV4+WtNIK2gb+6Ffe36hY)E~5oMuGjPD|9RshsF0h@^r* +CZUH>xsA-BNGR!fvy`h8Y2O342N726zm2-u#W}Uq8zkC0O|uYxEu@|didWx%|NEf;!GPVgMMqb?$!zK +Kn;+lBaligOK=ISH-hr30SW>b@!ZJuf&U7y6-przmokYPCB^N!)gC+tF`J2BhF~(bU}WTQDn49(BDrq +)LM$s8L(6k_C;?UoEMLBhtWXCst?f1ATL7lL4-qJdQ9JG!=keikFTYctj@WmG@IKsg2ya?l;&wFr=O_ +tMF`x&7FykY<&OTV3~v4Q5jbPWHeu)Ia6Ew|4%Sh4HVeSzK?SSb`E{SvZ-gd=!vIT{6 +AJ+vx};MPKm5^5974zUk@K@PhgIg@=7^62Z)O92ACYw`)3-F5j-J!@ZFUxP%HuS<;pftkyY_TFA&iq` +)iHkNE%L_?G*i=L^s;;nWe=bAbI8lJ$l-R?%?fvvg1yRLf+2xx=D}XbGH>O)XZRJJNb*Kt6g{g)H7kv5?2F$p=uz +mP-SurN?4VkJw*~1Xrw`8B{+q?L1HIYjPCEVg6|K$1~4LfuzTiI#kUb~ZaPY_FNOsKi5a<l!%Awd$eBA?;1q}Ih##Hl0L7PU1B69@uF4zwzkCOc@{ID&{+~)|UMG +kIg$baD95_ck%Iq3K>%*%v~+VCn(YHt6g0kUOPsSlyV +PN#9t6Cw1(eUta*h4Ui3_*@~nkG~vj>dqb%dgyU__dmTtq{c{2SUViq>!_N*$ebBc?}#KAYbO?Ex3#c +U_6R^j51hvPMzuSRJb8(efS+>|AF{EPSE>DIR_!2P*1c35H=8uL9yjH9hldS@cXB49zTi#XzU*j44-apF?W};fR7kh#jF(=s>mg}>~ +$;P=t*WZNqC3~V>|$Jo45enS@|a&kEQ}=@`qXP47+QkK@5m_f>ZmTfn17yAU+~AfMt_GOuT_OsZ2* +QFqiuV2=v<@;N?!^5>(jCThs1)&dD=9SyY!I(Q|Et9m`02>a$@x0U$&qKXT(lGTARUc;`&LU*5`;+p+ +ox~u8sTirU^mfI0OPssV~4%X?qEK{`W*xDy;yU=~ZeclDYSjAcuPR9)|`)vHb%N?2QJ_Dds$a5xa12Z +d3x=^7CDmhhPOsLTI&}I(K6vW{u%XnE2L5=EzPNHa +Pl#*#ax*aH@8Dm3?OE{M$)f)RFcVb@7HEH^nG>NTZm1nOxv)s%C52^&Mj*M4%JURk}(L{sI6IwLO;C6 +9sQ{rD(SF_|LJ}DeJAHlwyp!B +XuVc?$$4sFT_Tzg8KCIA^b0(K)#o3Kqr4`1eac15{%=#TlW7Q5^_K+Kn;3f_H#iM_nN#1nC=Dag8S^^8>dftdtD-_ZmrMGn8$boj6(n^z +=$!LUMnN@^R9ny_#txEG!6t_yI^~QgV6681*1i{nj(e>{d7{woot+2u_}#7RSH6)`!M2{T*C +#R;(-A#%SylZ(}+<>2`&!k_Yl8&Kt0niopiFqIwm)9mBk=;D$@ +LnspycO-=Dn#U^kd=1-KT@o450KXK(-OZ_MVz-+N{giMP1LahqX2?v``i8}MmO7Mt;l-8kV5B(HJ7IP +eH0FwvO>P-LhqXsj&Fn;;uslz~aP?KZ(-d#$Xh%Yq3cBhun;B9XJjLa|# +`*VsKj6H-feV-T!$tdLcUv +osa-}0U_NNWNB_@Z_IHBVj10SfZOcd^|EUWSs76?OuLCeaj-+|H4dt{!!xK>hU$Lg{K_bZe2Dk`h1!* +#vM535yzS+@s@vziBgjGjbKT>4ob!OdpOW;$J=q@0(u3612{a{^O8d~tgGeCU(e&UpC4>BZ2U-}4f*C +B&47C%t+l(h`eD)HcJt`5M5-RjS;anE6GSydrU32b&uW48gD5-n2r&oV1Wp5VRBg?(rC=){L_j*c#$^5AbPN_q?0p7 +~hoinz+38}Uka3fR*c32cXdzj88~06gk^9@llH=5yRFw6q>-rHm;*9kk*js$l$AYgT-ueOY=JSMi3PI +8Yz9Ve}A{9QTteStkU;6h`4Qrv~uJx(sf2Z$n9cxNOz>e4Z6qJ)e_8A5R_GoQh-e0S~gaILj@1!0k}& +WPvm;rA@lYI9a=3ro`FPg=SgADLp)0a2Fj4XR5E0+0g$^KRjKuQcHeP>*xjLa_;U50DR70#jzjv)y+1 +iZTYs?5@-r5fT#N{BAAa3i+p2_pM+fG;T +KGXF55wF25Lm+i1T4Df06=ZS5agcz*rJcYU&kM_O|ub2 +vsuc@D@ZV#l@#wf9v!*LGF2Vv&$CU2#ebG`;Xe98*rHeR7;v-Q$)E!W@&@z@NJCk>z%`XoeA7xuUG+u5xlJccEJRBE2^&oY~^tkOtB3hdq{mOY&|qF9C$~_&Oj +%TG~ho`O0jHe@*XJ*X?Iri#)^+1TaWo{XC_UKn$p#o{gT)gWsC1DdCb;Cr_IyFL@XN*8Cp(p>xW(G#l +lvYN4Dc)VQXtq*OQ_TnOZMz)>m9U`sLHu^SSi`ostVAIt42$Wl@E-M)BadBA1G>nnbv4Wow#F@A +d96QMzhojF24!DNG`EBWJDKdD<|SLCM!)=s6zh+u6kR!5CMfn7-vuwgV{wf^jr+NjQqzK1>7ui&X2Y@ +v?n10%Wu@NQVc%h8+0w9=S@p$4iMz;}`pA? +%zQ0_EXyU85#!s<7m;X*%t`Wh@th&54odeyG2FmZ&bo)GiPM~<0{LgvY+Xf-vC`u`yGGypMO+kVL#&! +|Fe!)X1%4nk*)c1qaCj*yXOE+usU`<_YA-vC$5tkbVs@bo%OjHL)f5$=Ej-N^TDdo$)EL4d^($4Aca#>W>1dJjZzz|TTA+c*0#yCTjM*{Gy?$Fb+yPt%{DLNv@MC +w*%hqo@C1xHxS~V@gwh#Ht2A%87v-(UOWgb}#cd1^Qm!ygxyo*MbzI~uRh +IaC0EnMNQYgbx8?~;`OTNH_)b45P%nf7XAS6`wo9OKa2RUV!K$yOy%nGH88Xz|xHsNOn(#m!2+Oj}JD +P^|{XW+DT;4FSuey30r1n`@GI=acj_1$bzj^-ZRA31^9Vel>gQY!QpN3OHvh~aehx6tGuI@Q0?+L?3K32I% +@(dL|%?<@wjH0dFjQxqdT!{SN{Fs-}T(4;;mLR0)95g4*HPtVxecZSl~f=c~^d=S6kR08ud=aO^1#XGGd(&OQ!&t?P*^-L~V$Y7ZE{Y?G8eqdcHpuux8_5Bxp&X4}acC1FCb`Pk?QyJU!HA8QOUJb7Y}{nExx +X{KnYxcZoMY5ApY9u3ko=G9i}>C_~6xK>kiI`!xHw=QAwx{-29u{y)(7eII%IXo}ZA{W_{1U!1)77hQ +j6x+2mIWj{mOROV8jqq~>EeSZ4t^y2iN#N_s3moadM0VV(6+riz3RQpWvj=6v;*e>chJaFGQ8#6p@C5 +frF<>(P}40s1w_Os5ZsixA$CgS`y-YGg-;{f9$s1=>>Zfk|OKm|g)v`M5+((nn3ZtT|M!Ppu=r$%UeR +|ivO=#~WC*+J(mYz5GrjoT7Ow>HcRO<&@EWP1P&k=ju0GM`6^lO)5FXyBUdSc$|YnbG0t2jYhY?@x=b +V%+UzU|154bxdLvXE~CDu5GY=@FtJW4OjNEz+gX^uk!dSR(VlH|7iHPvLVWsg_&N!Z7Lde_F|iDd-4a +Ql`a8U(S<<4=wzx +!4kqDP`-vIJ)y&mGjRH&b_SFrg+MNb0zLRFaDVuckEs*j@?tG(miuR{M@1YPw~_JRh=*HGG_*$OM@RID*=>N^OleBW!MH!a5H +;Wy2?Is7%PDMC-Ej0BJ?EB}r}v3mNiW2ekP(_8o__?+L{K2znzWw5nm%i7L|G^3|#uc-2a8cz;>d=T- +D+w^qp-)#dIxw0B{BAndtlgz+zX^c^4h`{13$JzqDg71=?)(zl|6H5rk%l3*$IIG!HuB@!?M@LI)Mfi +E$%2aCs6CbSE~EbewU<75P6bOcxmFS{`+2Ru!C3=_!5DYLhO2OG^=Mu5booc!uN$*Dm{q)XKH +wWB0j(4Qi9sm5!bow6u@&wg5UtH>x@$#u4EC9>&g-EL0*c(gLmz-J!?8db1l~5VFEd>Opl2`&c-5J_r +2fq?4YnXIde5QCO7lv!!bPuNEpDm;xl`7IxVqfa)^grI8o?o2L?S|wKan@`2`7eZU0#kH*_f#8Vtv2 +$8cH->!mVAE6R?G07Pj0$dr_k?Zq@y>muo&?B7)k1lE%fmLzX#nw;szI?c>iJ|mZ_Cf8)ZyeSvFqmRP +4Jjg#(!>P2-cdX=J@2t0eYl0TZi-epj~~+{We{krLbOk3ww?`7;Pr%r)126Chc`<6zmxi5Y5a-CzsG3 +SP+Scp)3zWj7kTm+mpd-g^>>2C=z$yXC|;C0Q&`|KRTc&rJ^wTgp+?F=+v!9>5ywCRw}pMTc0t>0*sf0EPPMrdw>zb@=uiv`38Ke$p#Ef?4U +~iy@EDQC0@vaL2J-3EsU>Ry7}9O{GdC+kp}f6kx>(-VU78rDOfaoxSya;E^s{FS`xo<&Io2x+mFQS$y +3=5wZ}BH@Y5+@904@j^oidmlnHFeVqF9!fT6-yJm@jo&$XFP7#2p;t^fhJxD;W_0`g&5gyH?tKRWJ(} +~|vspFV$D~A_$f%Z7(*a!Jx=tqBau$~6#2@SiuMhL=PfbthG;TGP3h~T&dHQ?Ajn8`%o*%TM;yhP$+S +{QZhwZW1QY-O00;m!mS#!ZWhwLf1ONc^3;+Nm0001RX>c!Jc4cm4Z*nhkWpQ< +7b98erb97;Jb#q^1Z)9b2E^v8$SIurCHw?b}DFp1nc9CQg|75cP_SE)Jpr^LS0D>|@+d^ifSxJ+`E&3 +Ea^wOu>Cn-g0B-u%uOGe};isH{l`GdIp?ou?i)n!I1>m*C~t4R0Ow(-_atDQ-&}ywOp_1H{%-E(VEj9*-{4e1$A39#M?*l`8|J=f7AFV;^g)u|38wK +q?XxMqgsge>-5!h?NLdJc4jQX9{h^`s#Yh%lDneGsKV1S;vXlaAF=+D^mkT%eb5z+;C<_ldAmpDrB3~ +{p#4W>t9Foz2(XzS+TO_bh$^}wqPm~IU^~TVt!fDyy2wufM>TdqOia13!hOhGyZlm$Gxl`JE#u(l-TO +^NL`B_>V{hN)cFiJT@`pa?~ePIxhv=%?8wPapBeZ$aqOy(zZSR(Yq~ +R#fY;bdc1JQR74LuyxNk%4 +KzTF1fPI8z^DPPT|U|rW!tkFi7;;$4a9HpU5Pdt+mB274x%lTA4Tzyp;y_7GFl8dSYyu{57)EZl@axw +huUrD{k8|OFt^pzUUUox6{2w!hCH2TJ|98^6|{z(N%a2u`#RgF_RkzFV;Q%-^i&U=j+q4^XF_fJ?hI# +e_>P)U*`P4<46B|i9Zpni@zM;LLdco@h5^2ti96s6!DAYJ^2}Ngopr!-sk5BzC=|BZbAE!r3*5<%ox2 +B7y#DcPZE5V#^=&ufp50?vY7fWb61#SaEs++_Fqs-0|XQR000O8HkM{d<{-)sd;|ah#0vlbA^-pYaA| +NaUv_0~WN&gWa%FLKWpi|MFLQKqbz^jOa%FQaaCwzhZExE)5dN-TK_n<72eyWN8-is(kak#swi|{N{g +4J0EuC#Pw5X6&JY(2?`|gf-#~75-mW!Zctd`x0i&!bNd9fT9r6i9MhZ{3U;>V}<5W6uG$8&ajQfnkQ8O-D!essXXi)iiC +KsQU3uB7=Z-=e>CU}D&dV-0YQ$ATrO_6Fyb#P#=l#Er9uE3ApkIDdKZYLCyTue@N>?tDA2LZ5GF6{5@ +tm)?{Xyf8NCOYUHoFl%hAXn#0K^XQz%XCrK&?I#zK&GE`GthpTN!qa>X7nCAQV6I5y&uM0BBCNG7W0< +z+yM6IGSCdXXu!SmrLhE=y>9dXLg6)=R6BEBoCyXX^vC)0bR5d&xeYg-Q$eUiH6l1fxhZ#uPiy&7s^BR0rN5W)By4>r< +P8eBjWb+=~Eln4@{mOBu8B&)G%qiUr80a<0R5BuH-48kA-*^H&&^R}s^2ciIF_1H?S{6TO-TZI?}cVq +JqlQ&qGIuM(u#a1F4SeGnvBM^bye8_kOD5KB=QlPCXSgV=>>zX_Sh^Jz?RJHQUW#&My=K@2MSD#FcIA +2^m?4{kfZZyzCGWn8|L?%R2C*q4*vk~%3c1C6PNH-nsaU1 +>~+JM2Ptn_wE{T(8fHp4I;E^eW(*lN*n@GM6%ZR=3XxOOuh>D3U%(PaRIJTwOy7W +Da~Z0DS?qSb$bJTImCuWYo?oTfZZ=xj`*k8w79O?}|$!H!65{9K|VERM8?Zo>56N3Ts;S{*!Pk7q0Il +qKMTLLrrm6DHCo&p&V(80 +$d+uir;jH}H+cp-7i~$9E|)p_3=@>08Ka@|XzX`Jj{$t$WT!Ms{sB-+0|XQR000O8HkM{d3+S?<4j%v +jV_pCN9RL6TaA|NaUv_0~WN&gWa%FLKWpi|MFLiWjY;!JfdDT4qciXnLzx%JiZhKD3P$DETrbvw-Z7Y54-~R3gKmrtHr`y{*XF4abL;@EV7Z>*%*cE&C_rx@hlWaZ`RXN*xgi +m&MdcEFGA^%ZHRjQyWlT_{e>U?%~&KHRi%RH`9DON>(mBdmBY?_p7F{`p^ndF%gXpB+n#1uQJTbW-@F`{?=Og?1Mxgb<@dlOf92KO*$EewS^#}!X>^n`bA_kKevL51$@~-@SeH?Bz-L!}0kGXikg}TrXg4d}y~5 +%bCE*hGiZq94(tlKkko+vcTDIBupKq6J;XFH20f!)Db2d6>Cwg;;57X?FH{nMIo~?T;;eLc}6eVDC9^S>=}kO5-o +r{7I&6ut2?~BrE4C**DXDPlVRN}X?NchGMESAJKQj*uYvu}h+j`%2jSz820}9@;FYF;J4lgbeg&v+!waa2Q&rB~f?mH{m$YSc`+dJt)RZz!Z{2wvLM +soj*X9oNU!R>6MGlL1`kKDS*{7iO~AVyK# +8$uQIay#e(~b<_b14sRR-%pqO;8^3<=H0>ne$WS~682KiZ4QF3nxGB5e!OfJ`Dx!UCBsqshmRgS+yKMew$oNC&3wVuRz6U+zeyHn1)<4CgGnKy +%LewYIG!M9$f$rloRA^_XC_g&2Y~^a%>wT%;6PR64;O(p;za^T7>ge_K;Ir1jhB^RzO0rLa7Jp51;n) +qV7c@mnFT=rW+X`04ckL*aK%}*ScjmC!_sL$n&Wp`$Lk&V)VgH~33z(BtCl32t_*(e7r3UbRV +7d<9Zz{BwsM@aBP7Uj#sTPr^ilz>UT0xR?h4zzD>~P`s1B9a3*h8qa1}&J^(gQo;V+D()E`e8>?j($> +49o%rXu^_BlM?lxx+H^=Wjqh8Hf%#%0cSZ1R_U;WJ*U%>F1M=jrKV&(B}p8sZmW5Y-sF5Rz1)QOfXV8*p(WLQG~KZGx-QM4L$@P6D367*gQ +V91OaUCC44rpeQ;`kPmz&+Hx}MwZ$oI)>%BvM|HQVPG=~{UiEwGA_@7bBZsWu+q5DtgbX0Sz$z +cH{2t`PI+!P!=5m6rDobP|NmpzQ>%5umVyF)C`In%YX>{Kau +k~$F>5{!S~=OqGWEy1@a+~SNDx +jg1pa2OvoD+aIS&KK%pNiqZ!$)As(=^0TFBkZq02mCUD#b`H4Fc0$E~7mq;a7y)f?-nJlN6s!;+DQICdYwC{@ae4C540f}4s)rnXt0?Qwfyw+G#SrC}=_A|VjVB#u)F +J^#Y5aCuEM0}PZLd@3*k$uFOQnQQDJLxmD`u5JL<-KAnDeS}$$(FZ0yc-flrAJ_&WKBDDj6kzfgM2HH +ptkN<;N3~3rhz!V|Dd=8d!rqurfo(v7rvMZ+8s`gXIHukzkw8|ABe42M(-dr%(FY{;2Q6Z7OK)<9SLW +bm4Ma~3tXC?D+Co;I=1b1?-&umk}r7#zDHxX2C$BAUaZ4bau7mq8OOu9mBsRwi>~1O#%`lE +)m;^k{X7>9thlo`IGpM39j?_U)nu$O;PpJMw~MANoPKPRKBu`59*)84&=jFGgTejmP|b?{Gvvyq@Qps +RVayk~A7*$njotZxZB#4Vs`Q%o)TwxrRg@H;BRFdF6L#&DEGQm@ +l*O2&;K%@}Pm4h@U$KdqH_P*Jk63(`s6`L$-eTOt5SvU>!>y#VV43~6kJ}+O2F-a<$-04}2)keBL^Px +O9zaAs*D$?4s1Y0%pVb4ShGZ$wc>5rJG+8*x1av|pz{E*Epsw27g3jzv%j$S+(bL#ZM;Kt3f$ +f?bBgO1}{;_rQ8;G5|pZj)h{|iLuy)ha75BL9eL@0f1JXj~xTEMEk&9q9bS&oevfoW9Ci$^Jn3(Z}dV +|?fbT7%&p&84En(~OC6g;b-4oCaPwN3thHeyuRhMfCzYa87VIFN18OJ9Y9d!nV<62aB)^90mmz@3uuz +GxItfIP1N++`F7lN_b|Qvl`H}X2}f)P@tX4P1a0WP*9*^Do1K*qPGgB(5kuOW#wcsw7_r*c#(zU^6z3 +we-cf=RH0NwjzY_#CCfTky3-R~co8kp7IEW)0GNY4oY0|hdrwF2KsvqysTq_vWe;H)mg%;3nZ4~OCWT +CyP*D>xArEYUSr0Te(U@DnLQYFWIL-4*GPf)!k$C&+slcEG<=rwixbz-DK#YaSr!n)wl;4_so&^gWyf +m81Ci6a#X?`v8%o>G~cVybmX6P}JU*~46c6H)~sTSwe1Zb*2Brc5d!?EjUdd8X6AGY63n8+sJ)URW)X +mbjk%}c@Oq>%gWgRdUB@n#f=%`V0;o|aZa4*tA@kJlB0*4tT=!smtq?BMn7r#*aVRIlCDu6Ce+MP2jZ +Pd|24JfOzh=S8v#9Y~KwqOQnrclGq+sCi|4cc84iDUnx%DMUdi?*4WZkTy=REoo#{L$w~_H@M+oyqZ* +2`wRXa7#Xd9YBE@avHEE8L~$INf)JZP1G{Y(wVG*b5_OU9HfjNxz-g65LnUO&!0FJSFcKJ2(FP!oqbv +}_&(2h6lgcRs^6i=HrU4hc0AYp>r%gXvsX}tv(RDQZM!9TX|J@{F-JVIv!CBo}+c+%(^1 +Bho6xax|xXpzZIQnB-xq^3^HF;Lbuy3D9JLw*X=fIs!lEtI=VUlq|5I6w5bC5pdMY39r6E&?!`=c=95 +dQ9P`0!yMd{o31EQ7I73-Y4#EUlf@9Ask9_pBuTGYpAMX;7WJ*WnD5+UN!sr~nE{HEke_{K9(-3M~rm +f2&)JFM991_xJta%WwPm^~rk>ELhf{#?bAQSAA7P^JR1!Fs76S_Dv1^cCa_gv;*c(kKcU@Zvd)Ujt(5 +%sEyxDH<%^hgQscDe&S0<%GOi4t05z|(W>9U_{=SA-zZ=I{Y<`paen@T;95D_>MrMNSR-3BcW{1(ptT +LDI&_1{etZoi*O0Nq%J)q93BI$!YpBKSZnp#i?Pe65ik4W~H=QSeF1=(2!fw|LQ>2O%5kq^nOk*Af#}MYFVL) +JJe1R1c<=QzBRd^+IigRBeaLbaw56bs|9yV4Kz?7(S0(kW9x?TwKv41HTjle^IJm`wb3#UsrK>+MLiv +1gTuEIO#&AxWZaShGx>k)ZFpOimNWsY&ASNCPh9ry9F$N0iq?-+>2Eq%4xP>ZBrc(K=4F-aK>dKa +8c}{5-V19vP#7!ucVm#?O6}ZY(U1R +dDFCDN=c7WcEotKtW(hSQ&$*{3sbeHRB9SCl!QFfDPN*tiUxbmnNi8mUeW%j|Sb!~zH!xBjcfD#$&5X +@m^TE;KO>5+9z>S8Exznl_-UVNZ-ofGU=)qSH|Lf7$dqM +bX&loW#2-RTdS4GlDinrOGRMTjMVSzQqu%^f<`jPR{DZ3NV)S3e)HNe^$^SBxs{l(;XO;cC5UMeWpn8t4oD7D2Rk#l-~f23E|T{b2jH#S$ +_;xg`WSGc*t%E*iHg#!TKfGqdv+8QV%^hpQTX7q`HO)#eArz$XeD(wKyco)Ic(wg^!IIRGZNlC<@Llp +v9K!G^mL|34wvsXhcv`Ms%hz%InBG6&*?CHiTbAUd=I7WVXyc!<(+Bm^;k1;8YbCl2DN^L8UxqM%q;+3dI6E;AGw%ysV +;`q~t@W*B0o}``zvr_kQpB{rg`I_DA20zx~6-`(InlF<0UC=| +R^E#X0#9+^XK_c5pLmwm+)Xd!8MDrvL=wF^YmbU_`sDj1`MT2J{Qix0Yh^3AQr1Qn=n}+aj- +C!j>iRD6y|&5m)=01T?`U{9D=Wu0oD3c0E<20A$A2`Nk}EZZ=;g-HIu`mWuz`Y7kZqRzz?DBMQQ|L_x +sMEMD5RnsBxtJ;`at0C$ORkP`@PY=bLew$0q9R;z+M*9(u}YXgnPQvnJzn|K>)p<&5ldb8{0||61Gv3 +rih=5r+>NUNoye{OYT~{5!Z^wCW`}xS8pX_(}MO;_+i~G!%P+=eZ{iZA#e0%gQ|RHHDeJPfk5v={i1? +zpAjyW9b@jwxrX|WT#{?hqpKudLQAQXu)Xq+{NK$mG(Ac%ORO<0@6T_#UW +}d`u+rX=5zXPpuBBKI}ktEM7(>YJ6GGaus(ws*!k24kwbkvnGQj?oM7Szpn)i{c`c3K%3X!-inIdNb= +Uf%v&kGY7HPDc#F4lhVMVmeu970pC{zg>6RYA|4}%K)zoI@R3VvS#K9FWlgI>*$nE2*XHKt?~PiJvsl +LrQs{ZhlamY|>!J68Xc1=M=I28lHitb^-E<7Ps>XP!2apN|(gM@;mQ3M>4|omy6lF(TaAU84n3P8WjA +0lS^9qcsg&!v&1i*lb`P9!oaMg)TD5V&^0zR_!;YhBa0994H+UL5GXJShAo=U_VK&W>SFJ;kz3u+Cs3QpCudDa6Gm$z8wLJRQaZ5cg=;2mooONwQepboS_)*QU4E#U`B#qL +&}|RUu3A2_X_K9emMhwvA@zywSN1hPMwEYT!K?a~mOY1?mHy*HKn(0f;v5YNb7>TKw_JQ5-3_lTthNY +El)(T48R0S5>hHLa!pmb5hbe>y5K8!dGhfYh0~ejW=&W69?1?nhPfyg9=MRFn?3h2__QzuKOjM~Q5mT&lrYMgX +udKi<&A&APj$gOz6_U3aG{HbsFs24krU=708*Okk9jR(S>z5aG4>w?G9VfP^yf%)koJCb +yhIlwTjOJL+Lgkn}uAAO7*`waJji}31>N88`w5A3u=+rj>z9SB30-pEO{ypW1dqN*Qv~EG_w~#hTnk} +woeYsR~=TFde*-r-+9nJio8=iR!liEARNqM6#5?aYC?|6y=b?-#yTkv!gn1meF^}YG0WQD&0ND8vs>u ++|&9{2a}TTJRb&9jWF-|^+8l&d|k;jW}^^NS&rU6K%j7P(aI>iZ3WN?q`PO?GK&Ct8A)?hSbf??>V>p +TQ4;V1EWuxC}n7(9EptpSHe3%Ku?_ +UA*&pUQ=)fG@uNLtj%(9|FNgbv2VNRg9W-N`heyJz&CEu_8ngL1{m}a8ZUroKNdfG&<@rY{?{cS-s2} +Ulm0L6tq&~n>ynZNsn1E*SO+e~44|n*|ILY;*4+hWHWx66o`bVC{kr13^Q}vgI{S$~+NaszHRT~+RhS +6HRN6OqV#4@_h13TaKr~@WAFVsE%Z$Os$F4sr5HeLc+X*v-g4L@x2M3O_qX;RlK99wtgdH)XGTV> +3BhLC?miTO|}ipS&yW^`zqLZ;#^Oq9faN1O-_b9fjCau>=Y@jMG1|JKY`o-wM``Sv= +RpMCp#w9<{KYV-s{Ad`yJQ;}QAw2l*WYc!@@V3FDp(hweXlTv?#_kvwqa&)XcZYe@4e-&PO6Fc0;6Qw +T25Ybegng`p$g2Y6SKMz8G<@GNp~Hu*3F(JhCw2I6>!fhqXk{=uPJ`wG`A|E;r%tXUlmyJuy~P_A)gvjM~~2-=X%*)W-fC`Tz3n +PR@|TEA)J)E_CC7?FEU&N^lZDRjIhoal^fq&<#-8NkXz@*5Ti&&+9^x+Ka74Bbo%xdjUH`eIN%D-TE% +^J;mwxoJ=_!9YIQ!3uOBz;G-;EzYormJ`gjXXDVoL^4bRbIv47rk9v0jZ`@xUZsc&oxX)#PB)pFAZ&e +|Po!b#xTz77;#et|lgYSyO8b9U?zcCMDv-#P(t`kLK(XlvD?`KQd?nDV!IE)^tt(kbT~dgt=JmYPj~X +_#=|u(ulFbh2YIbU__4NJUL~Ez=7;kdnf-HdN#sdt?p*ze$+~#H-)KFMx4eXJXcoTxIBeoBQ^1WU9yg +1tKd{u{5oPn97|u +VTUj!@m$4)}3IR9b#ZEt6L) +c3#mVurlQ-d;lRuvPE&T59=O^xYg^BmmyLV?7@L%!nUH1O|7yt9q7r|4iu`z{B%2Z8nd%pJU`kIa&5i)A<18BJZ&i?{XO9KQH0000805+CpNuD?-#km3i0B8jO04V?f0B~t=FJE?LZe +(wAFLGsZb!BsOb1!gVV{2h&WpgiIUukY>bYEXCaCwDPU2EGw5PZL1u>^u!aAZgb1w$VSZ6R-k7Wz<%b +&^)rHK$wUb}x?m>$|59yGdJWY^;-ZXJ>ZCUaeN1nWJxexN7}LXa3i(P8hYvR(lqkMPt&S*GZ{t8U72WKouNXJdm>mWBD +EJwv3*V-E)>oq{+9eM@Hr0try?#}hSh!sy%c3s10CnPI+5scNqm4%w_TU0MB$fdnp7j7Hl&-_D^ey!)sNh#D-WW~*1#@k(~**zdeDK7XyiZ(a28SW +k&F3UE@41m+atXDbT=8>xVBYU;RLOgZ@0#PzW!K#F$XW_DMx8O8uK-S&l%M`UKh8;by=>@F=Nr_X#VB +wbdDa-Awc#|_0YI0Gv(om2drJ|YN#|oc{m&>`35Rf(7dG)OH<&2>r=l5btmNbru`)I(2+;um=i8^&%e +jkCNFtMxw3VUWip|F&xocI8F;(d>{V5&ikkY(J%)hNMRf9Wv*2uo~a<>zLuF3 +d{*JWLy@huyACk|OSQb5y}rOg;(jrn8xEtAoZ!JZ?un#@=FSS(cAaH4XxI)Q4@ +?_@x`Ps|KOUo}%O9KQH0000805+CpNpWmS{EY$t01pKK05Jdn +0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoJUukY>bYEXCaCwze!ET#C5WVviqxcX +bQEDgZrEV%=2PdeGZ5g|fPu2oM*>=5a?Jjot`wkeAR7s?EPB1g?@#f9Y>%AQ?4)3Bl%%Vv+k3$&G7L# +xAPH)fY!MflE1Wz>670_d@5y7b3o|wiFRH}rONzj;aV>M4oi@+@~nSE56@OzcO*&={)Sp+wCDEXzdjl)y8dqBIE1z@g5W0y9Xe1~;vR#H|pRDxznWD>(w>RIk5%L~SSoSN^d3T +FdBx($HtN)~`VwYM@J^D-ev-bx7ZN%Yx@gGvKnJE!2U=Du|Edf_oz-!C?62`Wj>}v*j+0?tJB+FAvvHZbpB +XTAnebu+AS)O9KQH0000805+CpNpYONF?W#w0HQ(x05Jdn0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2 +h&WpgiMXkl_>WppoMX=gQNa%FKYaCwxyU9V-gkzo0Lf5ice!MK35eD)?85xZ-u0oi3&3*)j4Sw^GgrI +41=Qt%>_phH=i#w+VXg4t9hxFCGhuqv`Fg{iUd4BYxzx}_*&wlYwU;O& +Nh|CKOg^#&;ID;M~|=m^ycxK4{!hN?Yr0CK7RiGn>UZQ-#`BO{r`CT?YFP{zyJK_AKtzF`t`^6A0A(S +`}WPdkB_hWGoQVDYWl^yw;$hj%YS_H?{B_+|J|DpkN1CkeEb`I_UC{7=HvHYzy9vc|Et@#@85mj|M}s +&_aFR^?)dTB_aFA}zy9#%^~X2gJpS-kd;Fgt_4)&SefQUX)So^+e*E*ldmPtQ-NoPh_-BvLzy0>{C7= +EN@#UNE-+cJ@H{a|x`T6^IA3wbP!w>zMKmPvj{!{Hy{4|{iiwnr(gg6@vArA_edZA^yb~05B)a3{oxPazWurz|LX16Z{B_X +=JERb$9Meh`#=51O#PC9{O%seJR{i1(qv3mUB&Etpf-~921Z(nr}{n^KV{ofBE?B@4x)*Z+`cS&mNE8y?OI#ikZy6HOc?a6 +#uci{PX*s$#33#eEs&@@As?!OE2&DJ-~0jdHm`1zrX2a{`$?^mZ-<;-Xh=q_5arze*6C2zxlr1$|BpX?{P^8}`sq*q@|VAS_U4-(KKuBW|5V3M|J ++SJ{PaIN|HoO6$4`FppC8Z9=6S}^zdBcZ`qj!>{AwNNr(fmVzdD}hynj{Ks7b@;tov72t{Ohzi*MebK +0Zk_wiO}_MqOs>uvh|M>f-+fB5=Ok3Y3iQ-QR)`SKsXe0llV7yq>W^{apR?H51){8#__k6-- +mt1rL!+3&yl;y1tk*DpWs|J$#ydZB*)r`I14tQM;O{+kbKA(v`*@cGYv^^1S~-53AYFBtmB=#G0`Y4g +?l|7h_Kj~~CZ!aQCb_3VGvGhX#@*Q;ZW<5jEVdewiu`ky-aDPFDTvwwGF_UE4Gs}a@BdhuSJb<*N^zI +vd7k9Zk%%x*Nst8r%k)C=AJnf-*voUdAX`Rmawui5_`m9LJ2zs9;=jVt-^8L!4%$E!2e*!_<4(v$LdBAJ)+qoul~rRw>C4 +^i*cNT;ha3{o`-tA^lS9YJQuI~WIgzaXZ5Fg(8oNxH)iBGnf<3Tovg@YygjvhMwp=BC;GkOrJMI)7V> +cQI`==UI6`spelZvS^k3tNJRGi3KY9#0PZneUf&Z*65B&-+J-z)O=O`Y$5Vi}U=oh+1FU9jZS?3-{_S +lZu^U%MWblxAC6Df?IudC;)*Z0`{p1p2I_OG8;i;lB;F#Kmv=uy-6d$R0LTJj?O_C2b8LUnJC?EmZ!` +wmRnr}57D^0=_Lw$XUT^d{^{ +tJ{hrTWw`6S75ix}5VfAeB&b^Gs(ev9YlQiNZ(+$SVRrgW7zP)Kt9KGBv;j#NY=S#mh{hmFmdG{r +Ll#?qz4t^cL=@-pBpdg8{be^^ZMh7HaUCb-3xboSpOe((lru%TDdj59X~G>gYA<0V?W)73X(7wLMg}F +yjrjU&}bnkiCA^QD|2BUGdV&V$g37D=$Ph`oV0q-gCW{i+#L&@sr2Qfu`u6ilH8C9p|uG&L^^GzuEh3 +vLO@gbg`yKAeX&7{Vas|;{94s29w@uz(tx=%DkKNS;=DDXCU_j^ +8DpPg)%p1c$LGFYvCp&pis*)D4$BmI~bcGt3cm-Vu=0Qz3Va--ajz2C-&mmZd)i&;QB&3?aLSPg{xo} +EW;n6`d?G1C}S_2i?Ue_fc5Q**cX+gN9hckpWraPQJq1Eji|$ga-VdWex!d|(|w_ZY2kU^` +?%ki`E|v60V;dSRzIOdp$C1m&S=%U7&-kSrU&+Q^^CMa!f5ph_J0ok@mY7j?SnDP{WykIr^*L~$Af2~ +3j)iG5l_@b7SCd@v?wzp7iL^_)dS1g{m$pJ^}70+5zU^}o)P_xK>zVkOnk9WyiyAg;(t1GjuPQP1ND^ +lyPjLGPyCYTVf72?;Gk=f^X#r(yh|XfQ7*1N3m&H=i<{R~8$4YSZ5N#{qPb$bx4 +kTmvN&K7>ji3hgOT?Z?kVdwp7(RQeHEt;?wuY1E<_d*RN-7PF^nGT!bDr>h0_U=Di_?)-ba6Fuo}n2r)p35Rns$q2;=9E)HDM?dvIu-mEZLC< +g>W3O}op057gZ~G+&4rgy+d}vGs8velX?j=S=73MtLI#>y8uV$Y?_mW|rr~V5s{M>eP;g{e#JTBD+7O +WqSYlb_4>3%MZMlqqdd_1~e1phmo5nq#`vSC{mcfakIoc6{GwGi<_L)F0B_fY!@fg19~yCt@)-w<=xQ +`K%Y^6>O`?3&xJ4*ZgSEnIs>xm;ab0zR+fUj!v5BHl~Gi=!V-XAbq2nsJ=8)A`!++dja{WViQ15f7;W +3|=&Hn3lSxMI%)MZZ4bSU{$X}>vyq;!;3xf(oeMh)N<{2IGj0*@@+R;JGOp63KCC0ab)9k`>6?WX@?Fk&LZZV4bua}`tke=wa +IWEcrB0fj$`wQeY;oy=GUlcr4w}_Y(2o~PF0JcN(oQ;<&26^r6=>i&NDuax&4Q1zvO|AIk9+Wx@Q$Oo +{sqU_FKdT7|Jl@W*XTSl`0=z4yzUjWjybG@k`hP{dpyS5{>az#!m+hEDq%0m57;pLD4bVCfuLZ&3d^9 +?|`NnTOLxsB=|LvR~rmIuN`8S;RrnlD2k^>dsIECEC%MIo~TzW0SX@<9gDR0TkG0hw_e17TRhOA3;%c +MXsxHZi@5M)u^B4%;w0=^7}N)zWoy=xCBq(nnuqpFj=gbu2t5yKCpP5920Xz?IasYr!JepZLZ)&zVB( +qh);0XJ<*e{amPV$9cp4te%RRvR9jX!(o#E$`CulrR9WsK9#1|w?&54UK_C9Wd((!Ri!J)UMAC;*%u~ +4o(N>GcNm*QdUg9g;hU_%JcS|RmF;`aM$ux>a4h;IMHTO}bcO4w+dAi13^BO{_$La~dt$)!iv&xiT6B +ZGTT+kdF`OS%#Ip_TiI1#PW|$=vVkHc>8#=?1$OVZSCJ)>FYE#8NA$f0m?=uZ_MssZ;h +_TKUxlC_5nF)bIsfv38cs*f+N-Qf`lI#JA-(6 +J{gQba;IZ2auWU`a95{9Qq}%outEJxIofDrpSmcRdhfh73r5zvl=6h*Dn)qFcf;LC6bRnw(2P`vG2fK +Yd?L!NSfg-dxau~+o*Pna57rX>tY=|lzINnV6DFDI)?000S1GGdG)}8PUSW97-!9VtO8Slo{4;Q>7wm +!jLpkpS>xDDmPpDSj+kV5>eR2?%wHsTQ9pg2xcNUNspKV0}F2<*V@o=jdh$0e9{$@1`~Clh}yRD;gZr +G;UXL%D&llvaJqS%*d8tgJP +CYu8Sdf*&%m&nw`MwrZqbU;U186_;inze_aK4S;AKiT6Q_-==K9sjpg&P8O6Q5NIim_|B$WEE>Yhk9M +gr%*B@*K_yVen}68J$s>;F1C;%ERCMZ$fK8?h~QKW4Y3H~fwp-N>9js|%?)kV?zjDtZiFQr%qk%np~a +zJf{y8b4*C^^p=|&ILv)9T9Zy4rxy$vx3G0 +zbifz3-=#7@QwBE5XN4=(<}^~LaP*B4m8qaO@#2%HN=j$8LY@APD#q~^8zZNH?2t``$$|IQZk+fA!ZO(YYwwE=?Ay+t_=%YA#IwvDP_U1+KEz&^{DEK+rP^zRUxLCVm>$>moiP +l#eM;{ci2e?jeQpe2 +N2b00>k%cwz?8&X_S01t;Y3VVVXXVch->;X&I?#AKYlGmgN1Q{Wu#1hK?}RLg*pFO3nW(c4CKqLvO@x{ +(`Rm~|AKLYe8bYScOPXDStlSFSjH032QBG_ej-isCOF2)oTKeb4dG{;dKdb$;1m08zv +RSETpg((l0;2If6mTvuu$Zzc)zY&ShGNQPw;dE^NYdRM&Q;D6JB!ge#2ynfuow(jHD@sQ%Pb~HTGD`* +t-$xfrt;C_DdYH_eDSWWia;(kLGZ@;-3vn=7D3n+~wyECh2mjA`!*Ft|Z!gr;~ZZbzkABQ;@l!S7Qr(}kj2P-X5A8+H~|Jpy~jh42b_=Uk`rVTQKY7f*AlE>t?_1l2~Ksr=$8nUiB`4UeXhf!P-cf~f7c*l!DKN$g{71gY2_yMhy#p@gEH$;Y0DfEE%Qi6AhheD(krEt7v(+RHx>2)fIKVuetcOO371(malY +jHmOGCmQo4#W2_dlXsr?i15!+Ooq>IafgCpeF^$3cHXJq{`u0I#Oeg>Hv+JvHF$BubmtVRI-zI^9SeL +?N^BN}a-Di=m%HHZH{p|qAJE^xn}wL3M(j^^$VFVpi-V;n6*>bxI;~wuR)lTZFNa0C?ta@ZS-kVIZsp +RP%VbeBcq4s4_Z`y-AojRGT;!>)bvjENRz?^~UZvU@$X>I$vVS3kj@dk7!v{5~jaHilEyl_d +I!Vyk1EpVQ_1|De&l0cM*1>`bxBOsU7jf!lXOCD_-oxD@@mS*MYRcB9F5pRSGnO3 +#VD6V$e+TbnSgKF`Z0SR~^ui4En(aKVp~IV1h8p6ITHJyFT +fMtNoG_`_h|38+F0seFEOzl<;C?a03ysLE>}3YZlw&B+q*qqnS&H+rC}!65_1!)brRyYX?t9y`aDpk7 +>oB1fLwF8(#v77_JpfAB8NG-X`PtP@`2I9R6ru8B$$5NFPSKd1tML +iUQTItks3;)NI)E9g_dZ4nfEeRtUgV&jXBI+yKwhw-Ro&}EJ`Buz!;?#lt{J8P0EI$OC0&3F1jpp+oH +?FQ*AbPTuAYB#~0#e5Wm&D;!XU%K`q}yXz`HXpxkr6h^cnx2J3_0iHMKqr+I*v06Dr5{yjmIl4KGAr( +=>WIG4^0#_Q1bBZXv?rloR;qo4yYHV3D)r27?y7%;Kb$lZ@=TJUKl4{AQm+_`@&>-2#r%ct89XBl2{& +U+s4OI+u$K8i5OEFn64k}#QU@E!+4J++~N;E +JN0PT7gIrTZ=*_4;KQ8Cu4|)Kk$TT!Sh!rwLlGfT^LL;urRxec9?7d&9l%bVRO8Ikyt^xCArfh7p}B +8gx(Cu1>SmJ_!UJ4}#)y&qQeQ&ld4HZIBU +f?ieq8c+b1-Z_b|Xx9EaQ2U1P;zJ=CC~H+-85T8+EVqG(&448%_k&>}1e~JC&H@pb~5miuK5q7QhyzI +1-Mbg0blSmNV*JC;r*Nwj!KE5TRCNLsF*)x18MTfl?cQjAep_Xk}6;xK8WI@R}sd^h@0&F(I-y +n(U{DVf^T4f{7}^;C-GP7K<2vpJ+ +W^?jm5j5N|yRMZI0vSwuVk14^!6hR6D1iV}5sA#B+06D(!l|VP8xbQzLy4fJ}-mCzX^-=Kv>Zz_ok$? +1AMwn+?&KB1vz2F}6LX?zKH77r;h#$@`)3&iy-Ll%){+7+zc@j6o~SxY`cci}UWc{gS0J9%S=SWs|hS +0~Ix?5IWpoQxbrhHIALKnZt;H95MN8RoS`oL#K7G#7`$$Z&C}o&|(As>=Yzhz?EivJ=6fkH&JVJM?uQ +~sSJYub#5L-s+sXZT@l#Fp=4Mnt(`>)D!P;{I2cMFPHG86Wm1)j{wPTuA$EzhqLI@t79a^Ww=fi>%P4j +!{oCRFW>I(P&wxX2!!hH4@PH>*w>92kKrQ!`!P$1Z)&V9)o2cXvZ;>WETZufC@RmWal9hKCS)nuQ&y_ +Uoy?(V26M#la|Lmt+H!{@QJZyAoxj3Tp0`xTj%m0eK1v|&~eW%b+6~}2nvG8V)vqeXpQ9XRoD${?6N~ +onwVH7AlIttaqN07>k00DseAS80DN+dts;$zS%qS24*y{4g7Z$LUm_vI9~f?7$Rq2En`FQ85~jckD4m +X{$!Q`2Yw&B&n+sKp5?sjG95f=chM7yE{cH0x5EF7nU8d!XNRsM>O}EUX5gtgmz1kMs1cl2DVun-S{z}YWRef7jCQ5TDR0DmzvY3t*Morg#6>)TLJxgoh +=03?h{98(K_QZ7wuY6TcJ6`#2iW6*c4VmnfeG$`*k@tA4Uga1Uss$3ZnwL&M +>Zyc5YE*(PRH$zR~>*e$BeiwX_Ww%PrWQt;{{f3*5v_?<^A#*2tV?7Mf%0awv;$g2L*SOb>y4SS>mCI +2gVnkA;j>iy|sz4Ec-hosr`83bT!8N7FSam*c|AD&K$woK@sCeH8+hh=AP@P6gtlzYA(6cqJR0>#C_#i1kiflZ6*Uit!yZ1h(fXhl)i +hhO)`njKuUrk(QNjy^Upt|QgtneW9$GOl6X70cPs$IHEmbg$eJdyJB7y=TCu^(o6ps0gwiY*^oJcr +s~`+d~Co=@{L%C9 +QVnfUqo_LgLP)4q&w``hR{JFL@l)_kuA#%-v!3x;elP>kV%64fmI5?btJ2Ww8)H*R^L?)4E{x +oUXunFz00fQjEV)v&coGL;ebn;tfsjtO0|mNeMg{OqLeb&W07$b*>SWRfROU{`u}m%|`SHB0sCi4A#Z +Up+N?$?A+RHU|f{w4KLaN6{=)*8p{thP)7Px162=3{QLVK{ZYsl9TBa2tYwl#YnQ}?=tTa#c1aT<8SkL +AJ2En>KmL~?12$!JC4&hHr(1>&?qN9B^B(Wzy5R}xYNYjQ5*cU_F)L{Y +Kqe)478R%yt%X&sSjd5qbqP{AgD18=OEvEk>=913nS(0q<5rBUn`iaGNLKJYLL-1vNfd;5_NsU;^||}SFTrP7VBsb9f8aBPkbT#FTR(~W5su +u@oXFFac2A);EnB;}=dkXzEIm*p4RlF$%MLsqNuYm*yWx;i2#Wk1&(b{@CLEFYUC%YBdp(JQCi>wa#1 +bhG0396f9jP`aD`aIN@bf{f2{HUc;=n)Ksq&!)e?C2qXN|b!82i48LEYj&yyPigKp?1mPX;R*OJ6;qa7sxR}QqhnX(G +074|&VP8W!?Y6pa!%L^TTdoJyw1bQz;bL(GSSCrBVr_vdr#}LSk>}G7lj#6fwA+kgSyuPz_zRjvpi1_ +XB2(zZOu$;L-6t7RwpjTR1|Q?4$oS{G1uJr*g@UviE=wEy)`rqPZffXk@7`3rvCJokk=4#u1=Q4;~<_ +6m`oX{o>GzNl&RK%+3o+Ffke9OvCH=W(umY!)qo3sYN>@`TgQeN#-(Vcyj8TG%bnWFJlivrI*NpC^Mu +!=o@yhs$FjBoPGpB+@zy`ra*F0zFZLjVO%F#F5S+t|83-xX(#2QN1sWaVc(in%pxLFco@dutk^HXW-! +umVFZYtZ8OodM?Tvh6t4Qd67Zg>oAB}ra!b+I>Eyw_WeAG<~&e&zZ@W`2wYAG^O~x3bp71tyN7kJ!_z +XBzbo5Nbq?{IgcgVDo6_Im4N8;<53jr_sZv?t=5+=5O7}ci_iE8)nF>Wr_KHvc6aO9?0<%1bfX}CT&QsA`M0cJn$`7QRF7bO{OlUwHOz&PAsBy%X080Aq@_c7Yh%1>0t;soxR +#&4>t9d~0RTklw$?y0EZnHq|9!&B1A6jh!^ACxFqac-C>;r6B&PM@4T&595^s7~Y?>h +^Jla(vc)}bYn-=H^Rm1qgVqx4xMTUf`{SMd7!N9klc4SP2H-L4YI{9t{(|p91OD=aBg|QAe!5$sG_Wd +w}y4OkAJUre?ox;+6ri%9A#9teRP;LhgqZILR=|iiZtZnir85SvTf1SG5HBGd8EaNbl;*m_;XOrod_b +K4$S+O-e_>EaYk66^@4OPpiX2-{r9d;b+(L#0)fMTRO)p{T6sZtMxRH0hb>qJ6}sWQ!|r~=` +%5^V^;EhrGPzL@l6?9sPVS*3mKN6yM()>yJf*3F*m`<0a&3Nw?R`0{L0{f6Al@{xK3q5Fft^S370_aC +{()ce@T9=5lJ*U;F#A0EuJ^HjcxhR??Ef8?L}O(kukw{dTjxV8s&!00dpxb;obiy*|8l&Rc>m;T +(mSWWo*xI6{jM&Y;qQKEvVWxYmgWdMy9Z9Nhg<_qsTk@G!I}ivocV1R1?Xy1A}1B9^xFr{FQz?ZY_M5 +_2v7)|1q|F3WQjn9bREzai-H}3Lo`$95*M}b+4ZPMRRWAPkc-qaHc*cPUzE%#tdeMd3eD1o +;LEY<#p<3QGMl^WBP7m+V+EfR=f;Td$pgvUJvgv6Awcpjn&|A3Yf%+252BxR%w;gi4EPJW6^^WQHaF* +PI{wMoQ9}Gc#?gYq|2kKrQR&kXb5m`@zSrK?@zX=As@@B_bXa)UbY?+tsIX8!TZ`T_Q>t6S51D_C+l0ch4S~{k;7s>RyLu2_e#h;=MI31Hf0X +N*Fi$9F`H{A-I{%E)VPb@E`CQm&Ld1jq$y@lssr(;)ge~ysib&C7DBvzpz8oySU6+>=H3D-_#E+qTG4hO1`Xbwxpm+$38O;jSEex&$k?+fZ)&-8qY7d`;zEN+*QeVP@2gjEW>%1+3So@YVj$oU7@&*`~PpQS=1l+Qb1Mq;U^`4wgR*0d#nsE-)oH|T*9SF`Pc2mjIuVxA~H +xe?y@aEgS8PB9(y#(GM!TIkk-MfEjIJ8pe3w!-P7lF +Z1^R&{95-)L^p?Lv9!IXr_)I9W9Pkeg%Y)cs;oJ5=FEoEQJC^V;sMh$H$R)yy`GeFucd;X$`t$43H3% +-b`8w(IQC=wu#&0rVO71h$2|VF7n8cz#pMdidp^jfEeohjMC0X5$-Ko1LJJ-FWB=nq;e#3D6Nu){n@; +b0U7ks!K!TuT?qkO3v)U{3BAwo*1T5*0l55^{Lz$@N(dnkSXG$q@;&c_L_YT4rjCEH{B5EilJ~#x26nWyu#w0sE!C#M&* +(o2+TEEF(>h9R8=%h!&k`2qI +aG#c9;VLDZSI-m&f#&GNunElzn(X${175=zAoDB@8qPeL#63-U^1Z(zWNUHhCR*qt~_a-m>N`Z +ZyIz=8v?rKjapg2T%&!dsQ7+g>|fU?komvGXm!8}1cW>tbvz$2~3hBL7BUx0QBz*&W)$bHBo6f?iMQt +u5?0^2a?7buP52-X&L_5b5GEDS?p-$ +#U;a~CWz8~_5i%Z*w7+8nvnYX+ip_#x}-pq3!Ma*=V`Em#_~=lQ`l1{6b-O%kC6*9K-2}Nf_XHSYu9B +?>s~<`GcCF_)HE}i-n{L_kp7j&aBRU_w#bzbqxEZQhxS#zTp4of2kKrI(|+n!P-S!&;O+ZByix-1SRU +{FxZvYSzH)h~LwfrrUbi4}?R&o_b+6~9lGb@c2c`;4S;dLKkW3SrX?PEW2s1yb5VgX747r_Mw=$`FJt +;$a#J-iq4`7F+FYs6KDo24%_}$v)4o;_~rIu!oFf~MyGj@J+Qulh09G(`|@cBh?`bnkrvUEJX7Z966T +5wt4jYCGwEWhJ46t)Iu>dfO_H_izkx^mLPX>E^nL|(tmw%(VDIT(P)rkw~D*Z`}xJk9qsf3nYCOzK_- +^>xDwIJl?g0a;xZIa_Z@7IxmhbG&U=Lf3`smMuE+g+Z<>Zh4^Yb&y+`@X6B~va!{Rw8KcRqC>i#mX<) +*(nJ9#uJ)Tb{?c6a`P2dKo=Z;~7v6<$y?6==dwsBz +wav<=KdL+Lx)d4*JtPz)O(OWxrngLDFTAyd2)8B$)?>pBAN@X1O(O-Wh|BD|7ee%)5@CGsG{8m}-d-0 +f!69H%$s4tINW2-`-Oq7|PS*aPZuj9_BK!!Elb9FXY_b%k=vOa;E^1A1|^jFBk+MU?B8x!?I+zj>-}> +@13~>ou{|guAT4ZtV55Nc*y8cA@W|TwSRK4c|XHBEGRO4KHVm`hN2SB*AUB4Z?*e{mzd(kF`PivlceD +w*LQkly{F0v>QAAj>WvU!dQXr3uNS`UqtA2eb?ROp!U#sR@YI$i6`Zb_o~gIYZD~QhhCo0ua_I$V{woZ!6 +<5W>EL*s9@=Ai;m_q|p!*=I;hA=YvR%Ty`~EY~>&x(BMo%;mp3L+vIsB4oj^BGYaZX$wO2&uZ;ZdFxx +EvFC5pRjx{DClub#pM@4}&k}vB2=F85|%ki6F%rKa5$~7sq}tm(f}<+?iXSQTKXqQfYbSgOFu66`0`r_U?TKO-Rtluq&J+gy{GqsPtA?r)NpulEC|!{ +WXMaJR?YSHtq))L-tWTR?CbUW+i(ZGui5-uFs=mDpCN%kqNz{+&tP>#^-D?uyq}dI|6FhCcF;xH^L}m +U(!iphfq>pm5}b;S%m)=i6SCyaea+Qtzn9Evl6r5ON>hbGk2I#2XPnnISh_KmGC&$khHij&0wpdyW0} +>;V%(&Q@AU?v+p;jC0AD^YpLmOG2R#kQ0$0$>aRAZrrOzCBh25jA<1hAVc%)1Iw=@z%}!GJ;>Sn?Kz= +B(sxyXGx3@CJn;QE)G(~rpQq|;Uml98K2;@b@Zl*HMA38OeqTp=P*V9NMsqjb_JX?Ca~DkNYZA$kq#u +{|kbFRz6!4ZquS6L>5Di3f+C;eL6TD(I_I-Ghy4NAr^RV!gr(U|xzO!FwqKx3+IA4HzYZttdaBa5feJ +|cafAhq&>)HuDJCBb+3cuz~MI!SR6DxQb%r*SYnu!vI5q^J13u8vJ9AL;;XY!k3zv~q!6m9`?TfI=w*I4jSk}GfmhFpQBLHMbI3PE@UvA&>4LMPW@IjV +W!<4riLPfon{;-1OQ@`*M3TRL7de~nM1JM&HdozD%5530I*QGpgdvDkwHw+YPqSse$z0S8;yqrpx#0N +)q`7K3$RmbI>JhE}$#tR07E5if1Y{~NZ_!O5nFx=yXm!#MEUw(k?>Vb9lu_wF25&0~32>Eu2MM`!(bj +oBL+iu?DC69wDJAh-;Gbf(^wS>rG4C)t;`zwOf|5#NMSkvAx)Iw+#*SN>qe#sI(u03ynQ4c7GGl=B7* +w#>Z1(Nr85fXZF%hU&AH+p;G*x#$cCAcpKcHrUlbQbGcEMT#iM@T(jD!KOCF}xCx*mA+tmMF}7{w}{h +>AL&nUNw&Z8qAVhTe-8r&=13Q&oXi#02FoN4;*l|WkD)V+OlA1d8yc^e!aiMSv6+$UNg^XdSHnBo9aR +UmHW%jc=Yg29{k_SuU{a@@$Qj*kN4X5y}C)YLl$U&6qfuIfZ%zJ@}ee5C29clvC`RBj5KW?wAg+WSJw +4-6;7&r(tGyN{^??S?f~^-knD}+-umwG#LJiS)R5%1vbL_hAg6Ruj2A4gZ9@23FpWXqlPR4w +)L9A6OIt$37g4X|i`b{5>oEIm~BCuMi>a`98o3IaKL)UWOyU5J~Z8w>`Qg;~O5en6 +=*0wkAVZ(Tqz46qr58PXpw!Em6>Yls)fdlI=v-}O-0MvI<-ZlM_1dkL`yEPBpVVIU)jt-6&zL(`Ank8 +bz+?kl`wcPEFV=EefMUbR@aB4-u*W+*Crk#B^Xt>gIF-iB6L~7N@(F&?q@DXVOg#QWd3y}8xVq)J{RfUqw +SD6^I@ff*wkjd8@)`{stfdcx%XfNs$1fWU1zQd1mK2ii^P3!^c{xw7z_fCWu+lOtD~}*DbM9Gk#Z3!p +vYlVY>riM!);v!*}n$f5VsIAjnv86Km-aZewl>N656ZODFbb`DLFH1n(@R!f2Lp0iMO3%;XpWUsm +Y!QpAAT_3({yjgFd7)n%EmHzgs;%VI+0Zn<2n)bjOfJN*=JzbqcNc5|FJ;_*cwxrq7}?$%Obyb7JG$d ++HpfjwVbq_wyrYH`|r)h;%pLb&_ItWa0EtX))zo3kV#u#Aeh4sdae&7$IBaf8|7YMaH)49n|VP*tmL< +4f`E;-u^H-YyPVE$<}pEDmL~i#ppydE>HBmV%f?M7#`IRc(Hk5Ha_v+n9N2tcCO*me&HJ5f(UXL9rH0 +VX@~I6|Bpztl$vT;t0axOw#g13nA^QovffZtoua;AoYubE6aPAIO?%DeXzW%#~UK3-d+}DgS?hyLlo6 +4cF}^?t~>ckZBqBk2En{8H11N}2tA1E7xDNa`d&l|3omqGTb5TFs0!H~i=64YZl}~sW66Ro(q7ACmq( +2Kst-JoB{_s1EiZcZUTuKMvSJ++u?+W#>eqc}b$MwlVe}&0T^=U1tiwRk$cj*75f?1IU|n3i+oeN^gS +gOs3(sv``w%GU?(P>^LH8|{jQ1FOtD;+os@eq!TNH;ZE}mJG-Y@SS_G(=V!mU)f_Ls7egzbKj6>c(HU +cY7qt*J1a=!I2WT<5Sn)5a;v#d*KQ;e|yR?V^NxS+aKRBEeV^xQvSmktK4w>RvaJL3)N7B))87aSy=qI~2Ul+ph@lR(uZpFHU1GN_+#*6kO{O6wd~AA@SUYddOk +C1eYxYC-H+z%z}%>f=h9Ndbfbi1rQ-PFc+kBf|`{8L*X*p>*X*p>*dDf)Gq{XDgqQ#=c?L1OE8=Q#`>b +`@btl-Rea1c80EB{?vY;L; +D47b1b%GL>pr#@~%t53Q_}PK~9Ml&C#Q<^aWChW0_lvBMV+}H;0k92#b&%Bxl2-x43m`_|x(8lpfVu+ +|93YthqQrgaJn>Zbi>!cd1A-Y4!2sU{)Gfel0X7S;S-__P{1Qa#L69E=`9aVcH>4*>=zftEg1aE}3Zk +7LJ_)@1z;zG2)xd)ce7?ZR3p}jAV+kC9z*@&~JG&Im24~`ftZz`<8JztMj${PIUO|dD$bhtae_!8@V){x6=0}<6b0ZWh~R?|JP1dFurY8p;<)a0yI415g +$rsncRB=|AvmlV9McZ4b8r+ +ms2mLr*u=RnJHuz`ei0a=>YxNP$lwQw;UK{n;Lf0CJ1CA0>Mw&j!XS$q6q^OrUqM+`ocmH7e3tGPfgu +GSxhx21TPmF=$W>8dTl|sqY|h8c +?+0`2H-{0coLXIRGF*aeth<_z<6^`$cLfbA+w)6MY~$R6GQDKfss)4+uQ@;69$RJI8hj!#tTm4 +1*hAB!!N-(mY^Iyfb>BLUl3{pXg+|`0XL1Y4^82-biW7@>D3^^GRr3*Nu&q@WEzmT02BmKY7m_Tp+Zp +b6qG6j_0}=wJ>K?9g1mN6p%zqH1$8|^vLdLz3Fu>h6oYsws9X(-^McZppmZasm<-AaW5hkb?Uw}gc|k +#5kh}_N%7Ox^Ab}f{6b0o#LH$oqz!Ox~1Z5=w(+=uLf=Y@Q`!Ym)mhKlxqSPWNgb2zWf|7xtJRnHz2k +G4)X&m7WSmmn<@q+5dIO2ASB{2f5&fFB1qH(;~@dktu5Ktu!3Hi=;ad>Qk+$BSPAMhsY60LudO6`-$x +ngl>9Ku!TY3Q#~0$Ob`c>@FQI(lWQ+!Ds1yks6MS1@+{?8L{9zSa94cD7Xv?D}vI*pujII#wv%8$Z!l +OI0h8=m;BBsXX$G_zkEG2#$OPzfKvkvZqRZuljf3keQ*1PSVZumx4oL0xcA*BO+51eF&-;xs&cP_ +7^f3C0!Bf>_(%!Do31jt2x8`JkXbD9{fI^n*J5psqe(oaf-!Y-)p4GJBD`n8|{EvPOFim`&sd93a4;InkUh!ZLJAWI!2#ey7FkmL!nG(nmr +NR|W$Js_6>hYXlez*K_dS*-2v;InkUh!eCwU~NI6YJj1F0@0vAG)zFgry0~~#{DG +^_$=KoGDVeUP*)k0R0buLK^0}JO^;}fU{U-Sew9i&H%J#HO+h_Gti0zJzl0oikUj~3c#ts;asdGV4!@ +J2oLa|Q{siUr%IE!`bbu_a{bdaJEZr|MMde*kCKr^t1%+)vjZ2WO3}}B)Efy4o1*Kp?0a(C6gCeh>QY +K>CH{6w%p!O=LstU@ef-Y0db-*8t*w(!@ylT$dtNJF4iEvPMj|fGa^vCGkm%CGZ38kJq`8N_GwGv<9lz +m?^mvg$lG{OYJ4iwY8QUNi8swFO6mgK~4RW_ZLN-XghUZV=Y!P<8ldpIqFF|HC$gBqW)F6Qxq)UTbXp +jaCGN3^QG{|=b3CkBhvjMgJc{bZWR-%XQIIqW@x#S!U#F_feg#2|+3$NFhY-%dPN1x?hBdj6skh2-Cp^holH%Gk)Kh4WSRl_yD +;F$UQ*r0VEF~c>u`+kR71s09prZI)KmtgbvVi)IKzY`|%Rc=YT#3^f{o&jEU#`Y*;81P +xP92A4i`>2H4>&!hWAru1Gk-5ME11ue2=_tSKa{ojh2o`KQVABDc4%l?Sqyr`$FzKkx3Ggkt +Ujz#_9kA(uO$Tf`VABDc4%l?SrUNz|u<3wJ$G(Zm1x2cAU*?H#(fuM_0P6619Q{csbwH^DN*z$@fKms +PI-t}6r4A@{K&b;d9d~jY-=h0Prl8aTr4A@{K&b;t9Z>3kQU{beOz{akK-B@N4p4P~s^faz=zftTQ1w(E;MD=I4tRCIs{>vg@alk92f +RA2o&2S(%_tA6U6g>s(ETD)5bS_lPhEBJb%3t}d>!EHxU86*ewdE-=lD+q3R@c2=94%K-7n$<%MMs}z +_J5|9Wd;GVFwI5VAuh}4j6X8umgr2FzkR~$F=z+ZbJ8qOkFMoG6l;H7H;qwtAKz0DK<1#V5i|#Q0-EYfOLbVgBolxz +8@0y_P1Z^isJ3-nB(oT?eg0vH)ognQ5Y3Kc=OBnr^1Z^j1J3-qC+D_1Rg0>U1ognQ5X(vcKLD~t@PLO +tjv=gMA&+{H{`y~n5p6Hl_Zzp^^;oAw{PWX1hw-c_No}@z;C2%{RHuFCx&F;96;@JdpCy+aV+zI4PAa +_2Uj77^u%SFq@0~ak8Efy^nEfy_qKZ@en1ac>kJAvE@n{E{H>1c4_A +JVD?I0#6Wlg1{35o*?i9fhY7kq2CGpPUv?+z4N^F4#l$x{Z8n2LcbIGozU-uekb%hq2CGpPUv?+zZ3e +M(C>tPC)7L7U9^t@?tYOP=yyWD6Z)Od?}UCQ^gE&73H?s!cS64t`km14gnlQ~JI~v%rg%1?-wFLr=yy +WD6Z)Od?}UCQ^gE&73H?ssQ9{2H`km14gnH+B`_&ZBCiFX@-wFLr=yyWD6Z)Od?}UCQ;5z}|3HVOHcL +Kf>;GF>PJolIBVQ0HvWCiA(evv>qQ79U~cLKf>@ST9~1bippI|1Jb_)dU#0=#qV{5*E{B>~?F_)frgg +1Zyko#5^ScjwTDUjCKlNDG)d!Q2VvPB3@gmlk4YyI-UR+@0X=1a~L6JHg!v?oM!bg1Zyko#5^Sb0?TP +!Q2Vq&btU6!`l5KHIVLvbSI=cA>9e-PCTWAbSI=cA>9e#&f)NpmVJo@%LwMS-}Xz=Yl6!@kROc`q{USg3%c)^i{9)edq4xVH +$|0Zrl|GOgz;^<^6X2Zy@4PR!!hUwY$PeH<0pAJuPQZ5pz7z1BfbRr+C*V7$6OY^gz9(^ELcMctK8eZ +fevQGL2P6sboq+EId?&a&!QBb&PH=ZZxD&#i5blI=nJ)?HPDpn`x)ai!knV(ZC!{+e-3jSVNOwZG6T+Pk?u2kBgquSw_Dk_>g1 +Zyko#5^ScPF?z!QBb&PH=aEyA#}<;O+!-Czw0I+zIB+wJ-I@P=AGc~1a~L6JHg!v?oKdwg1HmSonY=oE&~}2f6QrFW?F4B +jNIOB=3DQoGcHUo-ilOX&5hBobg0>U1ouKUmZ6|0uLD~t@PLOtjv=gMAAngQcCp0@_A8x`>z9dvT{Wd +ztNkX;Li$lvNAW0zY1ZgKoJ3-nB(oT?eLbDT^ow4f?v60;`LIl-LsCGiNCs-yy+X>oEXm$d!6Of&N>; +z;dAUgrs3CPaaaTeyW`$dw#*a^l?@O6T(6MUWFJNOvn240=;>V#J(ygK3439rtZS7RQ#U*rc~o$%@eR +VS!ALDdPWPEd7%suNV5pz1k&0&=7N2TbRE=`lvJ`$c{L)CrqT*mT0C6D*xz=>$tBL^>hT35iZfbV8yN +5}lCfjGgz#D0aWd4@5d4(g~4Hh;%}v)8jzuaENq5q!SXIkmyVg$uKS8=)5nL#vZ;TSUSPd36@TZ&>4Z%uY&z4MLL4e;2r! ++w^CFnS?iV3~O($$RVbcklPS|w9rV}=uu<3+NCu};w(Fu-DaCCyBGxsGZn8KG~SO=Ri3QC<&>hx+nLncsl=FY!i0DHU$7N|Nw)d{LjP<4W;6I7j`>I7A1I={$N+8eS2s!mXK=Dws31 +K9l{Q=sYuRVS1>q0|YWP5^ZRs1rb)0O|x#CxAKu)CrSLm~`fK&o6!nY&v1n37byXbi$?+Hl1khR8zpF +6E>Z&=?QX80CfVU6EL0krA}D9mjqBJfI4B*37byXbb_T5ES(VPgh(euIw8>siB3p#LZTBAowYe47Vl+ +3coQt0VCe))Cs;bc(g~JMuylf@6D*xz=>#b!jfzb(!&hkrDeFE|WkxqzoLZlNCosj5+L?o%bauSheo=&+99P$z&o +0n`bg&Pz{;C4f>Vlsci*38hZxbY8o@1Y6eqo_>_(2o``k0n`bgP5^ZRs1rb)u<3+NCpbF6(Fu-DNOWG +eeWUI*A<_wvPKa~@qZ1gNz~}@7>{U~~eb6BwPq=mbV5Fgk(J35- +r)bONCh2%SLa1VSeeI)Tu6f0;BEtoucrfYAwzPGEEbqZ1fC6=#TaLZlNSouWxdbV8yN5}lCfyl(qO-D +^Um6C#}u>4ZopFgh>A$+tn0E=8s#sesT0gf1X-!JiBMT+huBv0E<%hb}mD!J!KdU2y1vLl+#n;LrtsF +8Fi7pSgI9pJ;Z_?4a4^h?uPI_oVqrbFTDb;}%4^AkqbqE{JqNqzfWlkmv$J7ZAFD&;^99`^!PGR^9LL +bv4-ZG3aB^$Dj{RpraZJEL~vf0!tS-y1>x|jxKO?J?}Vxy4M0r7g)N$(gl_-uylc?3oKnvAGm0_c;KQ +%(88AsTKMRlC&Myzzd_5OWzaHc8MI7VCM}beNz3F}NekyUX_2%@TGTzi7wcBEELs*Vi!}kuHezgr^oby1>x|jxKO?9k+d>?zO?zLdk +1)DC|bit+zHeImkf=w4}x?t0Fc<)F05t<=EfawBE*Kyl7>Rtt?x>wK%wYTDdD5U8 +~5F;pcL8t4uxe;}*1*I-1bwQ~MHeImkf=w4}x?s}I@*mS +|B3pQP_>4HrcY`S361)DC|bit+zCS5S;f=L%l+J4(FDcE$urVBP*u<3$L7i_v<(*>I@*mS|B3pQP_>4 +HfYOuAswb$_WKrltEueqhrDn=aUN!KMo~U9jnbO&4ssVABPgF4%OzqzfipFzGsXejd}({USB6>4HrcY +`S361)HwZn^WwAg#u6)fVu$G1)#2T>q7nz_jubcDJXS8sS8S7Q0jtG7nHi7)CHxkUE*k$$PK8vK-C4R +9?Q{fUX4NNei0&gb-}9(US06&f>#&3y5Q9XuP%6X!K({iJ*R`d{D)@yJQ)V1`$dR=)&;aKpmo8k3tnC +D>Vj7nyt?4k1+Ol6b-}9(US06&S#giI{gMJ+7tp$Z)&;aKZ#RRg6y&-f*9EyQ$aMj&3us+H>jGLA(7M +KXkGK7j0$vx;x`5W@mptNn7Ua4h*9EyQ$aO)k3vykM>w;VtfJAlC)CF3 +5F3t_yNqP_u$u7v#Di*EM`EWNGX#A;4~QzsMBOy5Q9XuP%6X!K({iUGVCHSC?P$h7UdG{vBV@O6Q&3w&MR>jGaF_`1N?H8wZGN_4-76BxU|*af~W@O6Q&3vykM +>w;Vtw;Vtw;X@{pCF +vh?jz37X-T?*9EyQ$aO)k3vykM>+jGb&c#H+ZE*N +&funUG=FzkY17Yw^#*agF`yKWnc(ETDwY8F^_!Lkd6T`=r|VHXU$AlC)eDF8_kWR#wlmP5TWw_lAh=z +ftTrDne*whVGzkn4h67v#Di*9EyQ$aPJp7LkEm7v#F;_Ny@l-7lg8w65tTp=BeQ`xEj5v@W1^0j&#YU +DH`YZh+PWw66QIYK%emi~Ins3us+H>jGLA(7J%u1+*@pbpfplXk9?-f>#&3y5QAy^J#&3y5Q9XuP%6X!K({iUGVCHR~Njx;ME1Mu664j>Rt;}U7+d$RTrqbK-C4RE>LxWstZ(Ipy~ou7pS^ +G)di|9P<5?c7laAuei0Z@b%Cl2R9&Fz0#z5NxIZhx}ekrr7kFSL8%K$T~ +O+RPS@IXL1_B!7pZ|#7nHi7)CHw3D0M-p3rby3>Vi@il)9kQ1*I-x_JU4V>^vDt{-vPQ1*I-1bwQ~MN +#&3y5Q9XuP%6X +-Mku=-u)s;@alqB7reSa)di|9P<4T-3sha8>J#s{;ME1ME_ijptLx^~X!GtDae`MDyt?4k1+Ol6b-}9 +(US06&f>#&3y5QBd?=1^|N3(ri1a02^a)kvzX99Ezd|lw{0$*3y2sIRrGW-aAAXwn*0$&&8x?-P~Mv- +^F$P@&-AlDUkj!Z$W3vykM>k7STpMYS2uM2!#;Ohckm*2@nzxX9!>;hvK7`wpN1->rub%C!7d|lw{0$ +&&8x**pDxh}|cL9Xk*gbMZjQo!p1S{Kl|fYt@HE}-?P#|XJD$aO)k3vyjR>jGLA(7J%ubzhQ?`tE)aC +!lo!tqW*fKw;I8w*Vdcd={F!`$e39)&;aKpmhPQ3us+H>jGLA(7J%u +1+*@pbpfplXk9?-%I#O9xw~H^30__B>H<|4sJcMa1*I-1bwQ~MN?lOuN+$@BNqrzz`o0VX&E5SXKTzs +|QWuoEpwtDWE+}fJ>b%E`Ujo4{2zCLj3us+H>jGLA(7J%u1+*@pbpfplXk9?-0 +$LZ)y6(D6^mX@(Bmu1pXk9?-0$LZ)x`5UNw4MOp0$LZ)x`5UNv@W1^0j;ZU`$pYs0j~?1TjlE_PEfuA +$(7g(T2(?RXiBLkr3eHnWzc}HT{o{rH+R2ClBQ6rhT<>OTdCfZOGQB`aM||?I(#GuUOkMmYsd4b4H +rcY`S361(Pmtbb+Jm+VMPkxcfzFz|sYlF0gb#qzfWlUS6(e36?Ifbb+M{99`h(0!J4(y6!IpLiN5(=L +j}ku<3$L7i_v<(*>I@*mS|B3pQP_>4Ht4@&~|l0jBHP=Z8?eJzmrifVu$G1)wefbpfagKwSXp0#KJm* +=+)#E&z1_rVB7#*Uponb-Q2W2S8ny6sr7*<_Hm#x}ekrr7kFSL8%K$T~O+RQWtc(t~;Km?zN!Q1*I-1 +bwQ~MKwXy;I*=90jMw7^aY!~VAB_D`hrPMVAlnhzMi+m^aY8&Ako+J);rX_UJ&UE7<~bwFJSZqjJ|-;7clw)Mq +j|_3kZDyp)Vlx1%$qU&=(N;dTx%0O6`6ZEf*~pEf+0=mO;y)r53FCT+lptVECUj3z`w**X@^3_j-Y)F +R=6lmcGE!7g+iNOJ88=3oLzsr7y7b1(v?R(bv+^cv|k8kv^RnQz|d=U&q +?IxVBqGCD1z(=s|Oqth}vEu+&iIxV5o5;`rR(-Jx@q0(JE^l#ior#*C9L8ldTT0y53b +Xq~D)pJ@sr`2;>J!d!*fBBJKt&y4MyS=B+Tcgu=@#*Pc_^oUOomS9k1)WyUY4x1p-Y{At)9N{`p3~|% +-5F1oJ)getrTuf-Kd1e3+CQiLbF@C+N%LRYL#I7-+C!&3box4 +w_Rwh$o%Yaa|D5*EY5$z|&(U^1{gH-8`fl&vc}ZGEr)6|nMyF+TT1Ka3bXrEIWpr9brzLb+LZ>BkT0* +BKbXr13>+_v2|Hkc<(=s|Oqth}v0x`lr^y&>!8|k!>PMheoiB6m7w24le=xFDiPLY4(Hb3kX)pLckkx +m=ww2@BVUmU)owdW6MH=WkfX&s%`(GibBW29Z@(<$~@bS~_i{(4+5YuyB`}DRJ|gr8d!N6CLHdy-%OFW~z;J+DNC3 +blOO#jda>br;T*lNT(%qT0*BKbXr2EC3M<9$NTxSPK^K39y;xz(;hnQq0=5Z?V-~iI&2ExQ?s;$PD|* +tgicH7w0}W+{URrblO9wJ#^Ybr#*DqL#I7-+CQiLbJ{PRr=DgicH7w1iGe=(L1ROXzsN53dvB-?*KQT1Ka3bXq~D6?9rbrxkR}0h +^mv&uQzNw$5P_+Mc$?e5>#MJq~~8C20?x_Rwh$o%YaS3$UKyre$Bk&hLACdtS1e1w8y{zqt6~=igrR8^qaI +sE=<8>a?3qyXmx>PCMzelTJJ7oPB-kO!zl$gVk<2?WS}1xJPeW3+l9+PP^%}n@+pww3|-5>9AR1Pgc` +nI^XB3I|=@c+jO;{PP^%}n@+pw(}p)KsMCTvEvVCiIxVQvf;ugz(_%U;rgQeZy7S-PxSgz8P^SfT*aM +od9Uc)Lf<~+@b=p#=Ep^&br!933x3`nj_xb8heShONV(paD@+N&R5vFS99WvegWS;`=18eYk20Np)s! +prwe4nrGT=zF_znVTg#f@02>a?m(tLn6>POIv)s!prww5m?4>aZ0uzeMe;^Yzu8=KjWQ#M)Pa?%U*H?Fj`$JH}o9kS=o~)DG-?&Xu8|<{ +XPMhnrxlWtww7E{3>$JH}o9nc>PMhnrxlWtww7Jf=>0Kwczi}I)HrQ!%oi^8LbDcKVX>*-6*J*Q|HrH +u$oi^8LX`PnVX=$D7dwuKYUeoeAEv?hiIxVf!(mL&{)4n?GtJA(Z?W@ziI_;~|zB=uz)4n=iU)@>kpI +@HImy2G#`DtmLmey%$otD;VX`PnVX=$C7)@f;-mey%$oohdT)(PxiT3)B6by`}VzO&E07pE6jFYaEDb +N=q_#otleT&K--+Fa+`bg9$U-?&|GAFe)Jbc`mcrFB|br=@jTTBm(=+E=H2b=p^_eRbMb=j*FGPyLPC +{Isu5`|9xd>Tm-aqL$WaX`PnVX=$C7)@fgz_SI=$o%YrF`s&V3|4!?Rw6so3>$J2^OY5|>PD|^wv`$O +ww6so3>$J2^OY5|>PW$S7eRU_MzuVg+wWUs5>a?X!Tk5o>PFw1a?X!Tk7ytAe=Gx#D; +NuUeZ^Dw5m?4>fAdG_39579iy3|uMW>vgLN}d=c4x2XPCM+hzRttHHeIc+)A~B!_knaK` +Wv^wYK@)N*lB&8*4Jr$oz~ZBeVx|VX?>m6*J*v7*4Jr$oz~a+z7M4H&)>M6m|A0}&2`#bch`>oU$5R^ +wZ2a4>$JW;;RZHc?Xc4hJMFOZeCJX9+-urpr(Jg1Wv5+s+F^%R{C3!Bhn;rVX@{M5*lC9y_K^w?K~wd +8Nq*;_zj2$c7TRf{op#x2hn;rVX@{M5*lCBIcGzi$op#u1hn;rVX@{NXdwuKYUehi+?XuG@JMFU54m< +6zPs_Zt$WDvww8&12?6k;Ei|n++PV4J@-v`nu=WpD`iErl*&tT)!`Z}$z)A~BCuhaTEt*_JiI&H4g<~ +nVz!>ssyA4unze`$lAHrQ!%oi^8LbDcKVX>*-6*J*Q|mey%$otD;VX`PnVX=$BzJ+^bq-?$A?OY5|>P +D|^wv`$Oww6so3>$J2^OY5|>PD|^wv`$Oww6xCmJq?{%{>E*7T3V;2by`}drFB|br=@jTTBoIT+E=H2 +b=p^_eRbMbr+sz4zPdBZ-?)uV`|7l>PW$S#uTJ~ww69M4>a?#;`|7l>PW$S#uTJ~w6CRuIyt$J2^OY5|>PD|^wv`$Oww6so3>$H$fYt4K;VkeNlahsYpRH4$KQs8Yn?_>KO^c)V@mp0 +yX^3I5}|DMvjDF|n_-{-44ZTt(TW}L2YBEst%FJrtm@yfx}&)ms8$&|;e#P2)5*5TD`ovhQw-?+^W(d +}b&+FYkUko~`gC|g7JSe=GiWT!=T+F_?1cG_Vl-|JgH_nLOuX_uXL*=d)Z*4Jr$oz~ZBeVx|VX?>m6* +J*v7*4Jr$oz~aMeh*RSiNA51B);rpZ(HNk`Z}$z)A~BCuhaTEt*_JiI&4cuOVbWJ?XZ*Y^{tAHr-r|A`GE$jg?3tKr-k-8`**$NO;_9Ow9QW +2?6l2Jc+9!cO;x_vw|?$5ZMD-@J8iYoRy%FA(;_=9veP0vEwa-hJ1w%)B71&qvU@pPipzaX?q^^7r^D +Y}T(bXp_j&lW+3qD{umL#R&HdVH_tIQ)-Ql{!b%*N?*WEQmohf=8F-G$hcD`=Uec0mc_xmmxO^hZ+6Q +haI*we0McQ3gm?3DU#tI&C)M=@it3Ej`Tn>%BeG0Yf;F%DxK#yA}RaNWao57#|hxBC%(U)bImq=z{Sb +TQDyKoF9Q+OA*e%8hoH7P?Fh0J>R +$y;zkft_J;ip+5A4;-3h0MA)`Y^hm7vNi$g|-jLz=nYsMg(Y!>+2-S>uU4%r;C*^=EoAK);5CrPJG^9 +jEcLuBXd2EhzTWasR^G9-0ZC!My_{WF7;*CDU$S^1mqjb%TO+duKy2Y!_Be!HR)-XXkm?Y}Y*;bjlK? +1MmphXl`VO-XXw%m2rJG70r4BzQ>hkl-P~LxS1F^fx5TG@B_C(MfQ +pxRCYc_Gpt8UFPt39+qavfbeX7W)m|aCSMK(n?MK(n?MK-tdXX0dL`PaP*`+)3^GbE7}krk2EhGL(6A +}b;*CR@F`M?Kdisv@d-_qplkg8L`NAhIH|BC=w>6=@Y|6=@Y|Ee!OM>ylD4#hQScfSPjwCX#>s)8X$f +F4-THjGBy^jGBy^a{-f0lTDLNlTDLNlTDLNb1uNl(c_R&lTnjVlTnjVlTnjV6E-#g{h7zvWYc8RWYc8 +RWYgc1^E3k{quz~9$*9Sw$*9Sw$!HbfWXB|+CZHyuCZHyuCZPMR<4hSn3_&$PH9<8&H9;*YcwaERUjo +c%MAp~-H8+Qa$nX9yL*4s((~lVUPYg+J*^umKa%*yHa%*yHa%*yHa%<*P6VMvN$v$qR)XyeOoDG_^nz +Wj7#EyC*H9kz147Lv9bbJ>>Q>R~+e2>IkM{7i9>U9>+`mJ3&+OknTrvO?>mju4KlwZQo*T{vD-tKW@i7TL+W%)D +63lL;ze9ox6DOqd5V^zC!4`49!vk@4Fz>6UI2Sx5_>ka3g4q)6cS!Kzte{G9vOh?I4+;M6DyIhT{xqX +7&z@_4XUv)4A;yOoA7acNj=#fvdzfzz;XQ=+5Z=Q)d&uo!o;~FCkk>>R~+e2;-xjp +3eklRCU_r!D08V?iezS{1~>LIG%ef!P@%(>tpvWLhXB72DJA+m?a9wK{)>>;v;iS>}uLrM=5>mi_rfS +&B@jX4=S1oa}Q7eT!U>P1j5f_l*%@&sO_^TdVV*7LuM++BPB2&wDGa6~V_C68Ri=bZ2vljvV9wGvI5zvc(UIer#!cjOKya?(=P%nad5!8#IUIg_ +bs24%Km{`js=G&?_LKjiJi0VaDuV>HG4rhZ^6YuZUMQ$&0dy(6V++O7NdiG}+h}>S}_S#2d4@O=u@_N +1ddviD)yvXfEZZC3sk=u*hUgY*7w->p+$n8aLFLHY^v0mi$Ca*Vny?>ju!|C8nZf|nSX5GJ=$lgTuCb +IW$x0z=Q(t2}3aFf!Tl-{KDW=_2cC>tC9C%>~j4ne&M>P=8@f_f9wo1oqV^(Ls*m9xLjHz~b$uX|E@l +hXB-v$NXaZ15(sH<7)G>`i2EB6}0rn+V=S_9n77k-a$~xS39G0(ukBn}FVD?@d2|-9Iq~LA?p;O;FjU +{&y49o1n5@AbS|5Q#KO+m0t8cH$?R&s`qy;aB(_#6WN={vRCPk4M+F=_|3$6lh&KGvT6J8W@5dWSZ@M +)6VRK0-URgi&IK;c25*9T6I8Y+&psZc^?vvN8EBsl(t0zy-lX&Z8pN$X +8o`KI=rvTq`L^RPTbmi@1P4^!+zRI4*5XaARv)O`1aQ^AMuK7{unybs}h2rqk5|4KI9HJtxtoZ0`sxM +Tnl{4m8nB=^zg?BZ1LA;D~}{Ci07LxS1(`1g?DhZBN_cMfO&nt@30LxLaX*@w_Rg!bWk2KdG6VF>R-c +pt+15Z;IIKBVg5$$Ity**mpIBfJmceVDEuLi-Tf=h`{#=4|jGybs}h2=7C9+5PtSklTmcKFqEUk$va| +_ApGb4|#pa>qB0j?_A*KY_QUE+U}n04Z8P|Aqnq8cpt*c9<#rP@IHi>O=W)%v+F}>A42;+&<*?A-C+$`g@pNAM*N;S2mvhJ^AhpXM+#3EPEOM9wPe^SvEBNy+rmUvM; +mi%k26RP`23pu_5m7C7>?>eF^CMoeSKY558pdC8IAHeaYxcMqe`elF^sh^(C7x*<|DJ9~+PVUb6X;&6 +jNMW~KZ}^*F@yC7v(we7*aDGY0W|nNwe4`4Y>QSiZ#aC6+I-e2L{tEO+x#eusJ-;`x%Bmw3LU;U%6g@ +qC$6Ut;+Z%a>Tb#PTJUFR^@ywFN#@Io|H~xGM#jIF9KPi6C5JCLe97TU +4qtM(o15}$)8mlGn$p=*&X-WWyyU-x@g;nKjWK#1p7pIb9-^%P$Bw{;1z+;{Hbb^qGGU;whYZ_M(&mwGuR+_y-3D!!+lA*1_(ysvZnTC%SPJ5 +leP7P7fBRiCM|Zz8?}fAi8sKVxs{yXsyK;HBytwSXMECyS!{y5*0}OvZ3@{8Z`|hKkcJH4UXc(wL9rTJl>wC!tjhZ}LY?l*t-!|?qRV;s +iVxB7c!20Hxz#X$WKKGB@tcgbiMx8!1!i%~9a$=9p)qwy!-k22am?l(8?F7 +$b}k#t37CF~adlDQY#S)u2{`TJ;g%Kv)A|&5%~CYOt!oss^h +XtZJ~Tsa5ro>k`n}E~<&|ariwMGCBkgoEmUyz^MVJ2AmpjYQU*koZ25Do8Z)dQ#1E>cY0ztbMH?v5E% +uh2AmpjYQU)hrv{uFaB9G*0jCC>8gOcc_e)ztG}}E4867f;Pz^#g2-Pg}?cE@#Fx5~94=)S@Q_T=igl +Z6~nSA%=B?AO?2r5D~2-Q@m%v-uas0N`Lglfc`3QkRN>g=%)szIn`SDX;+e~nmgk%%lpH3-!pRD)0rL +Ny50AXI};4MH^t)gV-ZPz^#g(%zeXg1>)a4AP2F4MH^t)gV-ZPz^#gVmbw<2AmpjYQU)hrv{uF@r_!< +xW^%=;M9Oq15OP%HQ>~MQv*&7I5patbpL_@NGU=!2-S#<(@Aj;Lt4etti2v-MW_a$8iZ;PszIm*p&Ep +05UN3_2B8{+YP9ob1Ki^fR7h$dsez;hk{WFa2r48skkmj@14#`eHIURmQX^uioj;r19*1~BQlpIw@r0 +xXk{U>AAgO_*29g>`Y9OhBqy~~2lSuFU+1UQ;pDzCH=JMh4<&rT7BP2DD)Id^Gk~00p;8KH24K6ioce +@{7C#pRP@dT#^oEmUyz^MVJ2AmpjYQU)hrv{uFaB9G*0jCC>n%(}EsP;I-6PFrXYH+E+r3RN8Txv`#A +*q3+29g>`YFOH`XFs^qd@j|b_Aq1=ml|AZaH+wi#>CUikZ9DPQG-T}cT{3&VhKPE05$&R&#orupBRI9 +0#O4*4G=Xz)BsTfL=6x%CYBh~nC(uPvG<4s)X#TsULrtH(WpVA28|jtYS5@bqXvx{G-}YOL8AtZ8WT_ +eY5=J5H-Cz=LJVqZP-ng$WgyZDL=6x%K-2(H14IoFH9*uHQVKu~05xYeYv!b|5Op}cpEG;OK+K;&)Bs +TfL=6x%K-2(H14PXspof5BPjkNc)0`AyP=i4Y1~nMe9D)iz4g56l)4)#yKg}Vau+zX!13L}uH0PT?yE +37FVhn2@0O +#?PfvFT)gkbqX4&h8UH9(xqh3O^0}GzT`_fr%^zH5k-jP=i4Y1~tgW00%=^JrtR9w##n_dl-Vs+sE0H +bqs1Ss5!9d-V4$SL=6x%K-2(Ha|kE^H2~CHzr8nyvqB(hfT#hY<|3#V)L>A9K@A2q7t<;HG#A-~od$L +q*l8}ZdCfjIhtopjX^^Kuo(6du30@CFP~oS6p9X#!_-W +v$fu9C`8u)48r@08|ML@x(0huDw^}?z +;EYpo=0-&*aXY$iYtoKg~sCL8k$o26UQ>>GUF?IMd)vgEI}zG&s{-&v$P)EySA!ZyLO5@TS3=25%a?X +)Y#FoM~{T!I=hUnmW^I{c!kT)Lh%;H&{IiLB00geE-g91QmH2bYqaGL7wI&por5{oV;(yV5fnd=3dut +uKx8;FMr2C{q{Q=kinn^gBlEKFsQ+x27?+5YHp&6Jq`9W*wftl?hPk}7}Q`;gFy`jH8+ukp9X#!_-Wv +$xtUH8r$L+saT>&F5U07l&&|bIA@VfH(;!cSJPqJ;xvfUAWnlg4dOKSwMn};D@2 +~=Cas{;fKGFhR=jEOrnyNg&NMjF;7oIq&3hkhvI#NG{p@So#aSWLG*Ht(O;c(**((rKylHNNx^GJMJn +bf+5Ys?R12GN6H21r&Z8s-{P}4w712qlQH20>5N%ZC=oFzc-#)WL+OoKDcO*SE>ftY3&0g;%0{nPMw; +?i6mE-x-`E*~ymE*XPK6j+*vL}E&VDGjDH&+Mzg%~>I~G_@t~6az5LLp*_{0hR_>8enOFr2&=(Sel1e +VoLMyNt1g|qi#+L0j2?%24EV1X&y2PEDf+Uz|sIq!(t&m6fx-1pi6@;4Z1YDVu-l(Fa#B48kA{Jra_t +JA*gKDKvOx--eKlch-o0EftUtj8i;9j0TDszVMr^=G$_-cOoKAbLs}owiYX1IG|wKBlwwMQDGjDHn9} +TmA~MqB5L9ewu%&qjDyB4;(qKx1DGjDHn9^WMgDDNBG!LuP_VC|%$HPhCvyU*7D8MuT(>w&VuynGwm$ +afwgDwraH0aWxOM@;Ax-`4oh;aPtpC111<&rU&M0pUPrg@1h#554oKuiNM4a77M(?CoEG0m&*-f&I`H +4W4>P}4w712qlQG%sm|m-u;a9u)1VGrvaS?bQ;iUK&Jtn26P(GX~J|0HVxP`VAFt212zrVG`n*IPw~J0i7}>U={zFH(; +!cSJWU8H=rmzE1)BzJ8n9`=rU9D1?%$GY!r(`T84 +{mki!CeBal1EHVl@4d^u4A+rCO8QX+J^b~}KsPtyW`LUkZ +U(p+fG;!PN$g>626`Ci;l@0S@i4~27!PASjPWqW9_`_}FV}s!?#p#wuFIDj@Fey)FJrun@iNBC7%yXl +F~S&Oj4(zxez$@Kl_giL?SUIVM?kg9r!`OlE&Y?>4~8LCIL(Wn8dOuVM@Z3geeJA5~d_fNtl +u_C1Fa!l!Pg1&UbHmW+-e)*pjd%vHD4vk}xGz~ +pxyc7lp730)Gpq~Xi!NdUy8*#?TABdWusWlF%igOG1~VJ^$=;@$c} +mC8$YIlb|L+O@f-lIw(O*f|vv`iSIn)6;C*ma3WZN_dm-CgDxOo5YGJ;Y`Argfj +_e;yadm$#u!Awu|a>(8Dl97eG@j3V9OpB;-lRlaMDNPhxG95GNr{LY#y+32~CPixP`Wgggm(lJ*JOM{ +ysDy{~&yNNeTkZ1Um_K((W?N!`{OXS@=oiC!M{Gd(X%%1|;3t`R7IqTsB-lx?lXi=09@QR)w8Bq +B*35XI9B_K*Bt?-jr1SQx>u#; +dX!A|mbF2E`i!B2vp3rt`tTGYuB;-lRlaMDNPePuAJg +M?@I8_$>B-THP^-n^agg6Ot((Z4~W7xwGROCs>laMDNPePuAJPCOc@+4M032_qQB*aOGlMpBE_p$Nt^ +*GF}$diyKAx}b{ggmM8WZHJYPlBJsswcrtf}I3A33k%?&IJx}T1R?^p{ +K-laAx}b{gggm(67nSENyw9sCm~N_nUioP;Y`Argfj_e(zRW_SZgA@NqCd+CgDxOn}jzBZ&JO<`~DJa +64)fLNnn$TP0k+on?G4HT@tz^bV=xv&?Vj9dnuNi2xSt=B$P=glTaqH!b#|o&?TWuLYIUt30)GpBy> +sWlJ2!ovED=|lTaq1OhTE2GKqCfLYIUt30)GpBy>sWlF%hpm(Kn+mza7O)|&`w64WH9Nl=rZCP7VNag +!h>K}>>}1ThI>62v5kNf49ndw)k+Zz8BkP?Ml0K}~|11T~4(OoEsMF$rQ4tC@r@30)GpBy>slewIWmI +1$Pulu0O)P$r>FVj+{zC80|~mxL|}T@tz^bV)2=60oFuKT9H(oCshNz@!4x$#;bg#6l*aOG1}~E(u){ +x+HW-=#tPSp-X!9vm|20iBKk?OhTE2G6`i8E0=^WiIqzNmIN#bSQ4-#U`fD|fF%`{I1cBA0FwYF0Zd} +ik}xGD7t; +dvvDG5^&rX);Bn36ChzCPgWYwfe&5h0eF2w)PxBo-}+MN7hzgeeJA5~d_fNi0?poFq6&aFXC8!AW}eJ +0iq_6TwP?mBgYY!AXLX1Sbin(Y7F4Rv<}2l7u7)NfMGIBuVdnmRT$~5uzj(EeS~yk|ZQaNRlc^rwxSZ +r-dmAQxc{mOi7rMFeSbFMFe8KiCDfQmM@9rO9GJuA_+tih$Ik6Ad)~Nfk*<81R@DU5{RVtd;iXY6R~_ +rAd)~Nfk*<81R@DU5{M)aNg$FyBo&d)_AE$}kR-j|`*#+cu+LR58E798(uyPrNfMGIBuPk;kR%~VLXw +0e2}u%?q<7cSi4`Y8l*IBSAxUESl0YPZNGc+oJs(7pgd_<`5|Sh&Nl22AB)#AK$$}FhN@DqvkR%~VLX +w0e2}u%?BqT{ll8_`JNkWo@Bne4U_B(dOf)j<6pWFb}FbPf)YnX&22}u%?BqT{ll8_`JNkWo@Bne4Uz +WI{{Cqk6O@+BcjLXw0e2}u%?BqT{ll8_`JNkWo@Bne3plB9g|Cksx5D2bIze937q8H0EtNn(weKqP@k +0+9qF2}BZzBoJvQx9ilKlJT&n`JRydCoIyS%u(xqP^Mxn!VWpkbh4pk~u>lHnx7NrsdB+jaF~#ff1h!%AlPlHnx7Nr +saQCmBvMoMbr3-N`{rpQYFJ +lhLa2@8BQ{sWH`xilHnx7NrsaQCmBxi%$I|n8X8tItYlUx8BTIJ$^5drrgZo%GO%P|$-t6Xr({gYn36 +Fi&wejSZ)1OV_8%Bc+$`dWDH&5TrsQ3;6i$^GhJd0=Mwg5(xw>@nJz}glG1O$J$xxG_CPPhzn#}SgLr +jL43^5sEGQ?zv$q +C)t_kJ+D!bygc3?~^*vi7qiX0?gSO4q)yVoPQO@@;UCmBvMoMi7vL>5jmoMbr3 +aFSWTWF*Pn&ytwsCPtLZLM9_gMv{yq8A);_>0EnLNGqIVILWMLGLmE@$w-pD>*~#N6C+AyHItDfBT23 +#UB7)4NGqIVILUC5;UvRJY@RagGSanD3~+t-re}nPl?*GH)l7zy3?~^*GMr>qGZ{%Tl4K;wNRp8xBS} +V*y!*#4BpFFEl4K;wNRp8x?{@P1Z0`;kWg(N1BqK>il8hu7Ni +vdTB*{pUkt8EYMv{yq8AkqjakL^6nE5Xm5t&o_Uv;KVFnauMlVdn1V_lH^L#(cVjDQaH&hWHORu +B*{pUkt8EYKIgkPoDw2R`)z^yMQi&lU*8GxPGd-tkt8EYMv{yq8A);_>Dp6%ILW&=J^$RpkWpC4tY$K +tWL7g7NivdTB*{pUktA1=&b7}F*@Tk}C;2?zz2SrqRx+$))-V}PGMr@AFd0cQl4K;wNRp8xBS}V*j3k +-0Oa9hUn)N1T4U<76gGdIE3?dmsGKgdl$<)rK*fOPod4FZzT6y0!?fKts4aDF5>*d4Wy<9Q|83mCHA{ +j(7h-47SAd*2OgGdIE3?dms@@{R<-}N|T6htzJWDv<9l0hVcNCuG%A{j(7h-47SAd*2OgGk=3?)keOh +h&0C29XRR8ALLOWDv<9l0hVcNCuG%BAFFSY`-v! +89Fj_Wa!AON%FnlC1%#07&1eltjJiAu_9wd +#){0UBV$Cyh>Q{W-OqfO)hEV^j1`$xM@EQ@5E&sdLS%%<2$5NJWMs(5kdYxHLq>-D?q@#C>JuYGMu?0 +M86h%4WQ52Fkr5&zL}r%^Eg^UXs7c +wi1j0YJHG9F|+$as+PAmc&KcJ5~ViE$z0LdJ!R3mF$OE@WKDtS~Ywj0^=C3NjRAD9BKdp&)0?(kwtRB +xFd)kdPrELqdjx%;F+LL56}11sMu56l5sKP>`V@XFqdnR-hOXG9+Y3$dHgBAwxoDagm`QLqUdu3hZsS|M?&PZ=1QY-O00;m!mS#!*fEffE0{{S&1^@ +sv0001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJftDHE?ooVr6nJaCwzfO>f&c5W +V|X4C;#mxZ1dj0^1FGkQF;M*0K%BMv;?2OCy^oMH(cPK>hW7^jETt1MKQ#4(C12do!MH_xeY}(Zgg$( +@8R#|G)D{EAi@?QpbvV-E)q)56$eys#`hm$YdQjBlS3HgN4*Jhk)GOKxcJ<;!27xSAeOtQ2J +-*HOlf?Gu+rC5h4A%1r~AJ$LgrB1EaMKWHJ<*2TSpYnh1#8D79PLBQ?O +vQ3heGmGAv89iKe&5GEO8&+eq!qop-<7^{Mw1JPv~_|_)tH(xeve_6y1_SH|!Z1UA5pvX-QHaXm{`)K +R^hf&loG(Fg1>=M)kpfT>3s)ew(kB6we;%dz@wQZ25SHTsVze^zXpe!WB&f1N`xb?RART4NHz4BS +WI9&#XKKHL^<=>;$Y@AlP?xmpsWp?EZGaG+)?@?+UroDDrqO +47;P?CVxmakFS2j{R}YoZ+k;*}UJSh>S&=rrPtR6jb})T!x(k+<{`N8SMbxLy10)IkL!kvZ;A2^VdaR +7GeHt3)LuwiWd;4iHxcxZz^L9YA$`N_*qtWdCKQ5JSr&C!|Q&ew?ov@Dm-kJ^cqkrK~ls3xCVe2`;ZO +(pixIJO8U8LSRk5Q{dv6Gt5u;g%)hnw_xbB2KCGIwF7Pk^D^e!hPdkFkwfhfQ>;&bj(^a-OExRjSkJ6 +iPUEh#iaTU9TCN0*eA;QPFxWv2WJvo?}&=;^DgvjQ*W|$quJzU7w_;^!1AB-m6mIAm8Zy3E#iIYenxj +0*kHa5xmISvR|K?xYnZP-{o2Mjn(uaJn*6O3s6e~1QY-O00;m!mS#zLvR7F%1ONcY2><{y0001RX>c! +Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJow7a%5$6Wn*+MaCwzh+m72d5PjEIOdSNYTU& +bp@*+SFMYm}J1VNB)9)it6OG_i0Scw!!%8s$vfA0(_`O>|h^@A;OhKDm}W)A)4m$Tm4v!&8!s5j8<{M +zVbGMOZQmsWKiwrf?c!OMGeU^IfU&>D+Ss|KNye(gZ&3M_WUdUgT7MrENwkEO>dL0y_k>6J^8KYz-$Y +cR`_1nBb?%C)r75u9l;VDf_@49jo9Z!~4FRk|`;x45``cS$dP4W-ews^|=a^Yq=`eGiaHoG;Sz +B>7l_He(W$Q)kVF?A08UA5vD7lhR%9p|++4=P8vm2?Ql!r6}s&_ZEu+RLdNITsqVA9*g)sCs?IDx#`j +?qvz0TMU-ICD34Y)M9jF;t~zNQj_+>g;vve6;HE=8oIH>>T8d(W*3kh)abi#DIJU?pGED^>c6=KRSA! +u*k_u}ooeQ;REK^S#rP0kn%NBDH2oSR@FwHFR?^h%SG)SU{Qe6!IOMav}Fs)0uq|%P90H!AAP;EMt5g +O$@uSNiu#s42w-13nL=939}x%23bVL71;KGQdwhiIrrng&Cmc +s1Z0;l@1_+oxq?91c4zy1wxQ-KX&}tg3o2+=wxEaeKhD +u@vIr{4s-vi^nI8|8V&zQVOb-e#+U*pMjh2;r`cW1Uj51ZeuFgID8>S8o;>kB&ylaimg<7N@KCfKa=< +jZ6|~XzaL0=8fu5qv@L5;pqZTe7PXJEL~TOtvgV$ms!2#$U{!fFt<@vH +@(l|H436omtw!`&SXZ_4O57uoII9ViFABOIljM_C;=YmDJ&1WvMi1AkGkKc8c82$Er`Pe%Dje;@2$f@ +Qi7^JuX1$@PDg^iw^DAI~?(UgjrE4gdhyC10jVgVy4wbgKpjI)>2 +F2_s^Hf$kl+<`Nb3ntlpSYu|V-}C*sHvld2*MA?;KD4 +I-OV{>VGy6yX1;|diP04Mr*`@G>s_tL{zde)Q%y&RLmE_&WssOG3Vx%17<{JBme+80001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJow7a%5?9baH88 +b#!TOZZ2?n?O1JZ8c7oV&abG8bvn4k7#!y|cGi&qV~51X7B7l?s|XD<4RkV0lb$Ao{q_4)4=*#!*qCI +c^+|^;!}L^FRaZUr)&~dKAF4I3nk~9+)*G!(gKF2e^$+v_?LqEDVK0;0x-^7R5$PETKhMJ9QPs=iNcrVXhrLZQD2FFHwG1xCxk49Coeg)^)W-8lLS-AR9>< +%A9i8X7W+?iOaOg5~*PDqjw?qZe$op%#KdH8gW5_J$T}My?Z(7M=_v_ArDYC-9Dx#{P-&s@0=w5kgbC5`oY-&E0I^OBb83r7MC^kQ36B*TV6}QkSeqXQ>EXDzLZKeM3UxJ%|2mK=)&U*{de`oo)3-dKRr3-aL&z1msIG{NSi9?8J69mDqc0fso}9I&E+pjjw}GrtH9prwz^?z` +Jwm#VFM`dDqZtF7++8_>eicnkkUoaAH*2zrE5X(uoXC=LcUjduMVc2sN4>t^?!wZCk3Ta8YKE^pgZrM +qgo+pPDlt8KdLweM~_jS^8uh?R-im{~?%n|KJ869r3p!Z^|oqod!$y&)9zJsLaT1l;Tj2}F^D5ScFa@ +}aMSkv%WAYz+E_DdF!TQoyN*Af7Lc^ptRqQPv +S1RSh%FA+vsMo>DLmz6iE}ocF4syAnRud|TnQP_qfu +R{BNU}qX#}q%KN)!y?WihXm+~oX06w4-nRPfD!vLE$zSxg$ +Z3Gu76SOR{Py|?MCO_?eztnQ>A=-lI!%^jsAV3gXePT^fY>I-P*@;C3n+oHE()1>CG>5xt!}eA<7iab +g{~Bh_))K+ai?VnLUgrhScv%6rFxQ9}0h1I9neQNy?c{C1Tt-1K$SnNEogcUuPn4kt^6pWKZWp%JMlM +5vfUx(UmaPqWMB$y~@%`{mGWip?gaOVwq#+DGIoXP}VCtd22}HpkaU(t{a9l$K-UV`HXgM@RGdyfleAl9JM+qp4 +P(g=@ki85sYl7f3Eij?d>0g}D$0FS$aE&BTv!<1{{;X)b`vOkPSEXE8-r;>W$*=FFODON|!79-0ZZpzF_UIUhS=j +MqS*a!wpC1%eCSdQO*)AEp7K%+i(|8x{b(Vu9(n=m0{3vru#JQ+NrS2nuGCLDU1r$me6lRdfsOT<1_1 +xitt-v5vR(U?8v6*cf>zglBDBB&Rmx|4ei(f~3uvj1jxiBC4)m0yPgHHW-<4-0Y~cD>ig~PRD17{B%H +bgh${nfLn9{h!S)q$A^Q30q!>vfNSoUycl?vPM2YVpIU~eJt$(lZx`}>oJ~**xaKT#+hHZHceMHzHcC +>bz4;3=;numTkr`cPrh`}-p@G9`2G +$qf;S0_&Xpfv^m_cJW)stTEFSBahY)Gd3$w?24qxpo;RwYx~QhXprAh0~bIXdi^WzwGbjROnWD0Ota$ +Sy=l(=BB#OIYr4VgEQ!$=TutOyyIm98o@>W_Fn3RY*Ja-@DRjp|A}#hS{n@r(v=@ug=Bn9wOg +p3k#S6}xoKWeRx{vqq&{{wIYqEjCi)286^I+LY;wK+Q(uK4T_b$eV`41x-0T?jn8h+ygOd1Yx}4jlAY +*XCBMVr5Kk>9;c&nwaMuy3__zUA!|%Hy>b?{yd-B_)@fV+w13`GW)qYQrzqWQa%kd!AK8NTfXK@pnw3 +~0Uk4VCA!;??b2acd%Gk@nC>|U<+`$5<&nBvBTeNH@XIV6ggu*PiHSk#o>ling?LzQQ%|n{Zd?TmOZN +<(`%ub^H2*;eOxz4Q%PmG)GaZ20vL}pzzdv?;u>h|&vwSk4*ec(e|OUVtp8@sGI>aj*|d&1hI@7XnS? +Ex)rz%ZE|c0aBiSL7_rj*_;W2u-4+AR0;?8X_*WQR+RT@^|-y4iE7?6baf;0BYVAty9UM4OCR{qLdz> +RRH1`eI<;`=*ZABxnl|Fpq+}^EWW>3Gq6haZKHm^9zSgP{=NLE5YNUjO0Lk~>nE9s{PYAlGan;9w6q2 +KWs7~~Q^CHgZVGw2PsjxGhxT&@b80l-0p`Tez8{z$o#KB0%pcl62j)Tfe-+HN^3%awEB|F+j_yL9Et) +fLdme*x>KCU~?-g~O_s!0;jk@%$`(r_uypP`_<{rPI-!tUG&#{^CheGc4GHy9vhEhhvgV +7q~PIzQprnQy=O=7*`*%OB_s9!66bkNSh@VgSAIWB(ge_||K6SZ)v=6@TG^1<;os0@pB+|L`DS^uFCj +g1gK}1#ZAm7;wqQp};J5B)H)e`UPJxkRd9NK9~|v@}Hv7E(`GhmrJ4PRfSR|FBW+wRcdz?GJ_th;{>s +I6;l=~jOnV4fkwXxo!i?#38K{9fo>4M-1=&mqek_LUY1H<3ZwWsqC^|I`H3t56Q+K`j0Z1@Z{Y@rq5& +ge7MqO}wNyM3E8uIzRBUzg6(VTqn>S*12eFL6Wdam>T&M7)gaIbJ-=w1Wt@OAbTT>)F%E!_+sJ411;= +}X_#;A!ZJfJ{D>CB>az+DO+a~Fk1U>ZVe)0-1d?N21Ag6PC_bVz*7Wn9NcDH4SEud;Qn +6dn+oS_YD66qKMDu>!d?wjCPgFICaxJYm}q(1#1M9TDyIt$hakw!lXT7*Ep@O`xW`uMbj?(`YHcjxo& +boqQoz9coBQUy~az744hJ)pD{6DB6+1TY!Q`(G)d+Z&BX%V$e}I9g5zivbolg6v^Lx7k@U$RH)d +Pd+mopbjy;k#;+=62(X6MGGc{WrrUCRtQ)|rdDVM?P3m0XiR*>RtY3pBIDSgY0CfN8z6J}4Q5=~3gzk +p`FMmWt%VYQ<^(SF47`z|ZXVIr4Xoz4lJ_%~@@`uAyp9qb=M+`}8nH&~)_U@6)p$YV#0L#ZxEpnM#4R +Jvl|o$NZYvfy;TcY>VzR6elF}OYB1(l{y}q?Gqke-mE%i2?4r&sUj>m6G3 +xQ&E9-oLAzL;7Q?g4~2^-sa*hOAB84TA|+g}$iA50aYcT#^QOu0$|IeE63tvCAJI#cX#wj+hx%O94L1 +3zjv&zt7bj&tipkpH%usDei!3mqpAauChdG~(MZM3LjDyKS9F-tc)+gmuRqTBe(FNwTe=sPcFqLLfqR +QzE4OyVi7^0iQAv(J&S-s@iUwzaLEBr4|O9KQH0000805+CpN%$G)gIfat0B#2W05$*s0B~t=FJE?LZe(wAFLGsZb!B +sOb1!gVV{2h&WpgiMXkl_>WppoNXkl`5Wpr?IZ(?O~E^v9BRPS#ZIS~EMUolcX1azIWc@q9 +cGmQNr3|i7?T9ea(o4AA@e?bvWlN?Ye+C-<6ZS3> +TZU<~DYeXmmqt4r?bg`c0l+jfc5lxt3(q;F)eiA(Dq#cGwnD14r+U9ZH|=%@5NF*Z>MBL^;Ol74j_ni +Y`%3yodn?lt_0?VDBP>J@!hWZjR4Xet)FLqS=pYazRWh~0RzcmuGLt +ife+Khgs!U0l&}2E6Zl51Yc@jGR-B`qLOfHKmm`a_a-cXijyKzU6?MzILIn9>y*)$$RXfE?n;vnWZkzXV(0J$+x5Trn^8n^|y(s$f72F=)g(n?+P +u55k8a!pohvB+oYaxKDa(~5!=4$blR=XAMFm&GKS^SM}x`TJD1N@tyWkJO%xgy#wx?Kdo;||4hGP!)i +NaqFG*l)?BW=V3+@)~m3B62%^7_ulN?)>qN``TtY +DFE7^A^lo|<^j}a*0|XQR000O8HkM{dz}XNq-~#{v4haANI{*LxaA|NaUv_0~WN&gWa%FLKWpi|MFK} +UFYhh<)b1!3PVRB?;bT4CXWNB_^b97;JWo=<&XlZU`E^v93RojjlIS_s4D@x*FU_;m;(Mp>c8=JVZX4NVSoZ7pxVyPzhDox1qU&;e>Qt2}m#-gcbsl;{>i626;j}}o{;2(hUWqN2$~4|G?b3{#r!w2Xw8Mmv1kt+Ck$ +fN5-OZjUSr&oQkI8RE;Ugbi5R1FqV5sW4H+uB@|Yy)K&+9mR1rS#M>n@2u?o@$Qs{;~X4bDtaIQ2asWaFOw8swsqR>6Yh*nHH$H`9BfPh%~+M9hI& +1cjcF6e7>GHDKHi+jXEX?W4U97(2IB>{}8tkC`d;s6+QChgD2XtsL&-fR)rcYCv8XF8?sXhKaIHz%`R +d){wOXgr^cN7GK7Xv%z)IEZ;om^R{x(dLLHCW-`BWPA8uJyb@ovwD$ +o7WAHELfZHm?XAS@VESHk7bxfc)-d!@y+(gE5G3?>g%(Va-jxZUyUG|_qn2?#gbtd>y?xhc+`etRzik +lBr?9+ss5AWZn~zAjR7$K#sUBg8JsRag=fe8%)C=oR-gFy=B6sbr*e;EYOQlkzgbR;CEcF@*o(Ce@NX +>U8Y$bY-&~hoU+{(rWGtCz$HXbbwb!(MR~6d)hl|S^L((^Vm3q+`bag-U!>r=)H)rcsqQhS +~~H`4Z-)4NCB1=0;ocQQ>x~F{L%$yQA~6JQO-t>Q9d>s>3gO%hdsjE7(}`V#H3)o!XqTD^I3Q;#0%w2 +mXrY~)@#4HNE}RlDp&=wR+UAw(dMHx-vxu9f-6HNC +nb!XMDh;}12R&zqy#)nClmkI-k@DE7?k@fUmX<|8#uA(s8l>TB1XCmDJyqujF$5@Xh$uf$cDqD{|$vh +B~AF4KJfe~wmEt3`@BOaB2-O9KQH0000805+CpNg(^(IZ*-t0EGkq051Rl0B~t=FJE?LZe(wAFLGsZb +!BsOb1!gVV{2h&WpgiMXkl_>WppoNZ*6d4bS`jtl~YY`+CUJ!`&T@P3rG%yM7@;uV5mu~5tUvqGcwydZTfcbg)Kl +N6x&T9Y_4&GMjHpGv2Ie9UkLld-mkDN&i71EyQ3DQBR;*&Ov-|0e@ZD- +o6f(%?maAbBCx;$R)mm4g|TK3(OA|q<7_gO7-1}|hz$`XV{)7flA1+w;tn|DHzvk=TR(+elHnt&wxyS +EQyEL(6p9A92LGy2d5ec?L&2D<5h0~Xz)7Od`q9KKtEYo-OHI?`6U;j}6yYr=bla()N9i(563kaI0<42L +jb@ug5M#ZG*Q+EP0twNj#9cApEAnfJOQzguu4F+@$l9J#-*S5`3#_-- +@?HVIokItZ8F|8bvsp2wZ)*2T8g<4f8749|1(ELExT75zIOBVIM$G-SfkGY<~Fq0b+m_d({mpn*rVrM +EFz>&W`x+kp8CD!D+SdFEy9i!c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJo_R +b97;DbaO6nd6iVbZsITyz4H|#acL#W0;?W&(H>G7+Gru5B&gz4nPdQ~#zwYjmHqmC4$vM-rQJx8;_;g +|Gw<1Hw=X|*7e6E^O_EWZ<}uw(W~1Nq1-9L4Q?X^5S-Fu~C>oiHNjjREKT;_{3oT#SI_#8NVI6y_*mL +QPr4rC?>&%d7=_O$I{L0Gg*^*h4zd#Lq%HEY?&j{^y2Q5qCrO^&cyEnF3fSBgS9^<8D;klw!-7tPGC2 +Zi@*C@61bTzuBL9f>b#YK3RBBdw`SVtK2-<7-mi3rhD*cX~hwXt$XH-rv7c|-HsZ +;fsc`L@O@lnMLhecnc)lR%JE$(0qh4(hHgGdZ*NZ|HnTwK-5JG+C~sJJyF%o`kNx8H@a#spPs2p@Xh4 +Zy3w7-MO>K59xv?>@W&Fux5+$^TSHX63G);vUW_u(LTi7_Cv~XXe2*1LSqB^M*bnO#D1t9>_>zK-Tt} +SiLrxO=}P#}KkVLz#A`HNlY(9LoEfaVpuxwe6-nLjZs86-z=%oTaQrs16u_rKhBLoGl89(j` +4bSr(WCq)|PIgMu-MKq7HA{i|vQAYDcHl +O8j7w$5jH4bWCQu$ruH7IumQsR~fsoZJyB@A}xP*t=QuMDG0#=WXY;Ee3+|8h|oy=ewU%7>yul55h&c +j(PZoE{v|PyT}C!{H9@McM7pZ66?^UlcsZkv^7dP>+={wnKNu`2d|p$n6dK{oYOgd#_Kl$PxMKp*X$& +$KOx8)q1XYb=c4^>a|*Y-~3#pKCZcGH}P2XTbvp{Wqb~R%e}Dvh>5L*=nW$A?u^JEXIU{?6wk$D7Gp8 +F59scX+ty!DO9KQH0000805+CpNvj4X#!LeM0QLp|05kvq0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2 +h&WpgiMXkl_>WppoNa5*$NaB^>AWpXZXd6iV#ZreBzefL)k>K6xa)VR9~Y#Q`IR_xS>Z;)&hc`|5eWD +})GgQOCuU%y9|FKOZcTRus1IXrV_IPLc3L;b>W^p9BYhCtZnbH#Wtv&JkyG}__U?u_040GQ^+HuluA@SM@Q ++9STdO4u4}SK+Fyr%rT5z1!P=0dX-rpin7_>sUuIJGRf9HI+n0dn?zaH@4%hzQRH@5%wp|rP^3o&^3X +fCvRw8`K{51`XP;yYb$J3tCU-2awhjLAa+NUDJd12EN9X+@DRe2(Aj5Wkzbfh=2dMfb%t_k)}C$Qjv7 +8pmo#Pvru4v?EvlK9Yb8@8k7df*F$qVz+UB-rrG_<;I +h%+M>ltM;uT0&q|gm}%nU9{aIQ2XsrRs3Xpav7qR<<8Zoox +q#(9idA=0hXd`ye>o}~6n8qYBWFsHezXZ +nyZSVoWW{VPX^byPX5q7yymiWB_&_V3$dGQqY|tyU{l!nwxS@atTrjb(vdfyu~ewUSslt5wIb$`AJXT +uuyr4?jiMf5ECaR6C(>7YgsZCVNiBhMg@2UmMo-YZT;4EIxFgo<`_#{TO$#q4s0+n`DPUUh^xk=3xF1 +n&)g;``|6jck=#1pTB)9edkS~7HinUcoK2Les!3dl@c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJ*IMaB^>AWpX +ZXd6iaOZ|XP@edkw<)EAIw7J9YPZM%J-6k4_r5TUy2u2#q-6R>V#N49A%`|Ed{F9?KgnZ{|sla7mW*8Y!If3ueo3m^ksm+HN^5?9!1QNY7IWwoJIj132rzcAMgz$n +VNiG??h1x +cc2$VFt=C@bJVEbFvv3LOJNjWZH-h--MS$Qz=WxvFyql$@fa?FA~awm%ywoYMV>!N6Y-T|YG+jn6(VR +Ens*B97ItzAJ`pI&YHF&pmc21234#J4IkYX7^9|0;SmKY%4W7*McgOnG51 +ku1g0UeHoe&^HMD_vc_1*9M4zgA3&`o*-u;G3lLfAvZgE@A*aoSf$&8Jks+m~F76rY7h^nCqPp4LbeW +n3$kB8uLdUUjan`tGsi&skw_mYsb;BYVVh>FQ3{tCK2+@hQX=dy`-NUK +A4d}2R07WCuf*S+bRV_0;bM!8sxgB*%r~?Vs45F}4pO9bRMB4QnN~DH(L4(B1pa^qecHMGtl`PamDH) +FR%EF3#ds{6LbFxk4BHWn6d?~#_$MSJRy{#gw*0P+bA4UfG17Pj)#>c-4-td();6&F?cv>NRc$ +$~y~;#?C|sNds3 +A%&fxpZ$U3JZ3Yc>5=t1gBL!`*(5J2+5Es&nxicmI%4d26x9-F|ro-CE$jw@U0EchISi;DC9beHpqd& +7?jW`y5V!ZTC#5Q*|)}lQZ=?A6fb#ADNH5P6xe|I~z{>k_ElYzhuppodH4r!jkW`)aO#J-42I< +{{T=+0|XQR000O8HkM{d)=2%#$pruapB?}JE&u=kaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3 +PVRB?;bT4IdV{>gTaCz;RZExa65Xay1DMptUmq?gmo5zd#f^d+KBLo4_DfgyY>~*lt*mP}jqE)|pXZ! +$|3sA;6TL0K>vY^LQ5K27ZVi)gn;w2Mi3uKqcdrk +|L5eOjmKlms1Hvu@)$sFC)8IM +y55s==b!;*7(o=ka23r0KV3g=jpt64P%GLcM@b1`;6&dru}fG5OR$6wO4@FigvX7DK=}4gfkJ*B*sim +pp`~x*awzLas(G00;q~AF`ZB~!;ad7q;cAA|x&eldclQ#ci*} +m(S*j36z$oe2Y-z+I1PabYMET=sE(pB9q*vhKX{d}Wv0JcNsSU0lhn?Zx;~y9h7y1ovBbZ89hSFJjMT +~&H@VPg+xqp~IYw!r4Tcc5HFnPR0U)*W5;`t?!-1)+DF)*%52|rq4;uzqrGiu);(YosOdy_}XzT2A&I +^!{P??=#rVQVz$wIBMe5ey$j!~1ck1TdB|+hW>GZj;wr>|n@wfIDf+NVr~@Ed3FWH^c-z8)o8J;xSv& +#XAZFmdIjt(iwVz{}itmk)QW2^;Itl-)het3*yz4p`y6Xj +jD#BF|M&x?eLbhz^dRf!WvJUVt#*uw5=nOs{*+k9?1xE#QC|Ov<5gt@XCr9NY$B|H&kL)N#smNXw-pN +AY=F2aZ7sAhQUeJr>+#3LsEMxtZ>xD9BYmm)hZ8~v!#_4$*aXQZ##2Ng225|<@nZ%hqXA)=fT!pv_&s +B)4@LZL+D$iAktMXipxEjyZh^z5jow$0&Rq(f3G%_1;bqCKc|0Y|5xJI3~5!c|kCUH%kYZBMwIYFG@I +YFG@xhZi|o|_Uk#cX#-2mWTG=-&>vt!`S`(2S{3LF-awRB`#fI;r~ +16Q`D|p2?fObHOx<|*N1@Og-y3DaXb;xC-}s?=zxfaK{>uNL_w +U%!-ftB1@9o~t+S1<7*|Ofx+S1<7*|Ofx+S1<7*|Ofx+S1<7*|Ofx+S1<7*|Ofx+S1<7*|Ofx+S1<7* +|Ofx+BUs^QfNjgFVceHFjQQM +t3_vx^fy}lcVwd^P@jJ51!5nP{trL19J+rFoc*20_|-VR@r!$d-kl0&_Gf*!_IaFQP8*LbWR-VV3)@Y +Co&f3`EXY@27h%8Qua=h?2Bv%Njrz3JhPr-xXSr|aRr|MlKMJxcZP!2E|q?x<(G!(Y$Edbqu(M|?}S_ +I*tQlD2u22JC)ycSr)_gFi_E^2<6_0zQpM0`S)J#8=t)0DkbRDEtXfO9KQH0000805+CpNvwRlMGFN0 +0A3CN05kvq0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoPbz^F9aB^>AWpXZXd8Jl +uZ`w!@{?4x$H6Lnp)Ca99T@&RbLP$dk1o5IO>P2X=$FNs>7wxW-xWE2p{lbfF+Vr}gU|yb?d1iLjXJ_ +>XuKFJbV;By4{qd|1SHrvBXE%n{TPk**cM3?MX}%>Gh7Nyf7Mp1^bY~UM5;{gDP#tHSS2Z9H55}8YnxE0jRB|EgwBT#e-T8jx +eMJegsHXFFhz~(5&f)^o)kv$Rcxekbn~1f03)Wp!Gwov#UpqFl%WA5VUn1Q6nXtbO~_Y@sl>7rC`8aQ +Fi(`&1tc;Cj|oudbDhBx5eAs>|CEaSBkA)Xv7%V`RF2Kspo(9jkZ-(Qd|F-=fZs+n2MDAN=!1hX4WJNC +Ilf6@Cixjs;IX=5dt7wP@G^@MpovbL)NpH0b->d-nmGMtS@wE4nDqv3^2>r9vx;?&nii--0OO<4fTC8 +zbZTsj)VAeY-y@8}+z@2u@VcNyihjNr0{A?GmJife_N@6@Er)4Vw~!S{R}IG1QF`zcz_hJ-spGQrE(I +I#UmHq|(5G|PM>mx4uD4yn+@O28{B;?1YYtG#1@=%>alU{~>>3mek@x`YsglWKMfyH~hflXO?t=(Jm@ +>4B#`^d8>7`+S~)+6~KS$dD==x%Ym+Lz@`qGMgDvR3)6U54j-b4K^C_RwaJYhaS*Ewj$swCZ-n5I +30512J*~Pw6QXMD0^C^s$KCa?*)hKOGqFrt15mauv>ry7&N;8_Z&Xw~AyoP+CZ0ONJn;g&slrs04)HJ +vbe>vDc;&s(H=dYmifQ+#;Bdpl3=xgTNkrcxpayl@2gjKpu$4wuCf%*N&BvYmu*|s8^N3wGrVp#|Ic+RzYXPrOOMMwozl}n8uM&=!QuTXRbDD +*=bC@p9QxLd#z}xY^@u$?MH;O=YP0blP)h>@6aWAK2mm&gW=SgKE|ITO005e^001%o003}la4%nWWo~ +3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMy=z_({)Z}#NIn%#oH5c@_z4o|MCAGfAgdN^ +7&65KmPoOKl;hffAsj9AOG}+|LyU=`0V%Ieedy$-@bqR^wWob`tZ${Uq62M@z?JkAHIG3{m1|N!`EMb +dH?*o-~Hj64_|%x-N#RlufG29{+sU}U)`Vi{<}XX{rsB`-+j1K{_XpJe*g8y-@pI#`1qU0cmF}2_ve4 +|{=09#`ttYh|6kdD`1sAY_m7``|MAoOaA*AZ*~d?>-+%S#{g>ap|MlZnf1Diu{iVMAB(LB9@xIh=zkB +?}5C8IUJ)h^!;y?WO_a8s_`s>FRKKt$Ci}&BY|MbuAfBkxrAAbDiyH6i}^@sa0|Ki)f{NL{1JRX1l<) +{Dg_}PcA|LN0*-#z~7ao^#0kMBM{e)h-je*5v8KRy3lR9}Di)u%5%{ZXm?=F|K4k8eNz=DUBnZ|tuhf +Bg7|$5&r|^Z4}s*B`!pWq%jMcaJZ>`SpML_~}mnyN|#A@S8vS)gQk3_5C>R`n&g^e)sL4%kaPa;eOw>|M~r=Z|~nc*7vVJU+qshe)hQQ`Y*ox&i&uD`Fjcf^1kUmKEA$d0>(iIteD}xu&hHHV{zqT@@W0+Ee(*P+|M>G?{Da&7yU%~|lOO&3=a0Yp= +@*Y5Jbw0rFMjd)4}baNAAIrn*)PBN*-wA|qwhZ+KY#!J&tFRs7((+_`n|GxM4 +m+Zc{Z})z{f1mc7`$O*MPPlfy{nh>7e>wTBe*U@j{PFj9FZlI;bm7OlcR%{&5C7X2|M-i4_}S+_{K1d +^@ozu>`7gfs{BM5wi_d@hlYji;2lxNGGpp~v{p;s`@HapH(LetD^Z(;V_wVluF6H&Z-+uW?)Z7vCfBp +2+bTVK5>g)H9&mON--v7nNe|z^oKmOwJf4+M>uKn5le{c88di(6!&-&~U=lbmG>v_N2zkBR;K6}*L^R +vggmfu~UJ^HQh&%NF6uIGGiefD^q{_NeIL;G2-Z*hm`uFtOPx_`Icwm0JbueuZ0N&j_coo~k*>7~3(2 +FJ~u$#5><<-X1P<-YtC_e;5vEy-Kn8SawJzHemmk8@}JSd(JA(qs^yy?Z?4zLa~vf6n_eaew;x=DvD< +=N|U`yYBlTR!pwP)7~Yp6;~gH^tz+xo#A!eKR@rMf1La6J8L(0?hiiNGb)D5H9O=V3O5vF_=vQ}E!33 +CU6AkY(sj`YFOyFGRj%woC&RhCba&OO>oqxT4H=m +P3%AwqKx$C;qp8Ip}9(!)Ce7fep?b9P4p*!_>Kl~jc6AmKT%bMptLaC?v?`%~6{b2Wfou?En*CVj6S +B7`#?$<9vBzWXIi0=%aE)r_~{&Y^E36a`z753{*fvdc}-rRamhWCv;h2Xj7Zlrs@`Lquz&D0Fq-Sl&L +V}4W?Pbr>m;VJ8<3}af@b3XIb^tR`Iy05vp`_tE5d-s1SG>dC%NA4lDdwzyp_~>o0mHd@7L`=!;9N +|y;EM=%TZfT|MishJl?yjwT>VY(&bN4$B+1$@PebIbm-cZav%~mbHE%%@cTG!<2=Crk=^Eul^wvTN2Yc +tdLO@Um}zSVs0zFbYE92NXjy7?*~7uCnaM1n3ME#U{ci)2`Sb{}^I9ldI%pJY#zANPs1_-fvcQ(tFJe~&krhSAC +BRp8#b#yd?$(aHaX<2esj9 +!cylGcQpLxnXOb#`_OCd6Ect-u<(H|=H>*)W^o%OrBr_%8}Cpe|^p!qfrpnwGIy5@}#Ub5+V!!0dcT2 +G~D{cFO;Xu0N6^UlP1&yTJ=y`=_y#K7HC3K6+Z8J@YE{O7@r9{XBTnI7dR@o7V%=qSF27O?d(I-f_yy +dm(ET&3nH&c){ahR)&f&?UU`ni0-D2%u$zd%jI?=?F=SpwrEBWe!(Vf`$DX!4WvG3hxw-q1pO;#GY9ygg)AinUW=Iz7Prb%d-@1Bw7P) +H16VnFzyO7L={CJ(2E@*l)Z+fcwr@Ss5;9JcwXN*^^Z*MaJnF|X%-JHU`L)HDiuH-iFDszYWCe7t(2& +m(2v8nIA|4W0O8(#Ag?#t&~)70QDS1rSs``oWFMQfcdPMf(j7v0`HF)}JiH?zqw?mwrf*2I|p9nHH+MVo(`a9+mv%XoVkeD2P4f-&@58pLzn +og5_AAf7ROo%%a^ovGC`RJC-Mo-wcauwvF8p1REE%nzRi{-^% +&sZ)IB1gxr_>M=izd8oNa&dgy_D0)%!H0-?T;oeFuuQhM0E>HIMHUo<`Grg>47J7*1Oc$RMPhwN9mp< +~TAa#OwT2qlVUC@Mx4)&=nKWl!}zI8O)1Z}Me=b5=HYfti2*3&cARMgy|`ShLZbToP?pNZ#GtMO^ir` +^{?T1=-dio6^8I!|)HSQ(hk-7QCFB!{ILq_BL2R!=RvFAq9NR!pUsf6nxMW}Tk)n%JBUwuHl*G4j$&U +6QP6?~}ybAZvOJm#bM8%?;1ZsawOzv!_3IhnGpjnibxjS-Ny@Gf`C)&-t_>oyVJYq?fIUC*9+WDbFdx +nPWfA9G^OiHPP(>;`Lv0cug+vD_x%Z%;Z}O&TATgDic)Kw5@sMGwpF6VET@UKE*ChuGbyv>7Qnb&!^5 +brqCqQf@i5T^N;6qn%;9(3R5W)Uxp@CareynIsLhMn}=F+rB`gauyNp_GuV2@rKLQKa1UMR{mA-!^O3 +ctm-V|d{itqeqQjNe^zrw|v0fdeA>hp9ds&U9ZeyFtSzugm0_Zw3^i4(0-Av$_(oa?2*{o?%+V{iYxi +pgdbNu99$?Q9;6`e4u$Z5S*)tI~ub)2hIh~d(?a9W +4r^;fU^Od1=ORnJoytDLpmxj8Y^E<6)Vn-0yjE>XDdj^e3JDs4g8J@YUSoM^TsV-4_$CF~86{@}>G|_ +9!WY!kr1j4e~GtJcB9X@6y^)|B?5qiy3!7zF~XSF-M`1CfDPFYW(P4&n0{_|hn)l%+P#hEHecl>bq=V +;S4zcVY`^Iv*YFV|~5FaJDkzT?&9cw^k7re~Dl+{k1 +o1}=-{*VwkEV<{QxU}qT<69oE`>7uXK@>3^2aX#@o>zSi&pKjsl7M@dPCedL`iTgg+HS1+P@ulQ+C6| +%?enXMwJg91&b&!a>^cB}w%Osmwd9L9;Ek(5g$@|63bgt*VW`ZF4?l<&6&-t(RGMAIJzV5nP;<~0SYZ +~{9ye^-Y;utw%4@${U+-fXO48!Pph6>Gb@~T^>q`LJ)@AOC#|K}U4}LHFx|#{dY)&lH!Z~& +yytTB;%>HgXWI07Wc}f+k4@Saz+I**_lpd*{D;nN_biS)qe1slJOlYGf+4S*HX;?xT-k%w9Rw9F +D+o&9-c(M=0P7Z!7) +?k+LNJ~o$2F#n|BnIKJ1!;)O}s^c&{6t-^oz_bj{Vvg{RB8AMwu6kfV!R#({NBZ(|x;uitsbxuupv%b +}+X=f4!v7}*TBW?%O&4ax4XCzfXNs-aGAU{ScPnUU}LQPyXi%Y95_nS$+!%`mWZJ;%v)Uo#e!UeJpB{?QohHnrAAOl8g#OfRJb?vYTJHj6atpq}}N8S9>f +kKz7q22&|&d8Xh!SDpoc;ZX;EO))$th*iJ@Ud_$jPq)m-%=6yeuUd+l0lyD()MW=?t=Ei9A2Xx2nY;F +}*zjUlYnFpGizp+sxws5nKo_*eO$Tp`Ga(yTw4m4`UJD5=P_wN3uXw#HYrT>M<(;99$NFqpPA&7|H8V +7${hAR+Cx0g<&U=28SV-v7mVRMrlS`w!Gu#r->}U#Ol9-CTie>grgxeO3OTRFypV`P^un%;xOd!t8R$X3~U?^W}Is&~E9K457A6D}^p9clIo8$CKlWg{+X4L3unG@4$;hNcndG{1w2-UgfETYC+U +v16WXx8Hv1=`3xNcG%^NPC%sd23AdnB~la>OZzoY3Vg|<;!eht+`<>)+WULqUkMz!^4!=`1g3l#7sbD +L1_q>-g4!vpJv@SK+BD_O+`(2Jawdpd(5;?Ct|#K=%*jAP^zg +E^QIoaorj+=)#>gb8-w67i#ih>Gl7b^NXyWJPNPu%{aVorjBB<(VtRw&UP*c^M-qb+q`VhtTF;9T=E3 +AO?c1!=B=OzDj9?kB)(Z!9rfU{aau`F2sp^623EEdSuBmfy|7$vjjA_fJQQ%>%xtlX@tEg#u!^zXa%% +?0Km*v5lDtoM1UeEGS1{xhp|zZ?)O^b{3a@o#FS@o;nhcRWg=2GF +>1-ui>tH<*U6~@w83u`3H7T&!8_jvov<=v(bf1sp+jTzpHK8%jf)_9C_hzrZ2wO_jvD&fBReTO<&UCG +ik?iU}_!5SIw&nOVR?4Ci&9OaR-kE`an*4xCuH1gT;neOtjC&T%)vYBBzCV!8jf+wCzAFyBB;5xi?C6 +n(h;*IVQV?Hx?JPlQkgaf9Llf*SUr+a=JVjRty%|l3Hw*8oHx{P}FFXtWp*aO=?b+~H)XAGIa2X +v)%QEp2|yG{Cm2qZ1-te>gjlIPQMYkY-LaFsEmkk!mJ!`?aejXlKf831_Z(-6NArn>mV3q%C~*JW5S7p0+R$WH6XqmE4SxduC*_v>bt)E`f>1tU<= +fUzK7&n$rjIy1aL;k;M6NUfioaoOsTE&GObo3@0}H)}EE-%wUbT57>DJrzg`h?rEMTIJ;+XGZmR|ehz +cqw}h9jw`r5Q$Jz1Tv$>$9tXE5!(o`6;1O5uZX%J^}a7z>CbL-0RIb|Vsa(a?8ZJB#){o$VN?Rk``89 +k6lSbNIiwGJ9*o)qp&|Kt?Ma@yd|RV_~kVi$hdQCzm3)-1WW#KVDzW%GLtecJ!Ki)Ly*JmVzuqXJ3C5 +|&NjHQP*Umh0CHC#IP-qpCNqdF1jUPG)v`P4y4V%s!YUC``K$(KRPtj0=~}=pshf;JhAb*$%#Po@8!G +<;{+(iRnG`$p1NKMaBzN=}cUckVD;pPn<<(w}m*Hsz@>+A6W7{ZPwg=bCI%j`K%uV- +b-hIv7e>SF>{zA!!@X)=haHV`yVVbHR+Tr;<^I9=A3k +HLsP?O@EZ!ZK{8U^Q1CKQcR=_F((tF|!bBtZQh`WMf&{Tsh@j^P?&8jGF^4F^MN=-G{-srdE4udA8!^ +wdc^7yP5xTu;?1{pIvwZIy +VOQ!~3A9iNRA(>?$yU^q{;$<{jubMa5DHV#;DZJe6Q+He{N!Ow +s{9hlMQ#oI+bO^C@HLoGh3*N{;bfvuQIYg606#M7%qEJm-#Qqx<;uB$*t_OM96&WWgy9dSHJJLG_%Ae4EwiY*x< +tM$kScuiFo9dPdJv0oXA&^_A+bBb$*T +2qmnyEaDJhgl?Xjn3HtxaJs@1^yb==10qjaA!C(p_v-aR>#Z_4fJ~gZ|?9+-ReI^eqzp@Og5rn_D0`k +Z#w6AjNxUDF+OH#<3@~;xcUL9A7`*&j)|<9OisI<ud%ycXUVr5*P0`EF$Y+4maTwQG^{zRHDxi1Hz$TCnO>az-(~omx91skrgO +^1tjY<%HT|L4%4Iuk%|@rQdCQvQE~A+-%?8$-RhFUCYmXU5%lyzHVcE!AHZ#^lyp_~L5U-imIQP69g} +Ixp=T=cBuglilouN((NUk{s0mRlcy+54~oHI*;Y8+dfXfA7x;^u7E#r)_>bISB>uBQ)kym{61nX{mI& +XDPYit0IcxF*IX#r!yHVRxil9dy0#Pz$zWxoU1?&2q%ls-}^<;VHD)6__5|qTtM#32kc*2b9f8JCyhA +YYyo?C&PK$1L*c@K*z99v)lRFIvbsnI45h*q*JWde~G~F{b?6H>)rQ$^v~}<{qeis`eTA$z5n{-zxYF +wkNz;?@!^~A-hX=k?RWDh8oz%3-TSZR2>tK>@agv-zkPo{r%uGoa5=BAYRXlI(^5TsAn*9dHq}J@g*970wOx+2y+}}&8%inWQLTU#G=8mkY(3 +onT4-e2+qm)<#70N_I5cmwE7jLlH|NdCnk*2%Q3k%yUq55)@%S^v^5h4!}6V>IrX&aIqW`1Ei9kbOlT +b8T_$^L+NpEx%bvs%C4CfQ{iQQW^usfr1x?x!nWY~aimIkdH$s#$aR +!|vcRe_GC$-WduE$AXsQH*5A6sq>mK%1PtpJn?c4YuPDZ_MjHxU6^1w4!9WNn!kUz^7TRK1cqaOYmWc +sBo-ZW@;4_NA)-TF)1f*dx@?)RnL|7Id*7kJnB5$cs-@ptPO4njxWGKO5OIucIgqfp_?iXqv}y2Vi-Q}e2a-?=SCApj)TytK?Okp`RyBwNb&dV;xWtW4S%lW)z>AhyAK4@l`<*e#**m5}{vmAn14u7m!gj;Xl8Hx$3nB^?ca<*c@#zixhY1lF=Sca_SMCWpxVA%yM+87vv#r0v|-cJ6CC_O%`R+Kzo~C%(25U)vd_ZI^o6`Q2}m&6Z+Iv8C8j+#zvixFy+=gd`zJN +D`8SBq2#i5-t)_gcLb#-n%K86DQm9>B?b`^yzt?*JtGL`kfq74&|C9ak*x>W=T;}+;MSdI3vjCY=>&LLp9r>jypqf;>gT)WMfI=B+vVM0ciRWq4ufnn? +(G=Jwp+CA;BH4B?hM6*(;wS9XwT`7J&z|QY+7&o)!Y8!wn4JV_qMd(7HZo%dULWp+l`xW?H3!&eTfMt +Hm*J8B`_@EwqqI_=Wd#@Ex@+J6B~eR#{%}8me`h{+d+xVRyIr9_P)3C5Zif(Z8^Jb^=&(1+gXPVRX2C +vHmJAF=k1uoouNp;W7{!@4WPGOneCXvcFbYhJlc*qY{wk7!wuWk;+8~-HC0JU<2*Vs5gJ!zo(KcrW1PxpJ^@ +=-F8m5J=1M#bldFQ_I0++&TYqK+w9ynJMRqDzm3jqqjTHn+%`J5jm~YObKBzFHZiwN%#CF?ZQmefgV$ +|aa@&!-GgSY4YV)dXe{nPR>vdl>FVcwtTZG&0;3nAH#^AOwxNQk;8-aI*g23L-wyCo1^=*57+XmmpJ= ++G~wyn2q>uo!F+m7D0qj$Z^LJZ7i-nN;ydH1%Nx9#I?`*_ +HgVjxdA6;rZ7XZr#M<+RHq%b+WZfBx4!Z!?M1uXSZ9i+r+>H>iC3WG+ZC`5R&~0C8+n3t*r8Y*}i0sZ +#oY<4vHlnuer)~Rb+iKc&nRdJ+Ns`x#tOW}i+-&Otp_hL7&T!TwcJFZLwr{lU8|~S#prhNq(T*vGxlI +8SlcMLtlFjFOG89I0`YK=lC9zPlbF=N)Y8o5!)ujo}DdHyk}<%7jJtI+aAQW2eIuzY}*fahHKuISbQP)4W&0t +-pqKz-wkXxo891b^TN#nH}czAN$w`O8{KYdyMgTnwwu*%R=ZK{r7SkD-Msdi0;%b32<@h^8@z7ty +20xPuba7Uw7SviMys2NZYH{!=w_muiSC-I2o&8=bVJb%MK=`PP;^7lU9*Zg^M-Wd0*r1jy20oMqZ^Fg +843(Cy2=7dn~ZKUy20o +MqZ^EFFuH4|B4l)v(M?7-8Qnben#n5^-B5Hx(cSZ1L +#xk?uJkHjxZUHz?hpbc52(NjE2bw?XL!r5luPM!Fg4W~7^uZbrHp>1L!Gk8V7=>FB1Tn~v_DQ4f!9Ji +77d#-kgLZali@3r67%}6&Q-H3D}(mO-Zfk*diYyZrDNhdlO>1L#xk#0u18R=%Eo00Apk +*YjIdS@s^@aV>)8;@>0y7B17qZ^NIJi77dp6~gX=@ld0h;$>;jY#hd#Ys87QdmTp?QY3Zh=o0jhRE9>d-km;U3P1f}p^?Xp+z|##+H$2_&bi>m<-(WF)BthNtH5SubV$_XMH%8 +qU^}a(9#8Ed#-5hme)QwR$M%`zQO~t$`od7!X$a6FEh5%xzcZMPerf!(JVd{pd8>4QFdQG>@Qa4N87< +FURO;9&M-2`=?Q4xf?5$c{VPnhl=qi&44G3uW0NthvkrEY?{3F;=Oo1kujy3eQxLfr^;Bh*b$H$mO=r +35pGVAPFK_nFF@st`qI%5_R}9zt((&5(2E@{@RGDmG(g1j4GYTc-Hqt*>suUX} +j)@z1Q+`8v)-8XODymj-|&09Bb-Mn@4*3Db@cs3>x1}W&eq3edO8@g`jx}ocat{b{;=(?fnp1*>gH5+)nGZaDOb( +7akUN?E&Ag@z$#PAg@7QgS-ZL4e}b~HOOnM8B^vqV_qZ^4fr+iYtYv_L*am51HT4-4X +hJfCCvC^%^iw{X(aeH@N3}Lz^{Q{gTCGw3J3fe_%-lrtk*di)4<6_V1U>Fu>oQO#0H2B5E~3O#$bcN2 +7?U-8w@rWY%thhurWuqYU)FDfY<=B0b&Eh28az1duJ#*Kx}~60I>mL1H=Z14GiJUfFQ8}Vgtkmhz$@MAT~g3fY<=B0b&Eh28az18z447Y=GE1Ln8@@4G{ +N@E3e97+m0_KtOkfVgl5J^-WkVgo%BamWK&*n7oE5SeSi#_Rdf^Fxg829gaV8%Q>gY#`Y{vVmj+$p(@QBpXQf&QK)a*r +2gNV}r&9jSU(bG&X2#(Ac1{L1Tl)28|6G8#MM^;Ml;iL1Tl)28|6G8#Fd(Y|z-Cu|Z=4#K!!^0R;&f8 +#MOLaDEmJAT~g3;Mc&ffnTo~ff#Hs*kG{1U}L`Vs3xtr7=sN48w@t^Yv9+wuYq3!zXo{?@*3pzn!kIT +w#;CI!3KkkG1y?R!C-^I27?U-8w@rWY%tisuh&EagAE273^rnZr^CRlcZQ;aw+3pBnCO^?7ahDccx#~ +6K&^pVgR}-|4agdhHRex`g0co>4aypnH7ILP)}X9GS%b0$WevU>d^Py$Wr`G#HRe=zP}Tsf0aydD24D +@q8h|y}YEadnszFtQss>dJsv1-^sOr1Gs)1Dls|HpLq8dasfNB8M0IGpeWBx#Zkp)W)j2Z;>LS}b{^N +u*-sKHSKqXtF|j2ajA)7ET*rQR6|5ttea24WJr8HGpaW) +c~piRPPK$2T={88bmdSY7o@`ssU6Z=N?2KPz|6OKsA7B0M(eU2MwYcL^X(N5Y?;Z;ROa(4XPSBw`u-a +Q!0W3o(9YeoEQ-C&QNqvtC+LNHN_`HP)yK{KpcT30x|?z2x1VNAS};gzOIZ}-WduJ%i^%m4J+HQvJH# +Eu(%6rxUkrYnc>gmdnVd5IiBgRsbS1%+L%ei%m`)_H@ID7G^Wp={&u?6=~Sj8n07Q_BTize!nlXi_22l;78btM);iO(K(uoeL8dNo?YEadnszFtQss>fPGZYwDHLz-6)xfHORRgOARSl{dRP}llj +krLofmQ>pM$H#GzY0xY0M-DkQS%Ki^H8FLvc`Nb;x(10{~)bFT7$F(X^r^AWwFYVp)EcNYP-~#p0Ibndx8ek?23ifY8fZ1nOhwpgu+y21gB!8W=S&YGBmBsDV)fqXtF|f*J%h2x<`2AgFhSq647 +@LJfi%1T_e1z|(-I0Z#*-1~(0E8r(F_Je{88%sK^}1~(0E8uLZ5(`Uldn6G=D-jkpPJPmjn@HF6Qz|( +-IG2hu5^fc&caMR$X!A*mf1}F_i8jLjXXyDPnqd`Z5js_i#=hzn>jrpE7J$NwEV5IS!V*?5Vlm;jbP# +T~#Kxu%|0Hwi6<2h3iP#TOh7-=xlV5GrFgOSD<=?oQ&H1KHP(V(M2M}v+A9lbLY6L>W6XgudOC$X3yq +d`W4j0PDECK^mMm}oH3V4}f9?+nER6b&dEP&A-uK+%Ar0Yw9f#&b$QNZ`=Gp@BmKhXxM4GZYg%G@=U;O$NlY-BU^Kz#eTRE +~DV^vbqe(^+iY63ID4I|-p=dJEWTJ^f6Ne@aO&oe>_?n|iobz}-m^15?*F5dq$m0UnlfQ`Jrn#oa2B*nQlba?t&H0<=n#+qAc$)Au;c0TyTN;C}Oy2a?|9d$xV}+CO5sT*%F>6JWY6-@HF9R!qbGO2~Xc8JxzL=@HF9R!qbGO2~QKACOl1en( +#E?Y0lRsu)!p#Ie*@t2sIIEBGe?PNl=rZCP7Vtnglgp-?i-iF=`UjB&bPHb52MmLQRC42sH_6?osucA +Egr~7&S3!V${T_iBS`yCPqz+dS@swIBIg#B9=R8MwT;J&WJW0>U3B7r#nM2G3{@f +-ZZmmToZGz0umGOG~sE&(}br9PZORdJWY6dXDA%#X~NTlrwLCJo+dm^c$)Au;c3Ftgr^BluZdxTngsP +-BGg2viBOZECP7VtnglfoY7*2Ws7X+B{#g%;{=}$>Q4^!y8IGgY{8D0pfl(8qCPqz+niw@PYGTwRs7X ++hpe8|0f_i5tCg^Fx(}br9PZORdJk9yaY4DH)H3@1G)Fi0MO_Q4@H@!0y4%{@kX>!x#rpZl{n);N|TW$BTYt{j5HZ(=G>Rg0gomgO+1=(H0fy4(ah-_$Y_$$B%?`2lZ+-AO)`2-M}tQbk0 +u^XFq&XA!Dxcftmz!cXp+$+qe(`Sj3yaPGMZ#G$!L<%B%=vN6O3lfspyFylLr|mU(GycV{RjX5IDT +(fLAFl|D<4SqjV?d#1lL9i16jy*?tXxR^oQaQp6}pg9B5beGdJPFFSU_D}ChH|+KLFVkzmLQ9jDCM`` +^df%ZCp`}Snla^+^I*j?9D^D?q6J(mSG-+wl(xjzHOOun{8Hy87nxHfpX)@Aeq=`opk0u_?nn`F)iu; +9;CL&Elnmy|jMw&fK*`Bw{OM5w9q?^TxC!?haN)wc3PsE)0F}fDJ +o=|^KbJhv}?)?o+doKGZaDeG~sE&(}br9PxIxbJ^$sx0*IR?H%)Gu+%&mqa?`t(RRuRqZkpUQxoL9KM +5a0au-lC1+%&mqa??bniA)oj=8$P3(?q6;OcR+VGEHQf$TX2@BGY`4Y0rO2Hl;p=J7pnkE+LXV!x#rrC2%v2$il+Vfx9GCj@ +tN8Bt{uUV{O)WoQXQInu1K}~|1@HF9R!qbGO2~YD(Z*wLGu>((&nU +apG|%)l;54~uBGW{siA)ojCNfQAn#eSfX(H1^rin}wnI_;*n +Tt%WuQ%qx62D$tSeRhcoPRefIcjp$+132GA5B&bPHlb|L%O?aB{H0PgDnmws +RsEJS$p(a61f|>+132GA5B&bPHlb|L+O@f*PH3@1G)H_38z^n7VrthAA1!+uxs3uTNpqfB6focNP1gb +e-tv9_rRZXgTXQ)%bs)jNvxVg^|Efs`O?l=yRg+{tN +DDrF~5^oh&<kQ7xcaK(&Bs0o4Mk1yqZr7Dg?MT64;@IBId!;;2PXi +=Y-kErMDEwFqhv)FP-wP>Y}zK`nw>1oh5vNizQyW65DjH&XVLWJ|o~za-ugZ;7`LZ)vy7ZOQiBVMr2^ +gd`zJND`8SBq2#i67DdiNGVc^lp>|bxxrryro~N +*n-(`MWLn6ykZB>)LZ*dGYyQzebB*Gr#ZB)Fk90@6Bi&QFDZcsOQ@W=sJtcX%(o>436as;p7B?+!`mV +rfans_a#Z8Nw7B?+!THLgdX(7`>re$hgMxina6*8?M)1swCON*8kEiGDFw6thx(bA%&MN5m87AURx=j +hC=ik22Ey)zU9w6w07c0A`tiA4f3Eo55rh3zI|#Z8Nw7B?+!THLg_>7Ai);HHI4i4XC|D*a(G(qg2=NDGe^9xXgtc(lN1G0|e8#YEo~6fGW +FJhV_~q0mC1g+dF3*6T2-YvRztp@l;WhZYX4HJt+wEgo7tw0LOo(Bh%RLyLzN4=o&8IJ9tR;n2dNg+m +L6-Wdu49$GxKcxds^;-Q5?3xyU5EfQM%v*urMGKVh+S`f4#=$)ZR0H6gx3xE~?EdW~l^Lmx0XqX-jf) +)fV2wD)dAZX1O;Xl6TUs1jD6%{bFU}(Y6f}sUN3x*a8Ef!iVv{-1d(88dFK?{Qx2E8*B5FE5PXmQZup +v6H8gBAuY3|edIW}a6(V9+9S6cHT+4KpBVodS@sc5NILLLZF2}i+~mZEdp8uv8R5NHw5f}aIH3w{>-EcjXQv*2fO&*Gl +NJ?{)f0{ATOS=_U@XK~Nsp2a-Ebdv{v*v8*HFDGQv?2k476L5-S_HHRXc5pNphZB7fEEEQ0$K#L2A_0LG0xbku2 +(;j5!Ow!91wRXZ7W^#uS@5&qXTi^!v!O*li+&dUEc#jSv*2gJ&w`%?KMQ^q{4DNS+_Si6anItOcZMPX +d=~gD?pfTkxMy+C;-1Ali+dLLEbdv{v$$t*&*Gl%3VasxEaX|pvyf*Y&qAJsJPUai@+{<8$g_}VADF*EU*Z_l)P=AAQ_oB5HsLCu6<#@FfNr`w)hcE0DnrjblR& +V!Q8BAW#@3u+eBET~yLvv_9V%)*(4GYey&#dvx8Qgeg@yw!_MKKFv7Q`%wSrD@zWOJp{@ulvyaVP-dab>vh+ngJ%}WERuQ6fQmBzD~nYYt1MPon6e0E5y~QzMJNkS7Mv_NS@W-y7o99PS#Yx8WSuD>Jp`OAI9YJA;AFw +cf|CU&YyJ*?+B~6rSBSC@Wf96Elm#aXPS*U>?$bFC%6d+^*N>731VUMavYtZ^h_Vo65y~QzMJS6<7NI +OcS%k6(Wf96Eltn0uP!^%A`Rn&Wlm#aXP8OUjI9YJA;AFwcf|CU&3r-fCEI3(kvfyORKg?cqvfyMP$) +b@(Ba22BjVu~jG_q)9(Z~Xk1tN<>7Kg0o%)UTmfye@p1tJSX7KkhmS@SP{PX|jQi$)fWEE-ufvS4IAX +XXGRi$NBHECyK&vKVB|Ki)lS1`t^wvOr{k$O4h|oOeY7hrBZs4j{5XWP`{{Pv11MX=KyLrjbn}n?^Q` +Y#P}#vSDPy$ahU6n?^Q`?6=A5lH`))lH`(PNwQpINwK6@QY9%xRx-H% +Ix$R2Zm9`WiMM&W&XM@NFkqsgnL^gpUY!2BRvN`0PVMpUY!KNDvKeF}$VQNjAR9s689pU>O7fKCDalikrz +B5Fo|1?G2H6a<8Dt~KMv#pl8$rHn2H6a<8DulaW{}Mwn?W{%YzEm3vKeGE$VQNjAR9q8g1j?S{|vGjW +HZQSkj)^QK{kVI2HE(r@nh4+rjJb@8$336yfakw8EQj?EmKIW}{= +GgS4^v7uu_$A*p#9UD3}bZqF@%(0ncGsk9*%^aIK_WVP04ILXgHgs(0*wC?|V?)P=jtw1~IW}`_=Ge@ +!nPW4@#*KG|s-8DCZ*1P!ys>#>^Ty_ljT;*`Hg0U(*toF)S(~=D`NzBFjm;aIH#TqV*FntZ{CK=br}~ +*=Gsm7Ym?nu09veJ1c)T-w{ZcwX0391THgs(0*wC?|V>8EQj?EmKIW}`_=Ge^f&QK6Q$A*p#9UD3}bZ +qF@(6OOoGsk9*%^aIKHgjy|*z<*<4ILXgHgs(0*wC?gWAn!5jg1={H#Tl;+}OCWabx4go-Yh-)Y#VIj +T##@Hfn6t*r>4)V0;Bxo-Yh-yx4fL@nYk}#*2*?n=Uq8Y`WNVvFT#d#RiKF78@+~d|_yl#fFLv6&orxQ*5T#OtG0_GsR +|#%@ms{HdAb-*i5nK3qu<8DK=AVrr1oenPM}=W{S-e?+n#HRBWi&P_da}Gs +R|#%@ms{HdAb-*i5mlq1&>nEuY#F=+036n=!WuLQe~3ip><8DK=AVrr1oenPM}=W{S-en<+L^eAiI1p +<+YDhKkJ;n<+L0SgsOlkNL&S!N4G|k6HbiWQ*buQHVnf7+hz$`NA~r;9hLFr7#D<6s5gQ^lL~MxI5V0X*L&S! +N4G|k6Hbm_Ce$S?e4G|k6HbiWQ*buQHVnf7+hz$`NA~r;9h}aOZA!0+sJ400u5gQ^lL~MxI5V0X*L&S +!N4G|k6HbiWQ*buQHVnf7t%@3O&Ha~2B*!-~hVe`Z0hs_V0A2vU1e%So5`C;?J9zSe;*!-~hVe`Z0hs +_V0A2vU1e%So5`C;?J=7-G>n;-W0Ve`Z0hs_V0A2vU1e%So5`C;?J=7-G>n;$kmY<}4Mu*VOZ8a6d-Y +S`4UsbN#YriM)on;JGXY--rlu&H5F!-j@Ee_P(vu&H5F!={E!4VxM^HEe3w)Uc^xQ^Tf)O%0nGHZ<({ +8pNiCO%0nGHZ^Q&*wnD8VN=7VhD{Bd8a6d-YS`4Up}VFSVjgbfHA5cYf>XA{CEgiQ#W5H=xfLfC|`31Jh$CWH+L8xS@iY(Ut6u;=SIn-Df3Y +(m(CunA!k!X|`G2%8W#A#6a{fUp5!gSbX*JrLBipdmn8!1k;gXQeiiznK9L!X|`G2pbSKAZ$R`fUwzM +_YCxKu;F0C!G?nk2OADH9Beq)aIlGB6Tv2eO$3_=HWBQefu0674Qv|NAh1DTbHL_+%>kPOHV14D*c`A +qU~|AmfZa3DGr(qm%>bJLHUew}*a)x@U?adrfQ0i^orhiTUn*MdqK#%_#|26(=`q%WY>0i^orhiTUn*KHYYx>vpujyaYzdke2_-pXj;IF}7gTDrU4gQ+>HS_B;13mO>=GV-xn +O`%%W`525n)x;JYv$L?ubE#nzh-{T{QAs55B-|?HS=rc*UYb(Uo*dEe$D)v`8D%v=GV-xnO`%%J~Plm +zh-{T{F?bS^K0hU%&(bWGrwkj&HS4AHS=rc*UYca4D`^inO`%%W`525n)x;JYv$L?ubE#nzh-{T{F?b +S^XuWh#(j1)#0q_0U|KWCsPeNFnB^fl>g($}P~Nnew`CVfr%n)E +g4Ytq-GuSs7&XP_s2P5PSjHR)^8*QBpWUz5HjeNFnB^fl>g($}P~Nng(~#3p@B`kM4L>1)#0q_0U|lf +EW>P5PSjHR)^8*QBpWUq5G{Cw)!&n)Eg4Ytq-GuSs7+zJ`1a`5N*y;@-^gZ$ +k%+Y`CjwA=6lWen(sB=YrfZbukl{bUv3}1chKHJdk5_uw0F?nL3;=79kh4Q-a&f@?H#gr$lf7)hwR-M +UXomrT#{UpEJ>CmOOhqYl4QBal441*q*zjHDGc<7>K&?gsNSJ^hw2@wcc|W>dWY&As&}Z~fqDn(9jJG +p-hp~|h9OBvl9Hq(DM?C_lB6UlNxDc%ky4ZtB}GYLpg&aaP`yL-4%ItU?@+x%^$yiLRPRu|L-h{SJ5c +XHy#w_Q)Vni0k{n5nBuA1X$&utpawIvD92a>?@s#2z#Z!u>6wj%YrzB5Fo|4>Ef2iJ}dWY&As&}Z~p? +Zhv9jJGp-hp}t>K&-}?oho$^$yiLRPRu|L-h{TJ5=vby+id5)jLq{K)nO?4%9nP@6J%wQ@um=4%ItU? +@+x%^$yiLRPRu|L-h{SJ5cXHy#w_Q)VniO^;GXry+id5)jL%0P`yL-4%ItU?@+x1^$yfKQ13v!1NH6< +RXx=^RPRu|L-h{TJ5=vby+id5)jL%0K)nO?4%9nP??AmfLsd`p4%ItU?@+x%^$yiLRPRu|L-h{TJ5cX +Hy#w_Q)I0O9O&qFssNSJ^hw2@wcc|W>dWY&As&}Z~p?U}E9jJGp-hp}t>b*Na?*P36^bXKFK<@y(!}1 +QxJ1p;@yo2%%$~!3UpuB_f4$8YTRP`+Hu)M?a4$C_%@36eX@(#;8DDR-WgYpi_J1Fm;vI^2DBhuXhvFTIcPQSWcz1 +@X9^)O1cQD?;cn9MhjCU~Jp?HVl9g24--l2Gh;vI^2DBhi+s>gT-;~k85Fy6s<2jd-#cPQSWc!%O0ig +zg9p?HVl9g25nsOmA^!FUJb9gKG{-obbW;~k23DBhuXhvFTIcPQSWcxTT*kMR!1I~ea^yo2!$#yc4AV +7x=|4#hhZ?@+u$@eaj16z|O6MIVfJFy6s<2jd-#cQD?;cn9Mhigzg9p?HVl9g24--l2GB{z2@6@eam2 +81G=bgYgc=I~ea^yhHI0#XA)5P`pF&4#hhZ@5BuB81G=bgYgc=I~ea^yo2!$#yb@6P`pF&4#hhZ?@+u +$@lMP@kMR!1I~ea^yo2!$#yc4AV7x=|4#hhZ?@+u$@eaj16z{|g^ce48yo2!$#yc4AV7!Cz4#qna?@+ +u$@eaj16z@>HL-9_`K#%bb#yc4AV7!Cz4#qne?_j(`@eaj16z@>HL-7v9I~4Ea4D=Z9V7!Cz4#qne?_ +j)x@eam26z@>HL-7v9I~4CwyhHI$&Ondx4#qne?_j)x@eam281G=bL-7v9I~4CwyhHI0#XA)5A&@eam281G=bgYgc=I~ea^yhHI0#XA)5P`pF& +4#hhZ@8k^h81G=bgYgc=I~ea^yo2!$#yb@6P`pF&4#hhZ?@+u$@y`5f69?lRjCU~J!FUJb9gKG{-obc +>;vI^2DBhuXhvFTIcPQSe8R#+I!FUJb9gKG{-obbW;~k85DBhuXhvFTIcPQSWc!%Ph`NGhH@eam281G +=bgYgc=I~ea^yhHI0#XA)5P`pF&4#hhZ@6-(R81G=bgYgc=I~ea^yo2!$#yb@6P`pF&4#hhZ?@+u$@l +MS^kMR!1I~ea^yo2!$#yc4AV7x=|4#hhZ?@+u$@eaj16z|jw^ce48yo2!$#yc4AV7!Cz4#qna?@+u$@ +eaj16z@>HL-Ef1mEFO32jl%e9ow-9!$1H8!ThTbD01jXgSt^*Cl(U!Ke6|dYhhvF#CT#nF`gJtj3>sE +;z{wOcv3tmo)k}tXWp2_cw#&;o)}MzC&m-wiSeX(QamZ16iqudUWppoPbz^ICaB^>AWpXZXd6iU6Z` +(Q$y!%%y>Wc$7YTSnhv@hsER_xS>zaZHtax!RXWfP@HgQOBDzrI6%rEMJGRVQh=JDizaZM%K>q5j~0G +^Oz<8BDVQ^~ba1f!@h&x7xJWGR>^qNG%j4reKneD)SUYncl#jdu97J7f1B0H(RIhj?yTcrIw&>=EByC2YXjHMnZ)sgqn$@5`6ZfVh|*QLGfDA=gp +Lj_nf{2PKKo-pY0DjqSLr{}3UX2>XNPQf;iP=$gRLlQ%SP{MP8BepsXA+6vnQmrBb_&XoQc#BQlEHRV +E+v{5=)$iyPw!PMCeo0JKc6f?2@t65kBxoH+P}%3ZxrS=!QL2Mi(u3Ra%hLd)O_!#|r=<^ +ciDBYo^+9S*tD(kW1f3i*K{#g5v2TeUH;Lo-Q75kqf7BivAstWVKTgz))p{_6>*wU@}OPZ>Wg-qw#3* +7}yU-i|HWCXgEtLrg@w$M#*v4DrhU77;Vm +3Vxmak7uhv`)k9_UX0I0|uZG@|EJ+*RrDrQKJD9#V-37{Pf4dm^JnGWFJtPVJL!kv3%7?N9^iUaNyVN +(%htx@o+M7?k-pzIIpPL@hGDGCOhX&KT|G7lktyXDGMNzfRx57I1J8Ra^kN$<9Xi_UL`;F%Wry2YC{` +6Rb?IQKYd5l^m@~zZ-Doge!SvZ*-PEI9&InP~~>0`lQnLMO-zZ}F^M~%ZOI@5Em`Yk(~Ot7s~tJTVta +PAO1@atTrjb(vdfypRowUSslt5wIbDv$B-TrP}$Pd{geuV_^r)lTT^1>v1v$-XIlBl!j1e|_JM&L0RC +tI;EP7Peu(I(BlUMa6##wCroE=>u-Ken>yGegaTS0|XQR000O8HkM{dB~POi-#`EWIEVlMG5`PoaA|N +aUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3PVRB?;bT4IfV{~_Ba%FKYaCw!TZ?7fAk>=muPf?P!T3c +%4%0E>ZWv@rV7|)=!F#@cS_l?!S#k8jBW^Ok|?5E%O{i1rj(s-m@UL5+Kb1EwsN2`&!_KRKlw*CynXWesowwc>GAp7$FH_8eze8^e5>bAwDsMOd8=>UZa@9tXIs0j$R_^ +b*WcUTfBACzl<&UTK7D-i`1H5Ouj)xYc>U__(~B>@&&T}fo1gtM-`Tc5Jb(JP?UNTT|N8Xe+wJFD_VD +fY_VxD3k8i(u{px=H9IBTuzIb~6^dqD8_0!|y_U851Z-2;+{c8L1_4nJC&tGj%k6*obQ_bfmPaR`&VD(^oKO7?Tg3l`!|nYfB*7XwvgZ5{`I5J|K*Q=`h0u +;<3Dfz`u?Y%zW?#(fBsc|H%B@@&H1aAUVQsqn&4MkKGoCnS8spJj%NdZ`0&#Y{w1$?|2H4~{-e+TOz( +g9(dQq3_}ORM@BaAd_Wt(C`=5UP(FcF}{rjJ8pZw|5PyYDXhwp9MXOEBXhM2+pM}zzyL;Q6%`R(f*$* +&&YK7aA@O+EUbb9&!o2VZ`*ee?Wpk2%d>KE6nc+MeeU`R>R6uQ`1A`qf{3-n``R1Ny7&#n;=b*KeO~K +Rmri+ez#DPqUk?{C$3(rO|)+-m~p!`K9Nt{_SN>!Do5-?_PYJP5(@`uw%@#d^Ompv;r+aJ@2%}W +Z)0!U_NUMCo&V~;?Zc0M`~T=ve)5nFfB2^lKL1x%#J_+4`0C3v%jaLbe5{q0284Nh{q*|V?TZ(GJ+>c +SKm8k)@ZMSB)|2VXUi+UfA!^ym-)s2@y*+}-~I9@Km72+dyijz|K8glei` +i--{uuhzxXHa-Fj@>&wu_;+y36{{cQPGKhAe=9V-srI$D4C)|&NJ+xxuVifhE=!hOd5*0qipPW?w;Jw +D%l`_9zq+^3BH_Um_T{o<$X=l4H>pRaqB7iMpM@zZ1O?dSQgpZ$7&ukA;zuphrmN +BQy}-R}7pERTNtH*AeQz1&{E%Juu^EvxL?@4x(J`zF1eo+bUzr@#I5;lX+N%jbXoZl`?GfJ=do?mW!nlr +Oze;8{VdC?fpMxWVQ&UXH}@($aa&(gR@{;TDcSKh0)n9o|{)AP8VjX1e=Kc9`c=a8^O6^hww|@KanZ^L= +{?(R*|)r5_IKv@+Kinq&u8Pv;Tt=h?tL;CSG9ZX57`Z#dGm4eTd{Ja=VCDW^^9BRgXd87I66JbD`VxC +bLBH~`CjXG$BrGg8~gc?kFlQh{m6!no%zViw=?`!-mr1yMfY3wD4*VuW*Ue6ZO`%n>C>5?o{SCc_WrP +V@IJ5X)|K;-FN+7ydA=Cca~{0p;GMg}7|c<=H^yS9@(!~;&~C~eV#GrZZ~oCoaN~)wT^L1nfoE>})tT +q)$4YZ*bMCx1X*{21PFl-3&$+vp-+jkhwkw;=hxF;Q3r9X*Pv65JM?PQ2#PT6?p7Pd>=WO$f0Fj< +XHBVjkl2_vYnbK_IuH{{mRx3Mmi@hCu1<7tidB^u&u`U_D1)+?OwUU+sN6JSLTr6+0v%-4#7BhYaV>J4Lk~wYtJx4pvDwE?3s)Vg|Dd`9S&S$%EKrOl%}?la|12AufLLur6{YyPzyIh@aQT?`^j8q +Z$qc%&m`e4X)y>&rPhxG}yUP1+E9&~sNb>n-~>j4Rh}&|3VdQC!^1IK*nmxQS2FcVG_4f4d@8A28qkk ++teAz=wT#~jNe1Fh527^yLaZF7xBSIMWt{033AU_c<_ekmbR8Tlw^@5f+*A1 +{xdlUdJ6=lF>dbgk=SENQ4?Ro^yHP*%D%4P7J)k9^+ZVb#Va$9S0Zv1(F%nZsL;smNNr5NhgsDAqN8# +ImOT`Cn_&z%7~>a@EMI@l#V8W8@5EJ&n4`r^_FWW*RiW1ao;qiPl6Y|e$f3vxar{E0Ss)y%PXyA(A5z ++K-1Xd6OOa&p(ieB0M1;(tX@JzA56+Yj3l5%;L?pI;mg2hfQtx*dk~(x_yuQOaVTdeaS702yL9d#kJ( +8#uvI*KLJ|N&a3zqBTjzshyTTdfe7b}OUrAf6b`zI$7xhIy28)^1o~~iXy&T*DOv-FA$muIDU^d|{hn +ob2oF{lsz*O@#z$N_z>IA(!a0qyKURu`)Hxn9`Njl4XaE!e>a{7@IuK-Bv+Rfc=;*!aV%8Ak;U>QOOL +ja&-PVok)ER85T2r%9?wu@Vno*hI24Evn-I3zAfkim2U9oE#jrh%{NJm=(zlrlxj*06jWQfCd!A&xun +N{3fydw07*9&p%8yb~ZFw3pTe=%Ith#0eiRQamgJ&oDN8%m4%@g4)5vM5IxEeO%1j#j;8lne(RiXBYw +FSKctE2OA+*WHsdSJ9wnU(_qP%IDkL@Bq*WuL0|;z^^cM~noI1f9q@y5b0WTg4H!vpyPlnh)S(s +;j%J;Z+uRJ#0D)9~EA*4Mf0Z?3Wio;C=wHBN!;~T^`;9bM(=D@R7@v&H3=1t{yaqHGq3*x)MB=K5l14u?D;GHQVT9zRTorO(4doxS1e7^W${d2_PMe1JA9S#k!n(AjzJil-3W|F=! +1xd6k{xhNcdQ3B7UOaWHTA-{WA4MIHjku5$;&=Y<0n^0FWmi2T+&Fn*AQUv*} +|qy^Sz}92<&n&7#Z_+CW`Rb$q*+gVLql%fCTrt+f7`Ow#r%rD;(Xgk`EE=Pwo{)KjJ(Qp#$X8Mi_Y44 +{jTj)ucm?v+VawTr$enx>EJmjtJpn=Uy6ikWtdrG;Dj$6N*Nd^M<$ME8DyNCMrw6Ze+p+15|e8OGXM; +4~wZ|9vzAcdz`pKn21~h*>hG%Iv?<1U{FzZmKoARu2dX9fC#*keZd{#W1QWkVZrJ&ErZ3m4-txP2=6> +hW5D%Map;6E=}b@S(jsJ;Q@}t7!b}eaStziZ-z>+0)Mh#G4w@?(Fn1RIJ>g4E{mB4_lWYl^1!Q>GyvX +UH4eWgBj_DxAGYD0=0L*O}r5pF1;1V2v+6tu9#6MghpW(llP|U6~@Ruk{IGQj0GGq?z=E8LK(=`t1Cz +v;Y6Iq-5%4IwTlkNvg7*Ht!9P%~B9L&Sqw#YUTn&ZTG7jKjfBj;_Fy|XGwPfob1>LuZ3T{g)uUZ7Z$z +50`Qd@)KF(?}9`-hL-xWa7!GV+8Us><1YEHj%-?W*WKB)>Be?s{sDeLRlgl{`t(bp>){BM+0=Qn{aXLSc#5;RPT(STz>6~)O6B!paxMl +%f(&dxIkDpx4ywrH51C{U~EMggiO!zI^O-z{h7Y73RZjdoslg1%*x7CX4zc6Fz(F2>{B2gq>?|E2Xmk( +j%8^hZtUfo(9L6gPKoBMC^c#{1dwAj`IO7*~o>L(ea0_;oCqLC&WEWzi%Q?T|YqjhSTe`CMiM7k;|zArhBNll99bVTgqeUQl>U@e)% +&2j?;Y^XF3Qz|l2DPfgn!xMT9S;(yb1?GH507cfc29@1h$2V{S-k=+4e%@Q=g-aR@5GcEKf0-pF_e2}^q2>Dy*q;tUr!Lt +u)BDQ*xi;dour089bUjPPZ<2lar0o{~3A8TNCsq7Rr=2#*{G&F-Xc{)@3Z88kTw!jd(OsCqzpviZ;nc +6mD)Ud;(JwFbgGU(3}%GTWs=iOf6M5-^_>dJeO@CM{q7_exxnZGiilzE(B^0~c?Ql7;214W9@?AWO(j +IMQ~15j21p(4f8iLpt3P|6psREUb$~2!d$LVR2G|xr8Dn$0li5V8M*wFfxFiNv2L3zGl_4(uMbj-fBM +lf@4W%${k~&lm`xssFh98x3X!%j8K5Y!?gA+elo*AuD2;ZgWO&ERd~5&(XdIUNqiH;yXYT3g0WF@nxn +3;s|?Fn)o$XFbXGi?!0BLt4ZaGPY6jq@OV_io)PfP|aR0y`a@%EOrh3%dyKz{|Tdu9?6yrWS(RI{l!K +HT`GyG1oTF_kEp#NEgE>hz|?4d#3{SD&V^qycLd9m))SYE% +etB%6awg=$-@;*MoTXTb%{aF+U3^|7&n3GYPv{R5BR9LMzu>FXIkYreVYKmsw{$}NjT#l4o6j5gee0d +T_Ik_H5oxe%JptHaY=ezCR^0W(27%K#P8O~AnH@nPoTFLeo04T`}BM>A)giB(%Um{Jl|z422_t&pp$Z +UiWr+76Xs-`l~6$7c9OVm*_nAWw{7N+WxpN11bc6Qj!AK3&03l`VM~Biu`ZVhBhrbM7k-ZkT@Y1GHW0 +uxZ@mVL^uweCIV?XPf>kq0I9cjAvl)?!AYmN3H>8BriLZg#g=KyJJgVKqCH<6_bE0Ss_};L_97`;px| +1d80B;=zYLiIT+ZERFU8dr*vfunijxT7o1Oy?haWL>_P@bf#8*95^{u^oKW)X#=VS{OEq@?Yr@v8A1) +N$k*)L~rYc7WA>I$PQ*?zo9n0N0j|uTULmE&N&0j>`c{b^h|B?| +^)PMT1GjQPkZTnE?k~8co4Cd3Xr +uIyq76Fyd&?!=W1{{=a?%wT9Yamm7CWT!FCQ)4rWCZn9Bt2_vhs9}2(hG8fzfumZ7W#_I44NqMBSz;v +Dn@SqEbY}stiW4cF~taH;rI5beq)P={X+0cgOtT1K3Lq+du*uvV;T=w +5sAzb^pY4i6;#x67^SeKCnyjX$HB=*y7KI9N;1M1c1fjhk`c(`fN3FWxpqN9PPbT**@bjGq_mjOE3qA6MxH6G^6@+~qY0lpO%qlv;wwL97dJ-Yk|~R6g +*|87csY3cU<+L+eKDc>9MFeF^wzJFBpZ6CB1(dRb*b>seNE36D5Xojb0#BM9h1m!@*BSAQ4!l4W|!6E +ur!#h+m{B#bKJPJku}#fH#e44>XIpQRynq(hSbZZ~ns09ke1Ve4XUV1mk&^RjP<)=uvLh?v&;5DAEwo +3Sal7f!8oAXDAz)vzw2Fl(mahBEg0Cr$#Ej|%+a@`mk=R*_E81}?`MCQxz}e>O|^+EvFwZcJB{eY;pk +_#H--+QUFQFeoSFs4|VhaiA=O^PpNh=FLB#d(DfinJ|p78Pc1YsSBaoeHol7Sj8x&Dje=FX1knj%=xM +~gzj~rT+54~cC6Y;dr@gTmP_L-)EUSd1=qY-%tE52WnIx(J|ssP% +RIP*622(M!nXG+hj^6A9+sZsL+wf(P|c06jC+L+)U>?wxG)lP)j@1E~gN#c1UxNzeFlyYo$SuN`&RKr +A+R@P%jTc>nAIsitm#b-d*2c8tepvRvChqTNgfaps+8p?hr@_#DNZl0~1aJWPz#e-dOU9OUD|l_3Z2R +USy^Gfm*92=p*`-{X+DB)?A{pv2JxQ^f+%Oj!~9Ya&USR2|0RPobnGp20i|#d)WKM}C +j0lso*q~27EbNBfgOV-ffx^0!6ps>N;G~L%t#;A94p_4RitBRTM~PRw9G_??R@2BzrIOK(D +4erGdNFHr +e|gH}1gZi*#S$l4wdxP$szlVVfkC$6VB-hf);D*gI_?zN#n8kg9DO3@`wWkCWzh5~!&)f_5s!_$QGhF +Y6^zU%EUsJniApnF~FHHLl_k)0JbB$-oO62*}Lly_$QpefJC}r;yk;^3+0s%dJ8LIFx{Zft3YIK0A +E^?rIZHQx9H`wwoj5Bc*a)_yJ&p9HDx#z?s3~P6oGFiXw>d}K6p4BdO91t-}8t>>mi3lO?W8BoVtCc5 +zlOYS~9;Qr~0#UWO{9DE21KsNsZFQ5lT@FF^Lsf~Gl)>O$d}SSCHh07zPI9O=JHc1hxaW=iI1~eM@tC +d=i4`qNtXv5{X;~1`xXb-Rw+yVSiFz+kOII~t`pE;`E7d2Et2+P;o{&8FYYH1Q +ANm@cQTOt;;`j>o|w+KrS4P188l +njR|VP8%>b!2L%fWEPueBth<;L&1jeG4vO9b<)jc4;p0n91~XMVM-(Vmra_c46=NMQ4FHQH +A}uwxH*bHSdtIkY{@pAbi4mjO5K_^H*htP1>M#>)0z0OwE8>A(C|Fq5<3W+;cQhI|KLOnXHP&1aBs=|C^zM}E)!1w +r~du>?Pto>Pv|4nvi2z=IU^UYPjte-D?}}oL~r)?qH!P{24b^l)l!dk!P#-m|7vxVcKOelCC7M +;G_?>K6E(;vNoR3ZKz?Hi|Ao<=zEYWixAU7Q&4VmA@V6UI+Z|QY7W}wYm~d43D?ra$2|38XHj<{IE_l +xr?VwH+ruF)0nFU<;RX@ +aZv=aa4JdINI<4MKTtS5t8^-0X7Lr4EjY_xg#nT?>UMG7#mfKY=JRWM*rwI^iHncdFF!4>Hj1d$83`{ +RchCBS!mfqvQew?$MtAPjKHQdEu_i-G68S;_Fj-Nr08yAH+Q*%=OC9l13Z&&TBJJ7u@Mg5oarsBKXec +J_eOzA1c96rGkV8^9Yx=T0{WGnAJ(7kqQ{G%I>!E>a`6L`0ZC#}tkpgr}TdUIr&rwUvbCoYHj# +kQ)Rb)b74=D53F%n~}Jrb*OPL#*DNeoPCs_$L8 +~q*xBS1s(cYG9%&z3g4mBNoloY#bH1@TqYPcIAhj6_XFMQa!>G~b?L8{WFmO7De6L|15}@;Q%iS@!^L +1NukHG2f&3lk(Y-d1b0@(YCZw#l<=()h-%;gnF~^F76wvYml3BOrV!yR1vg$Yoy4N`^{24}0RVB>0H7 +;^iQykqasrlB6*C3};7Mr{rProaz2%S&B`&b|7z-iT@t`YLmxyra1nfV+6l1KsOj7wHSz?C8Ruos`r~r(FcP?(s$UN=>1Mu9vt8HeTrV2Gy}e(Yc@MOH}>Ldv115?*pk!A3F6rp;QjNQOHlCb+fR5!?mD!3cb +N%%{)t<%l)I%25P;bd!3R1%hEXfj{A=ZwvBE5gUn<)Wh$je4m-k#uBI`Zmat=frR)LSDSfvOTDV4CvMQALD@Tbt*-)_gCb(mhGMq6cY*s4l(j9?h^x1+{g4N +`*P%*{NZQpxmEU3ExMSGeovJobE>GlWo36L1g#`fM8ipHAuA6^A_u4^Vo$ZMemD-X%vA;!hlDyF0F_q +{t=57Wg63j{!tVo*lR(<}s+$YT3Lxv3eLvQkqtU)AgbDCR{Fsf)$dB2PP1uTLSx4j$2SNU~xuMN1JJ@ +N&vweG;&*RmD}$xg8USpZ4m+FbsuclTO@6xX`_I=a^m2iJC~3YkAiEO-KTDKB<)FZVDbkXy^;r^JyPQ +X}Zoy|qqb@#`nL*TJ9+g24hgHw$i6i^5Pyz&1#uP`cI3XSQ7pf +*s@=pT9VoZt3{OiUI9$OAJj{Y&SftRyt*-JKLplu~r>qo_)X)iE<$q6guO_5>9k@f2BsS(gp8A0Desl +#xhuM{Q%X?9P1-}?>kp#_FI)!srUsBs|*-bB=Ie*8Y|g-D +^h#&^?Jp(HdcNpw3+ga~Dd8!H(S_$603Q5hGUFHG48HdBl64#EI^;k!=rZM>#!2E0R>mkg1?rnItvZQ +G$7yG)`>L;hygB1H{}LIBFcwy^gN7opk~F?!6m6;~XyXPPW^tS&1 +^(pm19`5i7{0C(*RJ<+`m%8eV2sdNk|14TfU?HJS+5$t)w4ybghQv?k{zm?&=|#TxJ +CN9ni~?k#R-g&kncG=|`-r4VOQQnOxP4)KU2NMEBY)W16U7t41CE(NR#?NT=}V7Ndc+gmYcC8dFcceW59VdAi>cef4 +X`~2+uJVTnrVrW3irU8^p-yLME5#83gogHefemp8|7Ch11*aP!+*gq(Km`N&27u>AyIf}%)4&?fbMlF +NCo#b6(sKAINd2_pmx{uK6$jPgwId#3k5|^eqL=wS*2

Zx^;XqSAh4i}QN_Jh0Ki}j|LmV9IauG*(S5w22yr_6_hLGlnby_nRmrx!p?F8$8!AJDxn +^%6|%LJ83h_XU{?v%p~Ho3iBPStXKE9z&xtQIsVxchle<-_X5oo=Kw;;c~yzG{wSWO~(c+(1*KQlByd +e|7CUgbkBlhxRIms!V}%=f<>J&(&~-eZ}0fxPe!P{A;gmquO<92KnXd`TbAh#`Fzz)&sn&H;ZZ&Bu~z +b)*ku3=x^4D_iDH=jPj$#=vM~M=h#IU18Q4Q9v?Zwlc=w7#@ +4g$owTp>F5dIm#0l&6Yww{aWYEtYxo83Aotx>o8`dbtzb>qdNQp7|!*SjV4S-a&+*abgdb(o~{l-aj+tF3cL^fckag)K{D5585{EKPH@+yZb(?e7f+`-Pd*$#trpI%?Kp85c)qc +aQhILlD?>P;o!QD-5R>11?Hy6ElviyU(SK}eO1vk=;VHJyy;)Z#a3W@k +RH#!fl!gr;=AQ +0$@Vf1N)_&C@`BFnbB@-2(8A@+jVbaro*({cwOBqpp~6Z%&tT-bMNUbq!G()uW8~HSY@5t2!%46N~BWW*#KzQ*1@umaPVa#qtm6Ub|b*)Hp>Qg62VsAnZCS4ItkgD +z~M0G$LNCI&Hf^0d^lA``s@35(}#oy&D0oxyv6Q-C^20WY<)-;Mom_#vT^k*{VW%WE=z{_j%)Abg!F& +MdcP!uWm1ZEN!Awv`~w>={&0EI3&eaRcHdGcV$%!TAe3$qI=y~nhT15!9Fj~jsZ1v^WNH-BRX}ngi1d +cdAEI%-uIz?=Tz-b_7K)_0509*Id{Re?g9}49-t{T3U3VuH+(q#Y48lJUM21-H|{(Z-RodxnoAzuvF& +bD@kGu`XGxQKLW+jUZpuc=E9tH%Be=1%&Urf3y;9to-EA2zNEPRvKX%yALAR_aJ4X!0;c+JN#J)%HUa +p_J-6hY(s7@aUqi3`{_iK8hD--2jEU5COC=s3T2#E>ES9Oaq1s(vZtslgluBVFGi@ngjI+zy`0vsK*TC&S%^7=BRWaH%iR +Bq?Q~6C27?hWm<#$0m5lCuooFS;O;SNI65Y*WuAHrSRx?yYMB4!iyRxdgMkr83s>Y;lY8(Lt0USF+6D +*z{1>glsQe#H0pf06W!}}8Ek#h;`uF>?X<>Nn){#)ai6ezOWlftUV3zkIqn08`Z$ieUH0Qxy4^MK+Mj +B1*oe5ns*i|!X(UF>4xD +O3*`Dx(?bg#?WhGjYY&a|?%DuQC_s+3irPS0J$D2=_avy_erXRLg#s61<-d+lzl3^%{};Jzr{!}7bIh +JAzk5=6N1PZm{+4`1-V6*rfHO~XAPj^JrQQyvkp93p(D))jKLYWL(EL(fTY_cc(%Q?WciVQ5_jara0L`)dG(B7jZt%nwK +3>dNhR7P{AtJv2&5&6yWifp0;h&pJ?}&IdrqR!96XXazA?A@1C!lv +dkMi??6uUPDA9Jw%GmjBm=1q#l4vi*paA8>gribd^U|95};xx!YDa6Sco(p?h6!=C=sPF0O_>Oi$wN0 +?l2JBsh_g!ICMmqQ)F*dM+Iu26*jvyWkSVIdHN=)`8S`x$(McZNu?pAwr8&{%)sfjKR}g=wXw(&AVOp +3HLhI&r@0af`^0?H)|SEv+W+aF!>ap*fkIDFSp4vu=(rO?<{n$4WZubb(~(~Gx#0bz!!NEIuhsso4w# +0H%b>BP&syY!m$IvLlSNs$U^rzJ;S#|%TsL+vvqm=Het;3g_gI0@}%hAOq3ACu)A`3sN=2?*Lf=o-Rt +n^Y68{pQ~)T?b-9CuEjA=OlbZRuocrd#SmhLqtz=v^EEoT}+Xa`nZ{`rT;nIoK%TVZ!en4eMTRIuvzU +p51C$dIXP4l1|cMM;pV_N85r)S)Hbct0VWPIHXg-~J(&S$cnX99$JcPlS8qGkyOX&%)b5X!9ehVFIl? +i=)ITC)X@yp>H*5$$n_9xidHrtknA7Y7iILH4LavxHf^=j!gqsq^zZtJK5jdFDzPSct=61n?qj>W-4z +|M8*}?z_~PzuvG{99rsLm#fEJ{)b1eBUbQi%=&;d5&K0-yFvUkLh%IVw_0U2EPnZJmwm!lUCv|=Z_H# +P%%x_uE>A?(#M~OTBuPmqhO?!&ajS~!r`8*~*C}h};neE1x@lSn^5qV!O?p%j)TjpQ0i9*t9&xRc09K +W*f-`)xzu;O=IdPMr^#i#7&OX3-zwjXB;%wwwrP^Fx;Rh}(5a7FZPv^~vVlWQ->j`Jf8xtBzKvdV%p> +3Acbvd9-Lbj(ec2{}f)TQp#qr^QI1;%utBU6-asM)tm5$?%Of=pkEznwNpNdF4rim~x*#lg?g42}S34^w49~UTxw;h~@b4sd +AK_8DwHp;>_^!YT%vSsLI7un<05`lTF|WEbt)1cm8xk0MtN^CKpJFy;&S7N$ymNVIeY@KQmo)hY%KP2 +pa8BJD`ChqRatXL}rB3zJ42J{HJe)QuobWuTyIsyNA?a#}oYy5zg^EA?nSeUMh_LJNZSK{i{^r4u&9F +$mtHkH32JUv@OW=1FRq^J@ATWjfG73xJ67vkUYM!C9nrCGr$sbE+Y4~FDM%AS`$RXnZp>r8-^ME0n#%(RxLp$rh*4@UdU39M<6xnN_ma~A%arsFw`a36}mczXZYG2&6XIWGkE`@l{a +Jx!Z!6xhU5AMVE$1SKFDwkr{+eA{aJYvah=N>ZWDa9UsfTX#hIPdJPUld5!t$$!^Z2AY!vJexx@8Q7^T->+hNA}IuVE^toX^3Ha($F4(`;>h(mQ=9OaCrDfphlLKxT +0*M28xdZEx&GoQIf2D)su!=2X&fz|6ma8YaxSPX;g(|k~?H&houT+$mwO8`#K3!J+)Xb +roLiZ2?!_ev+!4n_i0bH4zP9f|@FMT!pOCDMQflK?*xf^!zwZ=n%v_Ed)QI2(2o21(1esmF)sI>AzV+l8c*gOgbf+CR_Peh5~(UYyd0_e%v3Lr@{dk +sm-IwkaO*E-JbxqKk7!!{gl??8O>46Lb06@Fb>1};?nJk(Nn3KX7r_TuHJ!e)OxBZE*eJPy*vhcArzX ++F(uJkC^d1-~<$C}Fk-fqRcx4EKv6d0XImW#?6Dl^Mn$7CxyA#-LWRsr;~D{;s!tPA+q +1`_N3N;y@(7n#C5B!}chB{8dNiy$mkQT#**G((7wi6V6E(!r*?n(7%;pyR?oxb$unse|B9$3=+GCsrjR(T7dIQ`jTXn +_d?_IXH05HHj&0Kw<(p&X3|H~QFydT`2zm(!?W*Lov@LK0#@I0#+NGAxErI1z;R5Gb5i1M +^g=DlN3}rTZDhLYM0-~A=~BzXH*^V3T_wV3y%Wf}Ty?uOoeDl_yx&7+#?cfkIBg#GsCRGbul{fOIjJpcnreo +Ezg?h-{f%R1JZrGB3nM$h<#LU>^72ZIspjEASB0q<~N;Zc=<%3xDuuqh^>(SyUOg59gZwx4Ll%m<2DU +U-Mg2Ynk{Ik*zkiI6O)I|Yn?fLVeHX0X>Hkn0C(;((`!Ry$P##VjxR4sNSCi3eALXds}13Rh6Yism>R +-0S2DLUBCFYpgRP!5REfV>ZM|ABZfki7(8JgA^Xs}uJF#Vjwp!+94k(W_jVAyb>i=z^w(Ep+H>|&^Q4~55yqhvcjB$2pW +XKpjsQ0t)f??2^6!u@D5jEQ^)~=ihWRW56a+y?+S{oL3K4K5C&OWP~8Y>1OZ_dy-w~46tleKJJ<>wQN +XzbWJtgX1duC0ML{eHVoBim0}eaje}fb+K?e +L<2Y&Ai)qWfp-G*5}=m=SOl0NKn(!^h<@Gkb}?_*iv9-$U!boGBvOG&BPc5eCCdOH2Us@%s{y$XPzpg +>8>CnT7S4FFD{0u0n_0XY}wm;$*{z)}Y#vKXa^3ly`w@D5jED +^!+(szt!e2V`)-^#&wi!0iR3Tfnjfgi^r61nf(UxaaL+-mn$&`Y=x?I}cM{veF=H3sWZ&n;;_yQ4v8r +jGF|?K!_Q$lxu-vmKWYxyaX>?iH(pA2I}Kr`$Ry`2WQL#$G`*%o!~r>Kra^@cM-D`P=R8W7vAAYY{i5 +E;b@Sy2jYUDI2}|Cf^u9?(Fp)yz@Y>wR|F+;Vn?f1v@l@J%_ +=r!az$B)QkevMW~geU6>Y9vY@~lsD}cTO;FDXYG?t08DwYy6%_J2a2R0*Ogs)$$AP>xW+{>b#VjxR4z +_}hGN2R!Ib)zb3>0*M{3np)glP;#=Kx^`CE=jX8q^%)KAAaC%<{rJT#2oi9+23Cqzn)yfC3@8LEamrE +Mf8h&Y1Y61;FFHUh&CLTUl8pblUY;+LZs^guDo3-53xwn9ZaC^`pK +>hvOg%Z#c|^j6tleW4p(9;F#Z8q8L;I6nHO+n0TC8tTmkS8NZ^3z47kX +EhK%FJB`9Wj$#<|72%`W#hg=S9O~9%ItV+Oe1Z+mY7=#o7S$vSO2ibERH!eXj%M0&tCALDU7o>VYHWp +-KVb(L2WP +3S|9p-nazCEHAvnmDmcUnPAUfP_Yja5KdhP&Ql0>C$Yl`z<(8i=X_+91vwm!O#Cg?G3TTR~GEXc$7;34SHmzZ2}P3HH6 +G3F%fKKhpqS-_ceoN;p#l?7et}FUP-FxOgP6kZ?^3re=JZd`(5mX~}7TR}Sz$O +ZzYIUpQ@8gx*t3<{M&eKDxq1(myyxqx2}sP$MkEc!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJ*OOba!xaZ(?O~E^v93R9$b{N)UbLSB%O +Fk%${wU8!x<2jf7BE?>f+C{Jjy$FS;p*Vudfm|U{y7)+Ii|ESJeCb`4b>6rbiSjMT?N@Xu*!{6X!=Ii +P7H5&E6Z^aaUguA({yLo#s+)tt{!9z|fO7G_U>6=te)RQF3F2t%FO2WhQ3|{|sWcRGU3zLX+iOx+6S{ +@FaBp-dNO^CYMDWLVKMKA+#Srv3lO378FNG%roH +20uev}$EaU!c5nxQnsRqAvZ{Lz2+n6?%}Od?*V*50x>tOMT;fNS(x} +z4_4V-CXxR-t>r8DI#w@G??D~j3G3Kb)@-034Gh20WUsvJ*PaucrtIg3)20UdMe42 +d7`9SmJE{3pmK;vfa56cboJs(59=tHsO~GK5EFbQEIf${4YKLWXrsrJwTXs5`U|*?LD^tR`W9&$;bD1 +@^1(pRSqoDO#V&|;a9mlF@;^Dbm82z4p&JJJEx@^Qw=<5aDonN`WDt)E+2dw}4wi}&45G;11NAN6c%Y +NN7a;-(le+snh_g2$8+;F{oc-Q&~P)h>@6aWAK2mm&gW=T1X^bPAm0066u001)p003}la4%nWWo~3|a +xZdaadl;LbaO9oVPk7yXJvCQV`yP=WMykB_~c)=|K`0P+&tI|NW0|9$v +n9_xQBEeEo3$=H2$P-t*z@=Z`*n^YHGWKKa}Gzuv!o{Nes-d;E5L_Ya;~@BjS%-P@Nhez^a?9{ce4=5 +77+>4(QB|4|R#zI=RIKY#gj|Ki>KtL>YgeByuosuxc@>xZA}tG;`;{o<2fZtc3xdc;3``-j^{uU~J^d +GFip`Tg7br@!96S~L0N@y)xZhi`tYY5wBvFaN22vTc8O@$~Q8mk+Q1^7Qci_N%Q%_-=dmxPAH4yYC*~ +yq|w9)$50Eo?blt#HxM!bbr6Sef;*_-)dmL*?xNbaeMjV&GvNv>f!Brd@aPg?Zul{zkYnG&wu~;>fzg +;_|cDVUe$CM^}GA0@8ABshQI&(kK1SWZ)>F6@9*E-Kh*#;Z|f&p|FHf1ZSS9Wx7A+%;>A10U%UAOAN*wv`ls!6?Z(s3pZ +xG2F2Ubt`f7W4<72<8wXeU_18bsxE3?|Zx!-<#d;jf^ukY#!_1^8@o_+lBXCOKh?nN0e|@P`6vHUpZMtGXP-U$`cI7hchA25{L`<#+J5)N +^X;SU%a5La{p^!Je)iGx?aMzt|MH8kKK*dpzPi8vd5Kxff3(Q|XNkY9M}GfUEBWgF-HV6UZ`aiSRNMQ +u2Kf5b_T7uW-q$w2yniT*+Fq24{P5HN*B-upeDfFQTOaxRg8pWE_;!2q`0j4|+tWkYPFdf7+1+}|-}m +>fjQ-_^cU!i4(~CF%{<^l{tNQrw9=@$d|L*nUJiT~{Exmj3&FlN+f%P*cSd;sYFP>ig{MvR`p +MLy)`|dyIF$WLMdg}J8U;WQ*|M0l@n}4Yn+TP>+3s-;tLL2o$-{buGh4cLj`>Yr0k?V!_;lBU;LU%aN +UfmNqezs;jZ9*sr_W)`K_l%2BVh^QcMf^`-4Nf{)b9&NlA08qQs-_wcM5>t0W7S>uY6@9a^}pEa0T!!c` +St!8$fHQRp98fMlLvc}a%ulYFJUXK|qYAq(uZ)et!j{4#;Yhq{Cs|@p2>s8AV{bVtEJz=jA9;4QIuMh +W{I4_(vu3EWqF^N%g+D6T3>{oqkXOBjGXU(BDWoy~*+C1y4a?~4-Q8UY|zir8Y>(Tw{^_{h_^*NS?MX +I^iV`i;u?a^KXPBy*1^H!71dSg8`ItGNrM7@bIB)dHCB6$92%)6GVGreuA^&0ipnohrJaD&A?G@Bas= +=>4&;l}sXXljXjtL4Kc$_4_9snP6beO>Ie7DsJf?F>&X3rXf#3pws?W3R!M(Ko)H!7=s|o4~|dTs6Hc +J1objC$uuWG1C>mfUwfF3C+!GwT4-b*#=u(;if)UA87|Gu-61?ziWCO`>n6Ki`qywn0>2dC==*>cCbk +0R<-t+&BegL|)`Fav1?Z#a*Zc+D2_a)MM{*$HZB_L2#(JS>u|MAz1qhjSwyr~AaZN$i(rJ7|EZ7=UEU&1GAG!;{@HUjL1MPB&KUe;E=jDy#P;PeM +0tUm&;PE2bMOxxkk*D?%4X2XhnK7s5c+OWbs4PVh%U3T=U$(Mzf2anU3Uw>R>Uu6!=kpbiBjYwZHj3= +CKO2vP? +pw6QuVWFMh)W?%UnxUi&Rf-Z2Dv&FLM@lSnk0XE-a0~G4Ds`ulMYD0MUlDbJa(-hV7h*F|rIyr&3!d4g>+VzAw%)twAvAr2Ky9w**SxxYw4IIn` +QE!rb7S>WA3LB=7S+GG+scjDrw5lMP_c$S&o@k|h=s%Hidj4ts*g514HNKPMi*4Q^7RM@*?XIAm1s?^WO4HYJg%iXL;>L40`WjiKcCIM6kHxt +8N``9o`jPVrP5OnK{+l6IyQc=Ywe3@WJq^$Q~THSb6Q@KpPHIPOOE2k6MVqQjw=9U5b%H+z#*tZ)0ZD +Y0#5386WQZbPc$QVt#Ttn={xMn=u#czNyKNd!fNn)%AmKp8DCUzNIHV7&QnRk+~JCS7@_+-brS(T{+; +12-D(Sf6<#)x4TDrDm-z6T~=Da}~1lf}u51gKums(?y_NZ;If!XUNcwvDwu!8`S8*&()+WeK$%2L%Tc +V4|eHq0OEzL)+tF~OX74V4z2CM9e2D*1TbrtHy+ +r{5>qq`qzKowHa)sbvt&?IGwC+iwH=Uf5&_oKmsML1S2WC=v8N&m@lp`G&c5U!EFlSP^k^T~!9Tty_l_ZtPyg|C=@ +7-c(H`-904i;9l-PnMu!dK-#66H>WsI4flM|s$(DAG~@ud7c~UItO7p@WERxSU~)NInNFi`p(WYIg(p +19PsOp#rW?#AJ>QaDTF-r2IjQtnk&$b<~?gkp_+#mVOt73BE=FQ%+d_G^pqm!i*g|JPsf2*EI?smYs0 +lsRBA5*$$!ZjyVHIS31E;cWZQ3xDo;N6DGkhw<(yc5e7)EqDBYDP@f$Ha1yF4h8cSMiXFdyu)t3VTUmg8iPDmS6+dKJhhBdIvC}ifz+1UM +R1t4w`CX9MO0U?12s`BnGk)Dp@Bn<_32cQjf9$fac2i>ij7UFwHe0IVJQnj>p1TQ>;M;6HpHlSzBuy0 +h)>=;4k9}N@8rz^&9Zf!9zG^TM~f8!DV`=9))1>5F7qWa8PG(;cpMstRP&^k3~D_#DM;@lBpyOKLk@- +LOysH!XIuGV3cl?!>AQW4O+#uc$5NPENGEKO4~u02gnD|Q^trVc3eSrgL-^Y-ca +vXaDYJ|_SJ^+9+o97n(K1|G}$omP3q;W!3DXf5kZ^KGq4y6&vHNV@??LqyO7jyh8OZv1L6bu#%?+x-3 +BFm&4LR90wm(HxjWD6b53PZeJXze!LWJ?-1%RsCcA3(;Ye+V3!e-1ARHc>fW&|iec);N@Q=dg6Cqi>= +r=3Nh!-y@I>>v2j;tYL^ciEBx|xGpPas$y!~<0OrORtGH7CJyU_m&3^A%2De9Pvaz +%UjsLWmSWK=Ul4rs4B>-`9z-y35v{aEMoJx0)tH2TY=2Xu*u~l(;0$v_9}*Fxy +Ek63AbWT{|{?5T|Fw=`x@R(1ur;a!eo-LRus#;A*<3AP5hT*dp3=tD03K@K2w>(%|Hq7IO|!IdOpy0D +%YK+$rg>cCFS$Tl-BsgcP;p#a+6T?+Q6A{lU8S#qnZ5|bGHlAcL3xO4Y}kEY#2oD3eo98U0tZ2hWPn%Xz_*yZ#@Gbk1cweuy^%l0A%>Ky0%8y= +s`L(Epc#h+85RIm9;3bvU^lJQAZ(9-6*+Kqh^Gx+qCQ8>ehGpofy43~I427hOmuN;)_Ma&z+OYwqoT) +_f)cw^fo-ty4XE2Gz;kp9YnWaA_7V`B#6!Lb+5>brs8+G5W{!%(L1Tm>#HQ~Bpg2H+7;4rD|*KHlF%4ssAvoNuL0nS`%NwN +g%1wJ4q{Ljbb0zQBdRi~J2my2{%F-bSXZLEacUXkiPCD3hQsBzV?~4j +(qU~1UqalWc(~PGyC3DU@cA7}u3ccMs1z(2f%pSx)kHp|rV&OBG8zGVBasA#e5+t2*vH6-*mKcFAZ8< +rodWieU2bH;816Sj0C8<&rP^4WMn&vS#2fJ1^({a!f}IrbWeT|1??b+arK+VViy%-E*)K?TV17LX-wm +kyjdcdhb~wP!idS|oZ(Sz11Eqmm`>@*8K!IDb(6p^ixh_*(VA!^JWRZwFHF?uCk)Gr;c_XIUVL%F?*< +!=+%+RNd2Y*1EOzRYI%z)2NJSBjJ1CFLm2`b`fGf}eNorHRj{ErJilEkp?wf9zo0dUH5QB15DgMW~up +nCc#OAPWIvKE~pkR{zjApj2eq-H;Bv2!v_)M7O~To2A2CUL`TwrPl_JV=twVHvy}j+oM{y@@swY*1Aj +{9)w*T*@F!u`;wYA`2OGYqC01f|!4jATF3Oh}aD*yV;50XI0)3^Dj{@X_Qt?1v@j4Bmm)&p!+`V3`!X +}Aac)cK?bJ7p=l_VFWVcXpfQ`Bh8zME8`Y%hI$d*aV;%B3QXqMu?fV)AY+&FZ} +x?P6uF&L^;580bm~R97FKhG3-&J&Sr3+8tr6=E-5p*IGn(V=O+(5AWkUe$F5JxKpEz2)zD7E0Xh-l)- +j$ADrpp7mDgyNOi5~Hizy}CIn{MVOX@fvB(-YAHc1iy?XV=JK|`)+G$1Nw{(4sI${vuXJC>>Frvt?%F~8u!&|`kUs=tHJUqZP1zAjCG3|0($ElLQSFArt0(luvtr1(>cAEawf7?Nk;Rs$xcY=2b&$v{ZXm +pNWDwG_8UNG2p<)2#>*2RzEKiQP>$G!D`R)1Xda81%B}9yOxiU^Oc=0WK#E6ZRuW +5P+Tr?>oSsw=Njiolg_x(uW~v(LCVoj&w#@UP{JSpb^vVwOmYJwa>@Z6RB3{lu~flgP{()M+hfRA(Ih`iF-ijPf`j-$P&_HNh%TE%Q1f +MaAWZ;5ZCRn62n0KzjzXjrWE`l;9*YyV{IvMBMj$Th%VW3wVTnQrJs6?H9|_OSW?27|9ig3Lv9T~v=s +OxfqDH{q_LTxK>_hOUv;eO=l`*{gu#>GuChP~{1*Sf#UDu4t9OOXb5Cpp#>C=)(FheqM9|={Y) +(z;^&r@?2$g_OXEVN-Lh6*gn(C_w|AnaEx$8XtrN~|_)2QxELN64PQYliG)z!j|??M!)W)eWRf1E)?& +r9)km^g%2507WR~cL`is=&5VtGd$4NdnH&l#Wu240EpjRrtTW-X!*B1a4qg3gCm)8o1S?0|46NsBFJ#j@}FdrU*&SPV+ttmc&ISE~M^;7J^&v_o8Xu+wHiN&B(tI0{{xbSLrffV#4E+6aoRn#QPNgSwO|wXg}O2=R91}|cN`1J0}^+sF{1_)IlL1>fQI@m5ma@+ao_D{nUpStV`= +zOEroAaE={|uv`9AEo1@t(1+}Gx3H*qGl1i}PiL)!Sf!-Tr`@)Bs$g)~C( +YNEmm(jPwDz~`NfBNyRgGE}5qs?$A(_%_*yyTxyC@lQT6&G8Lg*4VWq@-`SxApVLj?WL%B(9fnVLz?J +_hdb5PMvr2HRA_F>F1^Gg6mea4ZzXDUgC!MNpJ7yDYbCoa_mPy%44y4YJ +K@i!L_E)WHiBoe%??)jPeDu89K(n?S;*O~S!;OB;M>kh#KUC4U?6FPyUhR6|Bkj}Mt}Nf^j-$qq=QaY +;L0YDH*hT{gOR=?&2~*_e5sY7#@W_JzZN{iulIvbTHG&s5NKD|4IvqC(3za9OJ5AXlf+Ku=+-?JXH?g +c&wy00|xPtPKnNDYlt5)kL8HDoS%ojVdrKxy*2E3b-<)LtSBnEEY}XVQSif@1)U7tCAfj4&_2^Vl^5s +hb<~4?m+1!=Q4TPmS*Kb*{!MDroS3z)^KQ%=uXHVop`%R^@PPQ%?0Z5j{ap#TbZm%+Jm%PZ-eGqA(U3 +59!9@l^XoBK68MJBXjt2)eM16X2Wzl{V<_guR^Sl;wf|&}_nlcpo5u^!>xEu=uB_UDeheZuZaFek!Dgi6;nW|H?iS8Q#Gp;=WL(sDh9{`c4`Z +n2Q`n_9MX2zyBNhL@g@nMru9g2ZAy4Es;UD*S9N2sG(-(Cj(K^CfIKs3~)B?uzZv^iAjI!B-h=DhDxT +=L{NgxVn2Lequn?lv7EQ*6}ZiJb<`2L8Nt%PR#7`zinouvqOWw}Z1c +1t{Q>?eO@5Ep?@6%0K90I{sZ+!bXCKjIu&qS+|SD=Ao+UAi#ckumP_&ZDTtff_1wT_DS`m%2s*^hA-7 +cOF_z8s2EADm847^N-)XTm-0|4AzO7UwlWKuuol;+iF +&ZObI$8!;3ZHVP#I&dbb9#w@U%8iKv;7P=JDpL$T-Tz>(4pxfVOF7UhN}(H;2-?}t&@K+U)A2HVZM>| +#Uz;If@5ceu^~Tx{2>U5IOZ=fyDTuEo*>H&y*jC5DF`2=~O+ZcbU6SJNC3Tb`Uu2-OxS*_&bw%C!M1Y +^Ny_?yFHMr^GBVZG)+9Hf;_&+t{IyLOxdtFpyI++mVVdjnHg@M{*kKfC6k(1-lFz=75PG3dm2%az>*x +B5n1nhtbejYl#OL#}l&&nT@o!2zlBq98~kF7gP2p83+x6-ex)^hK_`ATkREQ$JwTOpdIS;{DouzXnXb +EsfZ7j-IfJ;0Dh;RdI2F}gEr?_OQ=Pm_`MC~`6#uAstclSBeOSB(?&bB*|CHiifOw}ogA@M>X!5|?5n +O#F``1n3`~AQ1F$i|L9=qK^E?p5mSJk0Fx7U5yGalvvu=xOVeBvzuG2DDs9KT3wkv^iH#!56JY=KA@S +T0>x2zM%j^NZL`a-0%sZEImA6P?=v=HJjk#??z88%10F#jo*6MTE#V%dQBP=)WMYoKby+%pRkzN4R +8|{yttN!=sg>op8o8a%zXLJbFkhUZV{QQv~@oE&0v1B7MI+6f<={g}I0Fn5U&IgoODA1+`qjb6sg-37 +-d{=xp#7RKn4H&gu^321-agsiYPCd=SmmCtw1QC@ULw%LRkFb?^*cZOC^2Cx?^OzyAhHBst%4~4f-Gh +T_JyYEq!$KG&6?Go7tVd&pxiDJ!ZJP!wD)!LES1LRJ&W`kW+{iO8n@}45;p|f4hbj1?ZSkTuhZwX0w{KaIl04`nZD}*}C!S)a(U+q*298O8iJo +5Nyo?2AyrEt8r^h`!%yuj%5(j!?TR-SgB-Us3|r&;seQkxH9k7gnNK8jGudF6(ZJEnJH7mbfj}?;l)o@Z_v%)n(L!7j +;nm%iW)$YO)WZFHrvXq;^j6-?09z|TUVF{sg?7K+{czUXqqK@#;sU=sJl(7d1__Ot%(#Hf(`#K70I-1 +(*Jnk8W4d^LeL2GLK0f%2J3Bf-@m2L`sS?hJK{XTD +${2isPRKGDAL45S&-&Yk>$wE4(sPZUR}&B-2A&wq=Z?!LTm>U&RXMWFiX4i$J>w;BLq3PM+1HUf3tiG7`!+rBqAoH +#F9Hj;+G$NFBF9JwHL-Z|d$qw$O%e#$IfrL}RoR->%3%#kXwRJ6SG9MMYS!1|`Nk!I+ymh^Zwrn`A6^AbR9cmWB|ix|`$*e*X5`^kL)dWU4{RKYRT{TY90!JuS-8*X!* +|7E{DYQGz0q39N`mYg{;7G|W#OLM9hUm-FUbf<;5!Ce2qqj0VJX|L4s8CcPi_4%+98@kvF2i +|Q%dlP``AxL#>0{fLo(?`8-1Gp4!-UhfR+U>L0pWignNFnun?ypBr8E$#d(8#;&-NWnG&`cP#CXHzVteg`iRqlakSoKpnbhj63`-b9itlHT4?&&4kydGCEvaIVW< +fcGT9*nWb+|6Su66o;IYMLGmOV89&e6`h-P^D=*M-_}+SO|ne>8~fhLAARc3+hy|t)_A+k5SHv)EIhy +qcPcRN!xu1&w37_lzieyONxGr>+yfS#ag|(Y^hF3?NlC5v#7df0+SWWgJe6s&0_ +Zk8wLEM>i5Z30d@+$X*1<9DmC_QpSa6P{PVZzR4sArY%?9S>X#=^IE!t8&lXnbDYWx9g3CA#+Dm`zUAUkhek-^IBiilW4+PrrD5A{!yr%lqzlS3XD +XK>PEr-JC+BZ^jwD9DALk`pSF*9lcl>Jl|n$^$byDY;!s`#?L}yJg_+;54WLY-pjGuqUNz#5*1cX;hW +teGDUjI|<_9QalWS5VKpkfwE#<@?ejR2}pZ2)oN}J(nhpS<5*`^DHPQ|;pDqO8y8)Y&dbi@iYIoEy+c +F=qfH4fuVFrBUhpA&cjvftw;9@9L(g|}+Dc7(Q#vFGzPh)}7GX|!YRglZr#E?=;t@}PSt?=Tp8c{NXt +!dR0#rbF?F3s79k8ip*(kObPfjyt-Ie1>N@D!3phN0*DaJC(nkG*MlooP81;s)5_nbwJEDS?O~&C<$;FedN=NpP+A#FiH2@_kruKu9Oo(bPNeWt1`SbefT< +G{lkDd$S&K<%n!uRw^bP4FsqGRbG$?AO)G7uuNcM@V1$>f?ut-W^U0|*)GJ;_*uD(vL>PU +_%izTjKv(^t}-=u4C0Fi3y5VCREGGW*&nKg_Q1gwsKEp&C1}#zlGei{X +9bBdI6RT`-jZaWRI;I7mKrC~@Fj)EV5~vYFK7x3HYI5C-cs(L6r3E>nE3o838vaYXpexYO7LvL5@sx& +DDuFADVK$$r{2M!x1fDGrBKMj39pqNsf9}mIy_-d0?EXH90y9IDMINuhq4+*a +|F^3^Tfb--!2geft9HFBVY4fy0j1>`Sr?-;?Eu=|zaDpQf{F$gxCr28B;1;k38S2$JvI1}jP}5`$ClN +WB{Lq1e0$`GRCS8FEzziVvBx=NTKD84In$Hmum}OOke6nI(u$s4k^v^ndQ +kRGu-~L~88*L=4JU9URRyW*gOa&TLTw_iO9Ww|dJK$`6!ZfQD_~j!?mTRmka!ctOhDEo`lhK8$pSAts +{3gO}yScPxg3O58sJT^z)~Jb{^*yY8v&`oF0Jig +9aO9U@S>CTO{JP|yI3accNRK7LX2bz&8?GT0_MiY85c_Elm=bs5ILQtUd!~qgk^(#63X(2Nf|_m#=FM +Gn$CS~H29t`^&6pl%hLTQ4;H^n<6}ikFPf1+?PD$Y=acDv>C5ScCueXicUG`ur{5o8lxR&xE%_-~sgd +8{p4+8`zW|Go%n%gLTCuw1t5m?-$@Jw`^Q;jiXW?btG8iQfCKmnr*{f)^~dEtd&Iz4<#!f;JhFP!gH-rOUlNi&6Afv(Y_S_gv1RHUealtP}UQiJwc< +1R3uo^+a!%9);*gk)2jlf8G$TLgYR5xfAV1x9yYf-G4u(pltId-asoY*Zfe3$Wtcb9-V&Jvi7;+9%vt +`-D;~_7d`V8v5;ivhPnqk1U=Mbb!x=$|mDrq7jUE)y3ibHzILt!v_9N!{vj$^_HlntJ*lSJ!dqEp +bqHqShUkcX^qb%EqSjasV@exrS!MpTOHJOx#PmvXB~lAWOBr0bJNC +JNh}sQP)gi4s~R+4*SR?y+XekhGoVm)OUnZj;Z!JLy*sJFIEO7F9vD&0LWZAH~C_f&aozaB>luV2NgW +#G2FORl_g4tkpJ!AB0-!pa~zAq=~?i6RbZ#7>Up-S&O;6v$^RQayKZFq!9Q{gk!;uCLQTK9L;Wz6N}e +-7z1*&N#Q(bkR=E+hbcziMaVwP6;um@u3~t&k8GS=Z<8pVgA#fUol9^D<_aS=&!XQxA<+}6wnpd|44( +jON~Z$JO2Wo|6F539=g8XQ1T%U`VuOHQ^CLaW{9!`VN9>T@M?&aYzPS)4o+z7372x4LgLHIMfg4!l8#=|+Y4H+( +=HqpX*5r5umMBor7{qjpKIQyYY0p`J+aSxPMVZo77n^ +TEyO4ajkbVi*9W}2n`%=uzW!%?0zSJbfb}$XiWhG}%$a6N5(wJXXSq<>7%|2N(SFBF})ss5{H`F5`rdlFV*k){?mh^AK>-oj~&)O6F +l+!ls6mtArgV)+U;?iZ&!9=#oSrl$?Y}?zovEInZjbKneYsXj~IoC6VSOM9Dt|~eHZBN0)4M-nMM@?GEDzi)cfgamDo8-p&(7j6#UreLTWoTmi$ +;)ZY(+$TfSi9f4Iv)|9P(2LwXK;@ph{n#1bjxaxYm;&OfBRMC35Jo9Mw@oPQXIy%K6 +Qh_?wy3~02ZG)toYl!Mv5HBqtX@cxv;=mthLw+>@DnaUH%-c5|1Ko$h4A~kWe^t1mT24?LMsZS4eD>{TJo@&v_2+cS1BHWeCe^|)$R``>W;DtD^p=g)4`E|8m}H6pQKC$-y(;Yu-dmoffj6*ovh-970r5~~!$4M&3JV%tgb4C+|X9|q7Y%|u +BHdf5^3h7Wi(l(utP%O9^|!Tmt)!_wV0rxBx;s0B&UR8(R9twOiz3}PY<3#-n`e3m<&ir2l&$f1?i^L +Vo1NOjwYqXRmo*Yj{VYDriQPfDXJx>O +SZMeGOR--!fkdK%H=hZc|G?!K0tLVb(e|O<+S_y>(=N+5Z=n}v +YH3S*B1{7&`xZ=OHw>+4L+qxagEUT}UeFAI#PE0$QP+!Hi4b1$EaLBiztG8nO@P;99r87Wc?J|`l2xU +Wnx2vGmPty@z=wW$c8jh!zwix(Hzhoddnz>undqI_u)o1CfmX<7o3@T^#DoNofDc+?5+a*#wm) +}HySS@~K1xEEgp-|FLC~Yn?rXU@-e&ZK{@TJ5K#w9ue(F|0$;iZkIY|!DIa>f`i%DScvXh0gp-4hz89 +w@XTs7yH;0)JYBP{5G)XR1X2#BsI4OnF~C(Oj3J4v*p~m_vUSQ~^PwA`gjQA_PTx^3*`Hl8ECbg~D{U +9&;9tOt0D5MWWL+B#}vt0g<4qgOHZiLB!EmCc>txKjN~ZK_CkR0?ARA^pcj-gWm+ew3~{Cc0%jq<((( +C@x$5zL*TUE@;zy2}mSCin#(yX>_I(ko9I#aBF$mp0HY!< ++gr0OlJ5pj29=jroowVYT_;xv8n6Wk4Yzf(kV}vl1a&!+=~(2+erP*BSc0zgOk*h(DKuB!7_WCwX9v1 +E<@C@_{u3P_f#Q)MmJ^+vGa+ZYI2S`W4!l2zX1>qeBD^$zO9~E6ok;!;fN!m#wA4w=Hkts6<{Tebjr)?6IRnUFjbL?%#C+SeL>8kXWtFwjjlc)F%Sb#6f1kgB|yOCErly;U>vSN`F1$|B1E +yz%k3NO5=fLA6-eF`{@5U8%xtC4pz4s+!AT&kC(u{Nh?jL-FZf>bDbc>?H#5Zb-qkm3&2L+;jfBqR$r +Y+!0*B#5*I@hZ1Oix9-t$=Rj>x(|4|IpxVc!sjilaBJ%xJ{UC`&q)(1alHgIB=x{;$SU}IT`E`Jo7^O*>fxeO>gTr5AfzM2iZBP1Qd3laoPz6Yf=w%OCZ@32It9W;to{+8{B=ME(OrTYKJ-p!T0Vr5 +x%?=Z!y9?fm+Y{SZvmbHr?c7)h|`Df~omW?!aG{WT?PJgguESYZo!8y)yh8;x!o&hK;dEp&75dmeZaKQN%U|wd>f8y!ano{TLDy-Fp1QGcMjt*1Oi +);O~HqOPJaG5>}3|O%GuXDZ0~QTX&?Z#WH*K^=h%95lj<5U7?WKoyHD9wGBD1#30Igy$uxOq&kW47Cl +ppeFQix7`2Kv!*78|>0&x8a=K@@zaS3Bfg?*A-ErEiGSFKkgR$*NTnZ=Hlxbdoyc^b=r|=PKVKVM|>>L}+f_a>yRxA +27mcSIbrkO^*RknUGs^sO6xnm*yOcKMFfO>|Q9CV|t-M`P*%%7Q+>0aHp@bJ@$X`nZsqc94p%hXb*oE +8D~PL+!VY}!eoqQk&Ydj-dEwH4Ny7(btY8tlv!B663B}F@cLG)eX$CZjNYtBz!DFWo5~f+3cPwyw9OSy#Dc +pi+42)l@4m|Bfg?|eURDJNT${44Lc>nX5ENFlq_d0eEXt`U{5o&jpaKhbi_9`EvRTshpIEoSI~9umiRQqukr+dC{#WKzQmYCo_BI;m<#1nVJplVO?Itk(2$8P8qDkm! +4`k^;NGwbT#-m0!^;Sk>t3OO4$nDHU1gLJUhrOl%%0_4EDNb3-rAz*XvUmYdBahJO99ewmnYA1ff$2#3ar +s6MPtC=H%O(~{Ss+NstkWmnoVEh6Wz$$+->ox`Qg!sb@Gz5vMs7P%i3QCYx{`J!b!OD*hs~hgXO&2Bh%G-7*tKaCEOxbKfu}yW*JA@JJUD$bglig@o5ZEFWeK#kP8 +#Q5;s}R5aFnfl#}?7y+Q7A@U3-W~Rs?G&c(0yo9ktDJYLbppagq>m8n2y!{|EEyuhjjn2vC){`r4gMt +{|#&Hq3n5aXtNaHZv40$0tQNm;>Evr8J#B;5`YX;L}MNfL4YBNvM`z1PJ(|Li!l6Xo|1en>4A+@mXb5zpLYfdY6Ma?U%c-b<>SPe2^D?U*7D%K~)R5_XRD;_H +Q+$coYyv4m-XEA8r>=@O1&;{4u?3CfvX-lQyu5zerFl_Fq+cdyKn^;~P1UOGdJA)$KH(DGKJfj8PKko9+{NK +4`FT?vzmWJo4Cd&(sYy@xb9)?s56olZ`BE_ST66H*^>ClLuw?{R_mo&FY_%i9A%uroXoHzh6I1$~He$ +L5%AMR;s)g5VG+cYa_-4EZeY_l${HUds~?-L26LeE=#mB9hYQ08yu>Bm8?;{0VFt +(kVNC@oeL?lR;_`YD2ciuS+KM_Z0l)4!Yh=HgeU?3vu>Bdlri^LG);5G?#*RtC&Srduq2yvEgu6W%3i +hshV2M{VHSK&l +_^&V6i9UBomRx+@*zgmsE6zjj`$;Fq?KcmbO&TNDMP)(R`bSjS669D(Dv#8mtK~rxA$3AdMcprRrsc` +WRmLvKHyVo82#Ul~fCRp$vGWIX&j&5dcXm(TdbPm?(&XvzzA9rV4ffDqKoqf}51ACl`bweaYo58Ax!e +|G)#oZo2-yq7=Aq4TO|w`J5_Uab9LC-DmUOHea)mLmjkxJ_X=1k0s*6I29-u-MkS80{qH +eI4@!6nbJ!Iy4=5!dI3F@g>&#F3`w0A&gI5$5`2wNC@I}30({x|IXaP5NFYUnD1Lg=^0vggGp^Hs2_E +Z(Yq2k$1vi^F@OUL14nEOUS872rhcWFD77#=}D0yIv4!azgE#r47T}J@Jsn1%ERxZJ+LE{dV2s@ +_~MfU4C}ig$rSd@UI+J-jj2d>p?QeSF>lCYr&=f)0*56%HMni-k;)TZ^ruo9- +RrZL)MKl-UQbVsffEm}F+#zew8=X+!(}uusN1dZ +bo!ogMsC5eIJPFD3P>FHqW-HprL(v|zB*p6#6WS@VAuv5@!-A+c^}wYthMxKCUR{(5Ob>tgx3>j(bc= +!T#&yH_I(SOngiW#O@BP$itN;ZX;kbUS;^FXzES0{j4tCuZ%ccm%8Jt46DVCLv^G2=9U++Yp%4032Q5 +*2ciU)x+n`-^jRU(~Cr_2I{2axRJ;`pK!Q!vGY0!E0R$|=+P^+*ouWpWW<{IDA3`Opn>F;J7hny#ilW4V+Vb>)eCc*#mF94`O +B@YH>QE2xO3S4dz=L31y?Dh{qC)u6sN8?A~oXJF>&=Tt6ltHv4*N_HNLks{lhM*XdldMu#iu=TJMK{R +sLFH2W=;88UFTO@S2nuIh`zB(Ovn<)-c6Xj>gpy97En7gHcr>ZDIm% +>{4mlQ0m`}L?lSlHd)^gDE8m6aMElR$il2hUI~s&Z^S8sui>;TfMx_-K26MK?HQ#ATr##;bBqW$AvzB +V>djQowF0!<)U44=h_yWEp|4uzT`ChnNe)HpTd>23bC@QCk$9HzayI+8dP>;Va@6aWAK2mm&gW=S8l+x8j +*005B&001=r003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMyev^27bQlvpr3DjS|kGAY=8h5d)lQf)peDBR@y4 +~v!4M&fYIZY?YXr7H|I9()v(Jykloi45RObaV_QVT_iDVU_A%KVT@iOAR;<%mU{bLvD(FOm7c&#cUWE +t!)16%6Fh*}GgE7@?}FwakT=Mmv1kgR#dC0MpXgQ#`jUJQuWWj)?EC5;kBR8eFya)Jtw?@cHu}fVi3- +QLGfDA=gpLj_orSCnbr|-pXz5jqSOcKM^6C3HzOvQthm)=p%ulCvRxk_`T7sepsXA)(YDMmrBb_&XoQ +I#O|pvHRVE+JdE%pbn%<9sIN>R%O-?sT|iD??b%lD?BU~lO;dJYN{_7BLd~+?Dw(5rDs$G3NjN +%$nA^WPH4a3wmI#dv;E(R!6HA0qKSmx?#_ip;K2pc$Hd^)J +NPs%*P85q4WiFL|dlXaapTA5RgmXCabTD^@`&86Mc)*G@h@X?vV?taf$|>kYsgG62OpUh4u}Y17J2vl +dq_Vhm+}K^%UrjC#(4=%V@kvDW+wdt|rNP8mF{er^`h)iik4iv&X^BYc5|rE&*8?SXrD +g?CjioxBTnXpe;E7@HI&mxv>Nt=zt+SzP+j#b&l!*jhbdYgX94qwrxYW2?O%N6OpH*DY4z7zce_ +J8>oM|wX&SS(17;6>Vw{if~aMvIDnmT1}6R?~;m6(2f(15ir?1QY-O00;m!mS#!glC36d5&!@%GyniK +0001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKA_Aa%FdLa&KZ~axQRry<2T_+r|< +8u3vGLKZu-?tmM>f>eS6pvSf22${Iz^q_MvFxm|AXk4}pWPp^xzN{Za7s5H7Vv6^j|z%FH78 +cZUzIFp(gRa-N!(*Y=8t@<#zd;9MFof +=<#R3FASH{+|jk3V58G>x~gpHND&Rhob>q$+h@ZNNAPOwVu5-eSl2baFYl`$*hhOzy7EZ*SGbyBjrD* +W;VJ$=UnM@r}BEe{=or_Iw17Gsdf!l(|pIjf&?WnHA6^TwW)s712M!ycP_mv0Ca!12abkF%m0{h*)jD +%Z6!@FIZk|X%+gDO6Dprs)1UU3490Mw_{yUY3)0J(?_F$dU1k9I)6xEf?I6ANai4YkrqWcP^X2hXz6r +}y~oc_PL78sKOCPZ_5K!5p88SeSFgV@l{`B*n3qMSMlMsV%3=oTVLb|=Gd#RC)ipo#3lZ%VENcBCb5& +GRc%pgDNhZk`&B|;=o+QiGrC!|^Wqja0(H#{R#^y(ew5Y0enr_H8#UfAs169L|^F^%}h8#uvYzC96Nk +ty4)zYMtTpTSjK4~2u>rMLB%u2JS@HMGhW)DbpjfIogXuGxC=S{~8*-LTa6%)e6G|c5zS!KQ;lqiN|J +LROq$?d!0k3YWn+wjLjWTby47Sg%*^m?7-aj~|;ljkp9(1Ocikwl#pErH==|B5feOh>~d|4l1?{&{N= +o-oU&1zd^<9=1G_j>!8Fr?4CJ4n5=*Zzjp152_VNr3q{euSP0@o_1MBhTP_a5?Qq_kYMI>?8+-rJekS +X_&1-<*#HU$6TvYf71Bls&y(E1%yG;na0LyX0xCXbA$ArNS;t>~JRTl@`P&6$SzBaAWr>ZDZ*y`iwqS +-TVd?eSAhY>pqN<@?nJAfasK<$p5X4DjS-Rl(qmK#xu*)Na{X$nY1cml?*a0&UF%$oVd^J=~Ba=$cs=O1PuZ>GG%V!0diT2n5n78G=4$GY +h8g!l!lbU6}4lmsnI#Ok%Hl3kC|*D0Vk}MdSxo-IqUdx{z$D9T#1b@HtueMe2Hr>RSn9Q{L4mV +xaOmqcXwVo#zX}YocSQ{ZaJfynyW7=vb$=P=}Asi)iy6gR#>dx-|WyukE_oVRH^hM-d)#tL4$lN3%Cvs`q+STi2(uqbA$N3fXMeX4p+_S1nDBHLmkc8?IsB=Mhlz@Aa95pFIx|ed0FiK2K2 +Cf|Hr4B(zNr>(tL#cfm$qaWPQ(lyrP6t5*`e122X$wU$X0-LpA)F4{AnkcDnj7)znNy($2a-#lZGFlvPm?dA +u=vQ^_t+>jy0=W}W|$eI9~bMg_2_+=sq;&Cyh +eS%Ha6M?E3?`GDBZmmmis5}cc#t&3B7s_w^R!8dO{M_|-6$he1wBJ^fvndcx1k_6W#L7fPFxdh+!LQZ +_ew}5rYzz*qOL{QL#bRtD~=IyQJkel$c>z&4z|rDNg0i8-gl)6k}A +}KbP+i9irN*Ic|d51$QBtq*}aPIbz0{>5(l?;9>6ypIxnNz^&!bA%}wcVPgxM$7Hz@~f>7iL$>#*5L^ +XvQe{FB0Bt2k6)l3S){5n82hAkujxdaLMHFvMGI!PUDcF=H}JfWr{WzA;#K}22Yq#PD==fNODuo%j9> +h3BbgxH)*v1&y&O<-p81;0Q>^nW$Y=-5L%s_YCaB*PN<-^iVP~U{%>jsvz5nv28@zFF4N0NM4p=9M%Q;TSTZGjg2Tr8)voK +n4n0h&=0dF9STVk!y05Tt1&?1(bh5sr>>$dt~YVz^&LVRUt?4QYDE>;p%mDM`NcguPHpZ0M&luCmZbf +)JIfv@{QsnSNjuSt_YPN{dtw@}PD?PJqIzFi>ZU-vfmXd}M4vS6Cwi^rHi=g+Yw}Nwu##V<8;Ieup4D +xR_jxFYkXDU#M5=_>0j8SMP47;ggwLGCiNlgV--=o*1{}>iv~GnENIE$^6(YxjvV_fAA~(gFm|kcei6 +Shy3V;UlTn03rRTz9LUfwx&G#{>83if9Wg~P&Ebi!=sXzlz&bO7Ld;2ifGkGHy`)j5EmHcAYYBHr^Nf +$C*hG3dxw;n#&fbo1?q5%C@5WbWB;1Ryvn=lOzw!#a#*i@&Vrf5<(|51WFGK#2)lLo${yDjQ59Z&VpW +d8*xW5`t=~d`o2bb^OOwM+fbe!_w;2=tovpP}N>r}@6%L9Viv6-v;duXM)zwc3MbkFIhvwqZF)hyz4d +Y?Hpx_t0TT_LM)uMwqxWeFm|RK5N|!wGxx)v|-uqo`Ts9kWmVpXDY +7PWPFZ4hkFuJMj@QFdyOQ;hsgvsbwa1*+ld!MKkIN~26q9C8S#Y3ZfmI!Tt0m%AolW`J)QfV+%EUB|Y +teDW)Gq>i@V1e|r>v-sAu1&yYh>%6_x458}qrAwU#QniN@ +*M?*E7d_|s1k$&gyWm{>DPKUCrAFBERGki*8M+b;gLSWoMsA45qxPfgVs$i7N9d(=wmRZNkEZnuY33m +eLjrc_C}_k6G7IjWND=Pps6FGFuTa4^aB{IGyeo*RB{eg-nJ1OY6tYMY^E)Y5!R;M(%1I--DD(;NBDXv^Q`MViWdj$Bl<7cEWnVB%1slfD{@ztcwv9F~ZL6DQ+n^Dd>MD&i_8hR*mnX0{Qhz)NO(4)GRLAr0l5sbxCV7`H +mo@zWOuREBf*={Fsmb7Abv|&B!%23~rQ|*+p%`ysuA8aaW`XV?97E?{BEui*Z0Vl+7wS0b)OWWzEu)@ +=E)*y(5)0x?yVq|_2&;7|eUk};A%!!6>(;w6G7@bc{qP&s0A4MtCw-1N?;g-JYOONcw7!F3B)k9rBo7 +>MD?(lP3i_w?+;L#JtBRsppc<;*vZM;cw>_Om@%OyEgSCY?aiOmC0woyuk|%sJ0EZL2F_pvFG&_JJ1m +vy?*~~*%NY=SB_oXgN;yC5bRlJ`D-ZWC-NbXckx{Kf%>CihNfI-$P~XGsTA_evwTi#RHi>y4J0j9L41W5A;_a?KfkWL0k5XOF}yoM@NBl&BZt=WO5InhyrEV2<yiUEB0RbvinGWi141GJ%sQU9(jCpQ!C?DQ(@v+`;-4pbD+F@SzuJKHE5Wb_{-_NFyX0Pv|zJ3}$e@Q$rf1f`MPhN&0_4yN&`% +>OLN$soM=O16Glf669%eBmRn}Kf^;Q2lQwrk|)PhX*jj%M0wMX?N^D)jtLxG)CQ?*gR8HKOOdH{H42e+^ID +`2fN(lZSOQuW@%FG+y`SOr>Z=VNgPd;gPO%OY&~l=y+4A7U$bObVH$$}c%_~gI=e +Kcy1RqJ&`~D7ob4#9LS^OKw|2xDj4cUe@I^_hNq#Gu?Cl%kaM^9IW_ta-@iN>u)7jbD4^`6~{13G|K> +a$2*&{ +RFws|JQ-cu<1J{`NoRABP;q8-MUWc&rbL3zM1+4b$4=vfU%wAaAWu*Q@T@qa2%JaTvQUhO;NxBaxum;VJ&O9KQH0000805+CpNtdsh4!%|Z0Mobt05AXm0B~t +=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoUX>(?BWpOTWd6m6guO+vYrg?vUMF7G8HY% +;&{923bLN_3*?HjWvVh$uGake;qx#w9-!Pnw=P0?_TFSL$d`+2z3V08qmTaff7 +dTR`^V3Jd;R+JPe1$Zm!Dm~{PpiX{lBmO#cw})`sn)V&(GKI-o5&lS8ravzCL~X&GYr@{q>u-|Ie$}u +V3!Jzx(coH?O{a`Qh!m>+9FAp5J`9zTUt2`01yjpTBwa;ngnr56^#je*O0Q=XclJZ?6x3qt5;N-#&kM +|Mko7pZ|Z=zIyxS{r>aa_ix|%$FBJL{o8lv^RM4Mzx?q0&Gn}rt?@tJ>g7A?`u@j#t3Q9Ze)j3lud>$ +MRs7ALe|&xN`t|h%zkPpw@%;Yz-Cv%+IZyKG+czKHz53G+`!Rp^{^$RBe{x;FdHL>Nuiw9V{V(rceRu +uh+AaKWeRzBQ{>Kl0e*5Nr{@qotU;XLb%XdH0Yu~*bqo{?prcyZm==zj^iTk9_pQn{W2x(CQD*@4kEgQy>20Z~t)p`uY8C>GhA#Z=T=nr}_O4e|r7u> +s|QQufBeM^ZxmI`TqKz&))y}uRZlE8uI1ckn2}(clGw}-(SzK_V?WTFVFAZ?@zA!arxS|EdJzqb(fByD|*DrPr`?uG +B|NN`}_PalPb$#;NKVJX+lP|vbBqzI*%K_3}>)WPSW*Q5i78f{SUQTtCH7Re|j4}FYelYjGV9>7r@>6Bkf +4Y8FesTZt^Zj|L9}leA7yB`GC;rE>Z}yL9(k@t6jK7QeceDN7j9=^ze{RKPox6Yap;`3kr;j7Po_uGH|;*y5>K``tT +@7vpffI5m9o%U^%?&tHE2KR(+fdW&hrl=t|2b)gLdmu`OKU#Z_kAm%(N3FX|dEYN@&ZHOG +sq&GMr0S#OX2qCH~1=<$dbt;BfIM%g8>+$Em&ALYfatiGtZOYUFgi&9p5QEQDCe_Skn_>qW^2&2Rg6wa#7n>Rcud(z)!GJ +o;U4pHKUb`l3Aco%UrH+MjV*TsoKi^u0AMyQ0VLv|@2ue&tM_VLxFV_RTo;Mt`d1VIS=l#lCTgUGHvw +DFKWM@TA_1UGJdepyVE?J!BLg6dx2H6dx2H6dx2H+%PB>6k}qQphWaj@7m+W%-$DD +1|@@%LCK_KQZgwCrVE%ZDGK)(4dz=gqv!6!-H!)n^)a7z7lFau$})Fj3OL)^w7m&Yy&4p*!h~Mj2;dg7>$zA1snA5-ebL`Gy9yx^;R;*$0tc~9X#& +!2#!*=aq+r_D^VT(rDlc<5wJ$3^NbnHXT`m}$q0ok=Bbp-YyceD0qw33-u?CxbnefJk;_S$f6bjCIZ6 +_bMntjDg`IiDK#VVlEk6_}9MHMkTl_nz(7?!jFJw$nvpkHh}4OUmH0&cCpy)JuO+?_Nuuu)_OeD=+>F +BfRl@wPn2xqfKKjE{z)k)1YlvrP!W7dxdZzJ2-3g@r0G2Ng5t>mHS_#vJQd_rc=S +ZU0`oN(Oqxbc5>L%J?s~AeB*tv810g+v2NLKg=e;S*j4tWox#0!j}*-O)ylzd8};eJV(ow0gEX~LN3o +On!r8E_x3C^F8|c;D6pArTu$@I4cjJNefB&&dR%~d+hSqIE_oZ>^Tm~0<+D>)}OzPbeY|j#UgjQmtF7 +9BxbB|kPnbs0r3@7XSh3UI8Xl1ubdYZ8e`fGo)JBZ4$=KBF@xjixu&iaFKV^wPmF{XE0H|p4Zx#8nLv +62He4CBVS3pG8md%8Wq-j#G(aKm=i`TZF9JB&R;fhV!YpC3?s05K-QE<~gEyx32)|D_oy2aoiFy+or& +96am=c=vu7#Nr`D(a`^0V3fusq0VeR0uGmM?CZ4(!cN!p9E2CI+T(HX5>B@JWst +>fTq;Fr|FPg#H~3owr102KSeqp<*2M}`HMu^)Q271LjX5-hxxg}27tUi=b_>%LHu1-SZXEWnioxUv9a +r}l-CETffWv|>2G=)O>5QevKQ8~7!-#RCU&Unt4qRdLs_x&!xeUnps>vS{E^4}yV#8#)+*QSIM#{E~r +R(l9v27XDyV{72Dfy)Li8@OZ%*cVFTsWt +G}z+(fC4LmmR*uY~0kL|V(J098fg3AUj8@O!Xvf-&UAldNL8c=LNu>r*f6dO=%cxnw#t>LM)8)vcolK +lrIJ0-zN!&7Tuq=AtJMj9AtV5EVO21Xhf!Km#ECBR6FGj6f{l7Wfb7fOPahLhI7NCP7cj5ILPz(@ll4 +UFLP54`!oV!tnx$TMy+7&ov&ymxuK=tgpTmd*Xs{Vy-u2Vxu=lesb&jqqqMFqpF4rfp7fBHFQMfnTzi +YODD%jhQ;DGr*f6dO>)sO<}nw9dM@qmbQRAlZOq1Cn?R`$9<|*_fmqD0ZOOfno= +W_=5W~xCEEva_mlSzhwVGNg&yQBp&O&P!dRXYzE8YzEBb?BlHSx&4y;2PJ`I2a+8~b|Be-WXEiEpxA+82Z|jicA(gSVh4%@r=#Egdg7OKAlZQ=F4VqI5=eF+* +)dxkD0a+N$82?c?G8pd80lc7gONV(ahr@ASm|H|hkjou2}U{?>0qRTkq$;W7{R3<1B?tXGQh|HBjfhh +=k`nXAA?VVOLCc9C<#VjJqAp~z>y!WWv(j&j0`X`z{mh2KFoNr{FO&cyqn&Y^+b`LFP!g;Rure@P1B?tXGQh|HBLj>KFoJ`%FO&cy1B?tXGR7IVx&4y;2PM +JE04oEtHNeOKBLj>KFhaDlFWd`^3^0P@v@etZBO}hZP5hDpRt8uZU}a#o1{fJ&WPp(YMg|xeU}S(1Xp +ViM1Q;1$WZdz^#4j0OWq=iesC}U%7#Uy$Z+>4W2}TAO8DM09kpV_@9bD|=agQ5*Nr06AD*;vldlFy-U +TokF4|uKt1vDgdU{i+iIpNtb9@ERhb)nt`UxHsUa6g9DQNtKuB)~|3kpLq^e*40`z(|0R03!iL0*pjE ++DMgoik7zr?f)!!FNfRO+r0Y(Chz-3u4eo26p04o7j0(%l*B)|x6?!HhGj06} +7FcM${f^T0a0Y>8H9~OQ|fRz9%0agNg5@002NPv+5BLPMNj06}7FcM%Sz(|0RxZ{h3UlL#?zzRXhfSl +VGN`etNIM}U0Xg-LZ2a)g4sSGd@U?jju-0{%DFA1;`U?so`G~~V%E|p8;(zy&S!6ms&E|dTx2}bh7g* +#%{;|AZhFO&o;i9Ja$l3*mkNP>|BBMC+lj3gLIFp^*-!AKq+5#oH;3sw@WBv?u8NrI6CBMC+lj3gLIF +amqHCnF`mNP>|BBiZ|@7r!LIN`jRHD~UaUFWEDgl3*mkNP>|BBMC+lj3gLIFp^*-<8kW6FG;YHU?ssy +VowM)2QjfJhm5Ljy->;0SF +iLmE1!5(ub$p(I#I>`8)=1S1JXCK#DuWP*_iM&O9{WpD{D$>oe&!7rI$WrCFnRwnjjf{_VECK# +DuWP*_iMkW}6h}#!RfRPDC=J88*fWOBLs(4>0305Zd1U6$^R7!%82}ULunP6mskqJg77@1&Xf{}Url2 +Y(XCRmwZWrCH7J(*yH7<*qR2}ULunP6mskqJg77@1&Xf{}Url2Y(XCRl+&+!sn>PbL_dU}S=k2}a=W_ +Jwf?q%?dTg5L~U}b@o1y&aJ1QvB)C<#W$OAMI8fu}$4@CP3L(8FI~1ZH)tPz{mn43ydr3pmaoixyaq60=^=29>y>62M=?NW{A@n4J688#k5k^D=L0hQw$acdZbrSnu{rF8tI=Fj;VV3S3zsl55U +NQfh?&;bNsLGEPKhg?Nx|e)Sk#M!r$D`45Nw5cbYYb)eC>)y1=F-!x$A8(Zq* +F=MQR@Itujrlcl#v;KdP`~Hu9SV%iVBk8J9Bhaap^# +04(2U{9MVJ>t@fwB$u3cVTj^x2aPA3cHR<1YY2B8g}X;V7zEYVL>Zc%!2hOENz8QA<98AxjU)y!-MbJ +)!h#)&cmD^^};AtX#Wbt3c1%p^jtB54L|N8=BSv#>cZ}-7Uoh9|GV)vpBe;EP-TS&FU;|RJ6geIA)YU ++(H9F(!6B@$?-#CYC3q>gE*Bv{SvStM&qZF(C!o=t?}qbukgWu4lN{|JH;9S=o}#ckUkvEAOnZ=Dh4r +X7j?^3EaR|Aq*;P2Z!eUfdC<~!!kWsJjM&)7lh+E^9cOu$q60Z3)0d8))voZBl$q-kpX@M@hh(am};{ +v-?$VL}?wVH5yn1gZlnx|u~GLr~8Yd?9i-6HZhi4k +kPEBlaGDaPX+G@{0sOc^#y5CO$ie)7M9Thy;+6{SO$+Erx3&yc~|l$7xZH-_q^C~^0p6{IhfEkoMlcc +jY`G5RA*EHg`jqjT^23JTwy)1nQCGI*Q^jX)po}LJ5I)~Gi0P|U`Gr7dLi +FZ`VqhYEW8%7r2zm6@g{wUAi&8i>?REN8Mi%2o~oH#v;8O$t~lVtKG1TK2(`NU?WOo4&(O$ckz?DPR_ +LXNiy;JgKlt5o@>7M+#1m$ElLKa2k<_~2P76*%EfVicm=x@bgj91`0%CjqR0x5KWQX-`zoY`hf;U?Tg +D-AV5g`eGuNtcV1NMYq@ZFCmmJ5K9GJPzk-Fqt}@9F +SdR-adGdu%ejIJt=;xBT(1ra^Q;#;PTqE%&W42OO?#qbk3=xbGxy#IW$e*VRL2dbvOu{O7ZNzug11}8 +(f94~=;#Kq4@97FN|k(UfhwuTS9v&b8PEr=z#jJ2T)`3BxF{1mRp{#rCe3=cUs4D#E7`vm$Jex17qh` +BvA@8#DRDeC=1=Nu?0Zcory{B5oVx2pU!sNqKB|DE3renFEH82j#c7SDxO5`aYCxm0S4g#Vvdfit_iEZ{Mr0nH!uC&y15kMy51~@)*yj3h +ZPNMj^1!n3xB{^2&nC{Nu|bMG+>Z4)^`d(vsnhT%no&hlgoYD=um?#JEn-pBSp~_YKPvIf1!Z)x`qeP +(JNa%@(ofYn>)N2&Nzt4OuwExzb0Ia~ST~ExF2G($fwp>l8XDa-s_oQ^?v+@yVYDm6K;fQ+oKYq6tS~ +*LtKID^8VLGG*H`j-p`r>0_JWeDE$;r^eo4K5kD(D_JToC=A!fed`3tmD;|>*vtigp|y0XYAD-^}WdR +6P=?%(Z~v}vG1L&Iu7W-4MfcjEUePA_6YtFDlBlirl2Yja=4CtXeRo +7aD_Wp7o-ldu`0#%ZSc3l6zKkhNUUBboPSPq51BZG6s(X<+Z%9Zl~(0dDk1*$yDmeJf5yJ54w@5S@73 +Skb#8-U2!5KTqx%3h2#K5N}+72XT7NCUN5-bVweP9Qu0JM9VZF%!UY*X5mRK{DhiJa$`wHZJ{W5wtBI +;G>fL@xZOW^7T;mJWAGI3s*o_2d?Jxlg)Ux^jCsy}@s<4s@zH}7w@XA%)D=DYSVpLJ>)FEktUoZ{b9( +s0x5hNHOJVAxi!~5eDAX_Mk)pVt)cl#xXZGaOUYUk-(BPT~lah3Bl_{0x`0c2wvEv-1gu$YLyNIlZ$2 +fyfE+wnh*Be5c3$b#;Pe_gI`{a9Vr5RH!=4+>zS3vSBgT8i?>dbeNFA(09zX+bGfLGlHgP+9gX#=XWN +W3VyUC*w`>NY`-B03JSR+{)r&z1uITS}alr1&Km+-NKK71;fm0w%pG^-^e9R2N|Uwgc&Bfl3uIz_>&9 +({ux8oT`y=k22W++IA3040;!RYN=|!Z-ox6xH{K7zW$lV=w2)HqH0Ln +QQ|@|F_LJK$VWKkhO)3?`0FISH8rkV!0T(WZ_D(9 +wU+}Zc|biOrU)k^g?fzhx3QpL^3+2i&VSyF4i|(4gLF~u2>^Th6MMrR%2T(O{zw^MF&SRNYW4a|2!<% +Y413E2`=J8SFTeB;gnMo5)0zJ9I{l_19$XroI51c7h=EsQxD!SKF)vwc`=xl1yOLm760T?`ORSJ& +rK{~>a!R2@Pl0|LaMwjULJLq03TJ;N^Zc%1HRvsk>&qtR{Su@=*17fK@I;gKrjDpnsSsSJxB-i +Rs56GAjxC>E}M@}?EtYniTZnm%>jZaAx0J%sR>`R2|pwpo>tdB^hSk)&{gMlzN}VU^;!X%17ors&t)C4S*n%a*V22-)bAWwm&7B +g0_}~oPYh6OD$x^tX46qStv>?my+g@wA0HWOS}>HQsSiDel@z+t4hb7UgcSImx>-EEy6xbx3 +&;j4|!S)z8fe=gjD407jbu~x1B`yS|I@%5l*1@g=@xfJI-umZ%Hh{>Np{yZW=%Q~SvmR&=jLh5?J*(ln;LoaXxh9U*CAWP$-T#nJ +Wq*!o8Dt4s~jfaJM(4Ro(nx&uXAH^77>EXvN&VH9*L6%M65oQ=}FQfy}d1}M6>kW%f&!*rjp>%}lt$D +_gM6(`sM8&4w(MPrDw;N4g#@t)4=1H=X8+1F9gyK38x>63`4-wDMm(B(@P0AM +mw>{Tv~6i|Lw%0_$7G%vWE``%4j<@kO1N6e7|3uFJ>T&gy4MzlILG-S1b|DKZpKz`-z9wU +lrTtVpo}v0wP`Bix&rrB9yf1q4l)0o^^ntKD?xCa4Ns)Dz1sKrcY?w+8Akq)#bH}mhUP(q +`ryLo6dT1xMYk@djJ~8qz=5Ui3kxrUYbn(U=#}T{g*^ge)y%w`b<}%s8Q!uX8kOfy6&WeQxI+iN6uw< +jJX(&bzXZGee8{^ntbgxA(1Gl17b5akRfG0uM${Vq&7Pd=OA_5*0DvIYKZsFEdsq(FJtms}#%32i@!K +6BL!4s}wKz#Do*k4v8_e1s*$2N4YHQdf#42AS#_yJVV +G!cUQ2nN5RW@E=36TtwJFosNu>`$I;iH}n+diMCm-ff&1In<)d +54OOc|z3?T(jKv{7TY2q=p&S8IZ8pSYAQJ({zu|^8oU}5fL+t5cEOob+JPty=Yn&W}4@B20V|kd6l8I +oIfc*&*^3!}8&Zlt}5A3sMx$DI*A%)W5ZJ=#gC>a^k`|R!s)irjv+ZdY)7PFdQTH+mN!>vPO-u1$lEV +HomWjzub;EZF4j{kBF!i)8C(v4^$Ovqzdm&q?@G^WYe_9Fs1;{et-Gw`@ZX4K^;@j)(BEmb`gf)lb3^G+;e%}vPEOCATKU68{T +7Bpfc)-AY(;ZhMGi76bKH&PsWUdoghRfJOo{-HZ1sTaN^&xsT)@xyFCbc@4-A=lPxa$KNJM!iT5atXZ +){1-Xwqemnw^VB6eT@=l~nL%}->Sm4M2dj)s(?untBiZ&)>B2Ll8EV4Mb+;G3goN!yTClSHva4Cbhi{ +rU#25v8(md{h6~Eyt6f19%Vn)wX*}~~xbgxApnv)HJONB$IMMfOd+*u*goz=j~No2hkKh{BXx2>9a>3 +6;6aY8N-ZbAmK$#kpQf%lxc`z&`n1KHAQ&PIM|N}8X3V68cEA-m)@9<-Cj>BkS(;OYsRtCnstnd3%r7 +Cw*h2xkauzau#1^iKbxd#&NLf_jjYSF@Rp46(R{Bm%2=lvjqiez<(#Z1f`_t2hyNd+|%yBY5cxA?>T= +bPLa1*l19SzJgn-yPiHCc6#oDBZ!L{3RE2FcIw@JNtnN76>MnfE=HybXN@*&YhzDZWf`qbYkaX%rC_> +!<@s*W*`n8VYf@+=QIcqL3r5t<@972p?usaT|idqmgm(rsL0N1U@GYAh_Rg_cX_^Q|ash>ec0(4a7 +1|lJ~>JqarlCCzl{_MrRa5F%>t|i@t=N8?~9k@$Kot*DSPu +tMFHnNpf-cdi1kgQ>jgL<1t8hQxCmgXL&+83W?Ke#yJ;-LuF{MOtWjB9F3kDrkZ|$=kMjvL$J7^+RIg#5-zvu$%fY8?g#i165^NX +Gs3^CTd0_R(FM0834p4z>SDl6K5*+i?i|*Alaq0wj2_X +K3eK7JHCb;1>n!G)hV!EB)1DJ@Er3fVb^7c#6y|#Hg3IJ~8xg@A@dKe=@r!owus>C7m1?%g>@iiZSX+ +YXt^Pb1(UN7@+?7J;Xr^kpLtb+IE5kyECE>vfwyCvVe4C|FGVOK&arX6m(j_$RZJVcmK70a5XWB1*qO +4xqmEQF%8kevd}T-3wp6{{f8V4k<1IIF39JuGTsBve(0lho5a#L#Px8kw^A*Cml7$FZ>dwP;-28xit=RSEia5`COu*!+7Ehx}M;yn6dP65kOdb3JPE0z +f)wYy;L2P;U6I@;O6sow_H*~M%EbK{a34;S2(a`LdJkA%MuqR!xUMSRt<_JYZX5Hi@kfyfBi3=OL*Fv +t~QmTw@`chIHIvo@4z{Fg4(QuVe6Jf@8_tKP}3g;>T%I&A3do6HfS8CTWU`iC2q%EBdSlF)oX9{8ha+ +LRK(qwU~5?x_;<3Zi4#J8@!G^D%@YPRN)9kRace5%8PdBXnUk&gVy;9q8yr0hN4(7hJ6h16+)Y4*k}V +Q6r%^+#Z@@)93jd4cET43m3Gu9yJTl=xjQd7R}$Px}byNB}jH|BM^Zfjnwhg=TOHr`47;H`_5h$c-I= +W!&=^-D_DY_%ts%yaqNdcNkn&>kggPa4#=7*}^(l&p62bXuDN^KkokBeo33h^>wtEvo39}FO##0s-y* +$FjdsUCIj~L#Hp^G_DCu@;e#`EuT=_9ACD7Nz*4MU!rI=X*qrL}1PTQ2^%&jjHJr +ydPCDp_1?o78Xcu+~4^0zurCA$%UzNhd^qU*C`|kKc-RqLZ!EC`ER)Z+SL}Uwqf_ZldY9yI#!VuHspg +TA(%63iYu9JUj>R!8N01j;d$dFKM +hcO8LK+-N-sdmJ>Ss1Udq02Nf5N@@zGAA-~h_en|C`vM&H&y1v+aT +nBrar-9xq%H$shH@E`RM3Z5RvIWQC%;PCvGL_Qm=+V?=T3fIYdto2&SgWiZ0en5$fu&V&N)o8)i631> +L-$%As%ZJnywgdAn$w*MVlh6$L2-?CkAa>r05IROj9WYb^33CCZzpi9ZIZZX!N7Uvf2=nO8qvA}HK*pd&@SrAz8Io<(t6y@KCn! +07rEE4239Psb_DAy_4jGOGfE}hMn7t@@O3F6e_6*%C(JYUqen%%*nT5h!qiwfH$a|_n#2_6Slpqcuaij%vnJZ3K=$J1i=F6RPCQe6a8+hrm)aBGexCIi3XZ<~7z` +@AgZoo5-8iT&0I=x>9@BJW-&h4|Bo>r&=YKg`J8#BQq+vbv9kyD_CuwEqGYphbsq1gb|XFk1a=Pq&II +u%4yO~Be-2lJv#6>{!T~tTI_oyqz&y~cgvT;3ljI$Ep28{mDg4?v(^hqT1@s5AEQQU?eGL0-D^RTQ;4 +ZTb(q;}NaM@BH&yOSF8?9&@mi*?uQZ2REFq?wy-vLgURgGwnw3$Xs*2Vvi~3R6`lag32eE;Ss=zjGQZ +3H>x$|U5`?md6m>_lL1`$cvqiSY(G?C{T;+DQJjmnyylE7*Ka9v=L$I->pm+WtGrxc5_ekyA(tXY-rR +-3$zYo_P!QG?>lJUWvI_7GB`-TTRUF^_YSKUje3!tU{vf)kRkdqb85wdb(eUEZGL?NAk9y#-(J#NGYq +UKwYn+B|a>!yl$cF%qtza_(;VGBya+Q^Xgc$`hb^@aQ@JtQYkq%BEcBi3Z!Tf9_7e7O;CtUHY{gEsYx +fw^6QA1{zjmD*N4D_!3X}J%WRDVU;4qJ5?JJx{Y!(5P_;kVP|ne%TOqD7z0?Bqkrh=UYltv&g&_z!lo +tNIR_Wo4MpIgt4$RTYP8*6p14d9!<|`yFx`1M}x~?85GGmHRtN77u{=7duWallT(g6!PDzPo=4Nc0~m +vL|m0>Bw8r|s@><=u;*mQEi8bhtLurM)Iv!I;MpngtPUdy7PCCnP9yj~`gw_e2mav9^Ip+p70A-60+z +tF=?&zD68c*NyLpZ(?e-H#vs%*z1&^!)nmzw@4mx4hWkdiCbR^SkH$JKnJH&GU!nuRWLk` +ybwY|Mva!Q&q?guh!CygJc~D9Ez$-&t53n7mgr+CA1tD7A=L)B~@3kQAwK1Oc8v;Iaic4Fns3 +1q<@!oi!*3NP>)Cka7rmBOoz?H9nX{QEwxIcs59=2T@lr_<=q<$j}9ZP?#*n=?^jnK_DCK>J3DrfebO +E5!hB3_oly&cs5w4gVboiu?LP%0Qg|Y12IRiQZ*1B2<(DDps_nYSVV#hVL*w8Mb*F`qN=0_?ut9D86C>H)$-vV*a +&||hVUF-(-F`1!()fF!MHY?PvDJPc6K#z8V0h|hR&=tH%$Rn2#`P&7S#&QVHzFrY;yy|IuxtV?A>{0P +T8o^m@ewztQzT0JHwxNYn%{Kb&@t6@oXDXq2y4ou0ckoGfSds@8P(nh(j%4T64HXR%lv4tTEuwl{KgWwytF!`(olP^FsX+w-m>+m+ +{A!NIR7z*hk&M;o(kjNeJY@o>r7L(S56Y~=>Qjo##O#m*93_S?h;PK%Isv7h};7JGjpQ1hPdV?U4ena +vSz7K-Mq2bL$a|)BRfm;a@Ye5#Q)gzPkGfX#Gs^PZWdtM-(4T$rOASIw!10FD%il{v$f+!>Kq&xC}mM +3mcJ{w$cAg0*kHb)%S5zj_*cSHAMDmVB5Q&4KH%ka@vx`1rs3Rz0ekU8RWM#P<4>jbU5#A4Tr?SL)`* +B1Q2AS~{lsDW=5cyJvZRwo}9&0fNoI3mpjmie~sU=8tXG$#ThvjmnccO&4mHaf!xZ~lu`0tGn4&TQz? +e1$qb(;v4;>cn+lB1t>03U0kZ!%)by)e`-ody@=ceCPzQgl&TQ$&?)FQp +m$?|N}=um$ +ym_@`HCv@f>64C%~6byv(lg97a^fq{eHAgMaKm*zFA1QX;xtM8WuJ*V9m!(|8$|o_)J@FAj`i@Lpa>9;gG_u-S!OeY*&jnZ30Gcx +}`~e(^GIB9_&MujKiT*FjcN%z;yp{`~v*;JmhpoJlpZvTNhY@BApyO1IGQXTo2iBTZp4Ng6cN;YOck% +&a`&-10od_UmU>Dngo`pVT^nu0_#glX9MIof`U%4*cEgcqzpMhY*tx!d+|$}55)UwNF0WtNjmQ_+E9P +dG-{5jZPV(qv=aaI)HGoA@56~Z;@LKRU&8QXN^1X>f70j6Rn-JtbehY-(pvXVi#8EE4>v41E7cULdLaCp>)Qw`O97! +1Sp1w364yG1{Je&z+@*+8xlU4NSyLI~W*+6B9w0_{Pd=ZS8TfbNEP?CG~|k;l-HkBi>!e$X$GA)bCmq +nXTTLj%`2x`6E#qH=G@LWy>>g|!jZEFZJq^&(P10o@QVhWZp{ZwCd9jjVw*rK_7YG0{%FtT4mMF&93P +KfcKk#k2LyN*XgnEltq*@{*Ji`GD`yR4UIFLa@>9}+q)*xcDku?0I|0`{}J(Hwp#SffMU00KHV +nJi3IQ7?W8s=z=x5lF`Z;xQm%f=D;eWCk+(VAoTOvkqb0=`=D;0dE`RiF+RMX&|2M?nGLm|c!$Ik`$U +@X%7hq$^rg!&Mb)7U^9ajm`=P`WXBTnWOS$iJqA>dmKZ|vh@6(Ijx*j}da@GUC1Ypxd_f-=Od%opRDFKi^2xCbG;-Q@5ko3G5Yxje +m3Tw&m4F^ke?C%L)mQF`d2hX6Q&|O{Z;Zg&_YTd{h_I?iA;iXd43*ES!$5h1rHDl1BuaeeA{}K(l3CY +zRwOF8>>aO!jP1X?s@hYHQFS|BK45QuQ2QaSg+DQMj5WPgWk&c^)U;5e(GKh2L-~E7iwsrR!X|y#t1S +;n&JpQGULhpi9Tswyl;_rk=X7J7lgRrmn=DeYJ79-yX_|g92#o=walMNRNE~(?D1e>$lNiogQdEl2Ro3&gWsmrG3nG-@-5BZb(Hq#kFL+*?JQ5isuoYaLLr9Z#*3v=1o +I_V}q@4vh`%B=^*Igx1kbHHyu;wc*N6v!`^B#*)LsJOb=tehKoZ9DkB`xX=$gAO4Q#mrc8os0k;n<0p +o07^`1b)7zDqdKhB$$5x3CcGk_|p|PQJ!0Z)l(r+FrB7f_lLvV{tZjr7Ek5OQ=P=qNq3@zJ$A`bsB6w +mUjK&#Mj4w?cbeoqROFPw;UkSsUM?DX|Oq@~U|2oJwyNr}7O?U%HEZYf7IpGUDuMot#UyxU5Y~ntAe|TstY4jjF8)U&E +9JjDBT$ET441{v+!_d*msR4B@Pwr2n&*r@0p|K(S(phO!MVA$ELm%A7wOPd2T3txLkjaym!veN?&tt^ +1O{!QnF7%J4DDX3YVt7wTnCB;cVZBUTT%9-<*P7$+Af65L$_M_gZ$c7>3_>R)bYN*hM&=MNxO}iLp{N +J?x*EphdF%SnO^#j^&2kXRut!s^;R`r0spV4!;lHZEtR +4jGORYi~EFp-ZBhoks-E%T;!J9k(;R{THMZv-k9k|6(5Fod(`%=zN;mH*&!5>mI$G<8H5h$@2O9sYV5 +F*8asw!W#-4p>9~K6NA?ftoXt5+%QeyntLai#yK>0`au5PrqVY2D8nOtCN~Pt^DVz~pqQqqn{*l`cDmc-JKE~*Y2{~vF| +Cc~L1Fg@#@w`Dwn5#+1?2Cgq8+qZ!lLi2Eg;yj*4b)zm?i- +J{d_Y4C&YWS*L1CZflwOP#?8wd(N&!1DytSf%?V54>FEDe#;_A6CBNI7F)H36CHxnwbpl5N;XnzTwt$ +6VkG@qeBR>i}R$n#VbubJ^4UdZ%VO-OT4n`L +5fNgK$KRFsiYKAPy*m-R=J(p6!fLz&&;7q(0q7z|4bjY6M^b`x8@f6SEw;C){!)Bd=OPTE73(Uh+8jN +4=ktK`Slfy|BbA)Ep8Qxay$>1bBo_unz3>)&?GDlNT>n!H=R2oCxe>KOhP}FCiO5y+z +7vBHgbj{0EcK>2%KwhsRA8W(WJu!WOHsNwL&KiD8H`?8VF;kAr64;%`9Umi}?fMUFXl;fk)7kE7X8cYjY#BfLKy?+v*P +G-&vuLy+0~Ih2f-t2|ZDIn$SCA6EEsgXL|Sawq!699MG~G2a?XTy+dsSL3jh9NhdF;@R#STVYYVmJL( +Z6+tXJNO3aOLs=+N)h^qLJS{k}Bsl%6Yv|U^MjMrj;O}BN +Zum4t8jve}9=p!VRd#z>#HA%Tp*@L;^I@E`$0&(Blc2LBwn@UjG{lpz;}nr3a%ix2d2jLx4~>Np>As- +@<}LBf(+!^v4{>h`=P_G}@HU&Ixpo~*PnRIVuJ`-pGQ3=6kDK}1^D+@4)#Vs*2NThIEc2mn6^@{E51p +nZR`ZCbCmSR@uPUT%C-*xpxZr_8& +`U;Qm~j04L@R4v(u18%J$YVAfeMEui +1VH)+fTjlB}ieqgrHeMvKGDi28W0DvNn(0S7PIB{0YF4_hc+(Kxf?b!k2hx7UWn>4}Zo5KXJ|w&P+t* +cc)4kXz!m!)6;}~!<_a#-w@9>RXdO|>EUP(-9Qo785DiIMz?hOveVt2XXsSkDF%@;yu-1-sNXgoMAD# ++!I%z;4~k2fCshvWkQ)hCxQfiL +*)N=O%Euur4?~vi)i07-#S%R36hP=OZgDAnCdUqRZ( +7;8D7A;z|XwjlYW45(RT%BaONtTLgLX!|WL1v)x>B(ei?2~?$T)-4F8s9m6X^t6>TL*#`YWq73FR2{^{_LRU2QYwIFXemI)x-_ohJ9NPYG#VVGN +ROA{|G%v#KR~Df&Ezl^`(M^~#`w8a65S!XTtTfAOoFVd3!IJNmF_rge&v +&jIB$ZoG#2|@3JgQ?}+{Q`M;)2=%?>|ej&xrE)KIRr0{BZ5cxvFmjkm1Da6DQoYtAMk`7OC}77-7Ko( +u{I=BTlWhmhs*xB>)n1yl7~!liNynRaOKQPxH3Q7Ee5bOpzg2LiWZ?OMpGi20X=ac!VBu9^K`?Q!tN8 +Ilbai1g{V2x3 +F=9%SrfK5mEMaN_d;ozvy0*$hLbP10HS?!X_?X(_LdRYGh0MvbN&zu*hL`2`BT!GQRHT9yfKbz^^KQB +wA?%sp&j+p!h5aLDJJ)(K;lKbSETj9*+avpYG@EC(lbh{izeA*6?LC%%f#{J)eUq?_mqXtceSi_%Dgq +f|iC0?AjFU-t~+dy4S>U;rK#+Z(|q*mK&^pVrCNqni$4T7~D}}bfg!l31JQh+ucLcS;kSHnV>KM +_;XrkZQ{~xEKykRIapsS%04?eMgr~XfFS^&h&hNcgC45l$Qw!02yq2@8A#E=|X8JkHbX!r7XT9eIy4P +0EyZ}zcmdk5k#X!C<`eWg1K&%s=XBC;l+9*-I1E@MLPa`S$)D&6~j(4;t-K7wfCtGuIOIK;!gb><}gcK>2h5hf&w>m(7Jsfu~=u=VNVYPRsJ;RO1Sufh08xz?i#A`kb}k;1ep2 +8FKbLZ{}b(n75Lw0DTE>Ssuepjot{x+(P>PC>qGk6Wc3m{}w?3Dgrvwy@=RPgQ10D1fsA0JnS5zr)E~ +?dgMGbg%v3XKKUo+y%_^_ui0pV8u|9Hxhn{f;>@>cigJ(GII_QzVU$WwJ$-BhJti%A3{>riiHv{J*${ +5R_V9&K9d?~;Go?FA;t&lCB1Hn(=sTTPb>OhccfvU50;L~))d&J&$^wllu`c@Dn|b+7 +1%5_Nf^E>DEz-ScJ8cccG{2(|Kty7m%?I(WL~Xw25L +zai5W@nY)l9VHiI%)SPX3t0&8`11#E*qUSKfyylUv#K6 +8ZV!x^q@LYndhz)orS=MHQ8vKjl6Yh@x!X)!J~5pp3E|-iXA>u9smqdv3I=uza1*tc|C^?liUBtaRzLW@eq?<-RNZ~KUY*B;ngm +eDA+nuK%#iK7AJTVKSOy%IxyZqg;JL+Dsf2m{|3NO*8CJNMSS{8NuIvw5+=V&;sF(Jy7RGJJY_`S}fd+pGAs +btW-_EI})sh1ClCHBA-m0*aeI&4NFsmmjugFGUhZ|fXR0k8YikXNPhQZkZ>=B>iZB?`Ah%9Y(!3YsB3 +_LnSx!e>KGG=J$!5bi@3;Z>;@s)B{pP2%VQ(-RbzEn=n7KO+&Hr1To;&PJ?QJ#=3GjFea2c^v3a4g<% +1h6lkmCrONi^h;@(a}r7VxSh`!GFOgnOZ<$bn8l^nyC3jN>~>cEq@$AO%Tq`7GpB3vFT6cpUJv=R(;kN7UX8-`zM7s~v{1 +@>`B=MbM%_gZZXkGsw!rCE3bP;yn#`!L5e94)`4UU_AoK_5&{_{? +KilHFeKWQ?FanNBc-R`6$`P@EjCZ{JP#q(S;A$sF!{I+epy9J>x9@l>Z4Yg#3dpYJ+k$?`qNsOh>#tf +>N*--jdWZi5e#kt{|-?C0HH_!7hrU9Z=CfZ-8lE4zpN4v)MuTCzB3;q)0Lp+%Xd18*>W_^9;I*d{5M0!0cVp|j0@JiFX#@*|F)*Hc8tUHh8zJ}ZUzUHh?d$v$UIA;PjD$2r;^nk(cnlD*1s;iE +u;)??d)e1HM3`WC=0kTM-m^~ARTw|RBNg&_4nZMO-F7Fem(B|-7Ya@ +=3aLaugv(Eopdk$gs!WK-X6rj+u}8VLnn0EW!ynqi{EwLQYJUf#3f;zdY1TysV|5hHO&0rLglTCC*FD*548?*`i>Eck>1NVHasW^l9?vOPG +g-Pn&@e5zU$Fq$4;Vq&7miX0b$)t*G*QiWCcrCFxH$w@+mzOoy=^qHsr8xFx%MJybmiODB1P0rZc^hS +(!|*WcCbmS4@Nyu)uDR%1RaTNQY8s32DYWV}AT~0*YO)Fa3}h#ic!I5(7bu+EC#p_D+xZFYa|-o<=JV +cv!se`G)Q_Nm=F)#KxjnU2;J=9LBT@sL0Cq4Tq_;aen7;lT^c9yASQgZ{PLqW(^W(Dz2ua{5cmq>I`4kie#t +N+hp;@+ln-)q4L&mwmJhOXsiu6LfB6Lh7#2BtiQUFrk}r;ZK=+!6!xI5`A^=Yn-%R;IalcDpNhqpO)~3JSM7cHv-g?7r_nN?ZrPcq +k_(Rm~%wzok+YBRd=H0PQ}}9QjlaqyxoZLGn~xcrrq_zmp~dP{8<{$o36n_NZ;bBw}(J3(P5_&>|u}W +IXjey0iI#(7wzr`bg%MJh^*Ump!Dj^B=`(WYh~2>j&4%Gu4kOXM|e0Wcu!~>XP+e=!fr3hDxGWHXOwF +hCw^lNR6hf8(>j<4J`x52%}Js(>AqC3-s?QN*Ce?$H2nDYssCUi8cYvgXFRj^^OeBk6@3;yCGOhBL}(qP0=Dj~mEnb7pYy*`>dIW-99CpLl-4jKLn(RQN# +&ikdV7{TqIX;PgC%M1HZOq=1^J*)_`g(y4`g%6YN;Vf6bvlxtKEyqrxdmZF&6V-U48c($1Y>eXq!ALK +icNK*{!C1Q6fDUp~4s2^TZ<@C~3;hx@4+!6e=S)gD!W|^)^6q&N4_m|vnr11N_owA(WQ4Oi*0JvPqI< +0-`b`LV&;d|DUD&nBh=Ya+H>5iWPcg`VjfXoR9)3Xy(3<6L@AgZE2`|Lyi7q`+qbF+ge#|`66|KVMBLo=0o`lr_39n^RvV^Y*ZoMlmfdD?qBi7852gh1BV +IsGAx=|S8*`rhBHZMuhwsVKDiGi`gBPAuON=RNOvGfS=G0*cXN_-$d+-^X_^Tz(JVy7LsHGF3bfSY!b +kK>aIZ-vIni{iR=0%8TlTav$K9Z#>aetB(Dd%}fHUHoBf`{qth#OFwCZf+omzk(B6E$Wc#7xANiR>|v +I3^0lM8TM-6?2|_GLWG_+aB`Uo{k(cHxrS72Jl0ZL=OYeQ-{D0TW`i=f +8QGF$%u0&atimFg5CHka9bd+dhQh5wgm{iq*7$s42o66&U(rO_qGWflxAq#AXTG!l27m;XPd)RjqGv$jwx30 +aT^)uv2|M^eXM=URVKx6V`{>vpn6=dIJ_|GQqWV$M(7-Klhy`~H+&R;?~CX7hxkU<=#q@Oe$3|+#;rNkN}T1uixipg`W+uuR=%7srT31A> +^Qkf9kOe$c2mPzRrDHS;s0*aLSfbd8egLU%V6WuG97n7iV61Gpm>q%%liG?SD>m=TsM46NLaT4)OBDq +P7Hi^t8@z{Kvb$+6I<-#YFER-yitdy*jtdy*jtdy+Wt5Tv;qEez#qEX`T4-?%h7e1k6qhzCGqhzCGqh +zCGr)1||of4fAof4fAof3yvp6Fh=@ChXcB?l!3B?l!3B?l!3B?tE!lo*r5{D<4=w7+-2_=J)L +CK(GP%i)~fE75f38gXdRV +IS0i41EZxtd6>CTgpR&}t&InrN#g+Nz0gYTk$0Pjs(b_=J*R1*OzPBsI}OO|(!GE!0HsG?6+@R8A9>( +?sAj5jaf*PV+uDX`*}O!Y7mjD@d3o5~hi8X(CseD3vBkrHN8$B2JpW)Ea^Vw7f)&_-Npv-dq$Wz9iIQic!bD>*(GyIP>61+MBnv!A_D*uS^VZ +o+bgx|agpy!|oXsRFGfBEkQYe#@$Ry7(Nmxws5tDqtgzlfvClgwHU&_y|cl#wzA6?(Re)+G@^FLp2-u +~Omr~emFO9KQH0000805+CpNgIXa$V(Fd0F+Ar051Rl0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&W +pgiMXkl_>WppoUaAR(CcrI{x)m&|J+c=W`u3v$hd^mfL@e+KwotMp4IgXup*0Ei-Q*)_Q%0)|%#f?O2 +Nh%)SuRnmmgKm&?Hrd&&x`|?00`c1Y^wW(d;b+gL|B08!uTRg#+3C^o`Sr1Qd3JI1SMfyMXR~MGW~Ib +MQ{Ipa7>Xxt6XSJ@ksuA^4bQ68*`sb +=^=fzgBZp*rA_19)wH~kmgvAC=oTRv}8(W!;Fd+d804^=d#ukE8AYSoFoqkSQN_~Coq#bosZakyTKD^ +s@>SE^ObXSJ{^IjXC!DercAnS1U2kGe#Nw?*?wT$bzmrre0HZhThGRn;m{v|?+@+7(Ia#7yMcO+=j3y8B+bKM7Up>t^iFs%dqJNDd@Mb3H~v>w2%~%>1= +Bx2EB~p7f(wYi%@Wc`zvgTIoWRRp0GO%U*xb9qNTXXjq9mC3dY^?$(j+LDv<(oZh^-cy}WX&)#JISwx@El)eu|=y{e|Dx<@^6-ND=AtD`r%#o^1-v(uaRX7(qiH|NLK*W%>jN*s#I!> +gOqqjzVASK{*B)#b(Y@qrN6N^IVl0QKHZ$v +VHs}9j@!@zF)6yLIV9sluJ?7T_hfwQe#J>Z=_w_3+Xq~pr0Q^BA2>SQGHr#6Yq41fAy85@@zI+HuXjv%o>Po$7i=UZ?2B7-&~x%(pO|0&)y#X&s4d-aC(0FR(J +jC@a8bMn$3Vz{eM+9#eGo~B6&Vv6^&@s-*>8-Yv~quYYl!Q;cB(WJkI{MO^$SrhD+41ogQ~@wiid{l|=Es=AOGByN5-K5Ym#2VcD>Tc0xLJ~&;!ZcB2D +(_v+s%f9QXC@2pC^_i9#0%*x_G~(SMU{38Q3r(sQVEzrm+zM97tlQ*8^`zcRkYG +;`N;Cx1*Z_1ECT;LlPwopdw;XPnGo)OscfjHV3Gpyn)4Zx;N(rApVS9FSM;U8?ORaqo$fE}Uu}4FN@z +mwC`6WK2m!Rwo^XY>)yAO}tDnENnD!OqY5&L8TZbG&3IjWUg-u4H^TYU{M0mQ%F%6TO~=9)Jdu(rKb* +CslyjssdV)d*MH_qzNGq`sooQQ!X{}~oj3*~E2SUl*GW=Nqm*4soe{v!L%F6A=`HnR$9^R4nNl~O)P{ +K|f}%O8OQ%{H7#OCJdn}tF^N6zo5EpxR5bXmvv_ww$2xkD4j7yYc6nlOIMj*{3B5IMYi^Ss$(*m%HAP+u)*s>vyl3nthCb|b+AVpF+;!!)GbfwZw5IW%U1?_S2NXdf~PnODM?u%bLdP{(m7dzD&P=d2ToiGbB`W1KjglV_sMUFtulzBczviMRTgOEip)h|0NnNpHVc +d%{$S_$Z86p#i?(OM=gwwx}oK5dbd@Q#zbSbI+s1rwQW%cq!rs_$<1fJ8z%*cPxd72^LOTMT!hoBZ)_ +cfis9Vag&q&H_E~dMB>6{gfAF`_!JRV%;ZNKy&*kenLu|s#3*142?0H{+l1$b0U=Bw{^YwV3io(QM@D +cQXq_@z!^jYw9eogwQWQS)(}^z)F-I6A$;BR9GI|P~R4ehK;Vp;rk;J1zhKrp?3f)1tvyu)Dn6lk=4- +JkpDeVoUlkN0tbcGTSJP9yNK=AAu-|}(gk|Dvba1Sm$74bY4LLP2Rd`pfQWkb(I>mi9!04t+0(O^%-! +!!a2xlJx7f)ueS*8#azMuW(d$N@!I`5=QCPe_+L71hv?GYNWy@%Bz +2B>X&zy<&J&A3M^IBT^oZsKUURQigeyMTFll!Y6l`Mzr6IBXTF1$FJkjaC0|yq4bk5DMJ?6CKL7NZh= +X}bNFOBMEmHAPZZk3(j5yCM)^)KyuC%!N|@@UmmQ?XF$&5;K7hg;5Im3Y(IY;SYw(_p=xH2fLkT>rMW +i1`$WVd8;kz&(Vkz2-fwnjR5P^p2B(jxgH$dyXJ +EVK>@AA4UIQ!*8gN@p588Oc-Rbl)RP8gf)}6QaEnf2aIP5{wkHC39k9ckaRs7(8?`C>sWZKrC4*-uEn+mW|(ke3O857L@x0j-g#P*_TK~wo=x +Fa&VTGgxsQ`NA};xDN@W)dD;<2=ffjG^i|1SoMU0~x|Fi11;8G3z;mfo +&TmHz`shV+shLn@*S?rHnHIHp(V(tCx}Vz~F)1P`;tBN`htZiE_SRRv*Ui<6RWK%Tbx_YMlQ5wih2e9 +rZFWCd%cL*(3}Yq-Me=vP|I(9)1H7CP{&!WNkR);OngyMAn)~RI-XzsWwuQp3(4dLFOCNtp$q2k*XkH +pG2hSvFx&lGYwBCWnLV1q%>4LSLJYL{j{b2<67VL8fOpUVVFm$m5j**(xjM*6p4t4tk(u4F)Jl|=L*0 +aE*wn*46UBw$Jqms!411cyE1KWN;SUt>T|f8faYV)!=J2tT$L(}%8Yi-OL{Es_!~32*)Sz9DWJ?)tqR +Ej+_SsqhwuS_##JA*2%!U&sn&)gtn~WqvLKaBoo(b}h>@%Ec7>bZw$t*!tp)S0u9p7RMhZu%?lr@c=s +#AY0iD+ArN0gtQN{!>O%<+v(N_5Z;E9Fn=gnK3)Y>?04Pd(aUsGOeV!Q&ga4Gy;uJ|#jMlBul-#DRVN +;JGL6#&|L-^fjOqC~kb0gVGMP^CT`vnWX4>C@>CByA!bu_DtB0z#PJyJxLa8Py9k4JKE9#DsaHWwIo; +CL=yC{VMLTL3Y>>I(x)S(X+8~^^C|ECEw2FCVFH3~m=H!NYLranuwn#c*l&hQ105wyig1hMyV59}TIz +MeoJ#1K^3f2eP6!HDOAo;i!r}<|`7iB4c{nqacrvQNB7Arz-~@z2ft!`E4CIen+<63F4^&fBYx|?y;G +_wd7%^t-*&>UGZ{;wNOGXtYYPbu9i{s>v$1*WQ&VJ{fGo}+ed`h^pXWLp$+46jxDFNXVm+}-Ocof+ae +pe)k=!PSY0EmVVFhbh&j5F>Nl4!sbj&H{jwH+h-4m#pbHF7DF#E`npSt%a-=X-zLn}WOKkGH20&&|eB +?CUwgC&b|=k9htFoJm0k*p}x-@W>lwjB}sYBVSK<^kcUi{^SZ^7iOGu9+ZT4m@~gxp1U9;I_z{I +$Ct(9h7FUy3d9Yy@|tv<3Wf;*rO|#G{$-myJC=(dn$o)U`Aih&H;A9t`LyF{A@g#H<(oO2*L>Hw +k)5oZY*5&sUKWggxO4SCcql<{b|XX5k}-fyC5kPE=w4Nw!f5Nu4$5hl=vfirF~@ +|f2G%&2~UHk+@DwiQ1Y+oDpfa_8I*t784wmhF!-q5mz^QrzB_RoUI%?zL*Y+_&ZCpZR)V&d_yxx-- +h+qKeD_z-^-e-MMii)`$2DYSq(arfBu{myqyV-8H;?UqY(ny@uzIs5a4RIOf`s{MVl}++=X%DO}*TubApjM@s*-f)kkvT1^=H^&xe=xYNlsWmV6;RFByZ-F)s%TkXc +S==yg$p&D-z(Gfg*YkJts>kk_0oFSM51`PGw)}rVi3~WVC|{g{A*OVYpNL=+^p8=Nelj7>q*bqYN#=% +-qj-NXU~+S=lUpGZ3{*R{qf*#rN8LG_@eqg+XHc`@ldpi)NdA5H==u}Jzy*>I9fQeYXieh%k`m0zSd2 +Mi5@N%FsN&fUHcic-ppEh{OI}USy@c2RHF`r_(k={*5|9bZu>*WZnSPy`>KKF9?bdJUOGJ&*hP|@>fX ++JiP9p>vG2AtR|>vJ->5$*ZtP`Kd{Sbw(>A;)jbx0~M&_VtKlktpQPx{e)K5fTLvQ!0yX~*+8Q6X(e=Nm+iR9yc& +{UVbK*R9DQeXSa#9+)`ri{K6&-+GCwHb3jP*Z8s8;_?avu7#dKTM1LUZ#7KJ=zN6F4z=2+3Tgt$%m9>~@YwfmUH^P~JqU~To(PxrzcOAjB%rwMug?Yn6aYan!Whf@1^+j3*JV5i+}y$WWWETCGoGv@znK`qx}K*5Gf}^e%<3UGOfS=6M8>6e4_U! +xOk|%qst%C$TDymOpQnU%k0jqCW`(a)FPZe70*Xpb;=49p!)BL3v~D*&z5y6aKTCr>p@f49KYQp! +9st-!{}OurtPhw>|t`ONHmKB@12)FAqMG5bGIO9KQH0000805+CpNk~!&j0_6^0PryY06PEx0B~t=FJ +E?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoWVQyz)b!=y0a%o|1ZEs{{Y%Xwl?OIz?+ej9E* +RSZB)Yc?b3Zrh>#wNQDgn@4I6S>P6z@;Y4*n?yWM6r&#MPY^XL)=Zr%@sfvV|6LAwFh*#z_+4`~CeYjptFBdLgbKDvM +oLQBJm&4{&u?iq{8kgq+Q$FwrZ%BleR-T##%bE_9*uuX<5Oa*(BE9$&8z=Ii3k9#(|-80BBYd7Rwl@x +6E}fUp#0Ce9zqyDVMD52}**I*;-PV(li^S`^t$`3=C{iHB?@=20qgy@-q2JcuYolrDbBa_HY@i}>b&m +R9Kk;SlOl=l6x-@WbgRaiR+#6(4k}b3}8#x=!LbluzQhP75ufLM&;mxU) +ID}Fz|`t9t~mDoT1EPmg=xY$3v`uq;EU>bLkzuHoKzeEWx1ft5Lw0ru>+ju4kx8;Xg{K9U=XZ(#C11Ct9~MsZTqp?^kt3jjxBrVhMdG;v11>r7ynaF=_|Z*U2ud*!=n^`uUD8#u7qN`XxaME}?!D- +@x=yl4ZFs-e*Ngq96C68z?D*w=xW*5T7owGV~)3Pk-HVsJ!xESdGVfbz5bLnBPTtG)M6ibs?;ZRg@$T +Vv*^B0u=f?>V^u2%Bz6qAyep>Z*eNsSiWB+w-KisMPvKu_XO#ek@B$)~Q=Uik)ks +0N0cMY2fYcyha*B7$@*UXmz-ggz=>GLiwiSPJ4MF3NY?+V{1kR9Q>s?3Z652X*032skui&RFwlrxAxY +=(6S)hW!$@gSP<8qEZrCQ#i4k_kLbXl)8rLWR#Wyu-T;$TXpX3`~n%S(%v-8hEU3;hK>Oc@D8g>-ao_ +IRvW^>=2q=m?1AP)2jwv6u3}8q<};P2rQW3+Ql`+HLJ`_5fr$=Y`_I^pimOx!~;+&32_N=aHSOF6yy} +-6yy}-R9!c-z$5mRf{KEQf{KDl2-?YWhcf>}Z8c$ami7GwsV1et*fm7SsspB1UYBsdd_RH#m{PK`kUjmT_`M#Id6mgxeG6 +(^v1L^VY3pngO_&}UFTrrMEJwVOU8GdF?v#`88$w!fy*UsLIar&4>$w8x92F|uLAn5jfZ~c +s?Md{tw&003bjX1GnJ;*6yg&|QrAr>Qxj(zHIt~CO0#+%tf$g0;+rB{k`Rol=H#7Nbs@U5?#ON@HdE> +O!)^Y=;YRmqxS^`~a9h00aMM3H+z2TfZuL~c2_Jt!ChUBcl{iEf`j3@P=epPfir{Zpzln1kBF9qkd$Y +;TESxEOA6++M0^v?DkyE;zYux3k^b_o;S*@MwTO8VO&gT-rP7o+KZ${=xl-|~GX<7z;_{d9bT=5=LH? +N>kR_oug`V9kez)xGXyNbg05kmJRt4sFW=}K-9g6hRb2*`yO^mvkM41wQww}U{fi5YsyK?FgKpr3=se +4CeNtPf-O-y;}iUaf1y6p*UuRZXG?5vVQKdg{Pp1{@Yzze=`W=CJw?LpIdOyt^xbb@od!#eerH +x2L_E?b1!`}5flrpgFrf-ey|elmQhD)P=sp~Y8}0FhVD!Df{iq6JWF<0HK=Sa4D3wL>c)096srlh7hb +Lof;H#v^fUEGiY65@mXu*qlp<=Jfazk)Ra-WlpK4*EN90D)q@c>Izv6ExjX*9s5sW$Iwl2|+gf=+ +1?WQ+Yf7*CDj05TC!2`L~BI_x+ib*g;V5x@PY+J5i0G>-_~dVBKh=R_wQ#0(KJEY4m6>JfRK@g3!11r +y5^8D?KD`pYee#@beGvbK}iSgrP8=iJ;-Yo`)ohnD^w+M*kAMV6xq}4=V?W*_rqT`1~xi>mX?MWaZmq +r#ppspf7tqFuRUDB?Z3OnQbK+Ts2dk^36fsQe_YIR>^(0WIFS}_MVMeGUGOwAD9OlPigk=gK%B>iur4 +2f#XtUYqP_|9wYc+rrXZun-{XmvQ?;jOK#w|XOd#BJnNT}A&*M%>C!h68&FH77IG@x@o9Z*#-4pqS6TJhVq@lLeQ9kQJ%nKru{iVXZmf{&?zm(f0j6p{WBqlg +;VJ-K9)wU6T!hZY8?n=IOgHkz7SO=tgb?WqHoE;oJrTTd3cRleQJnDIDWJm;?HmRaaiu$1;8XieohF?PJSiR*TwtS6Ff5!;nkcsM +WzK|5uVdD*x#ama!5yUn-z>g>*T*Ox7y?MiHAL3R*y>wWl;C+&Z-x-U2CM-YT9-rF3wXBN%`>qa+P>A +S%UB5)^Ad-l0=*e&@r2i+Rr+2~Hh9uDf8Ve57u`|Q&Q-h4|w@@6aWAK2mm&gW=Wi$w`2Va002Ej0 +024w003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMyBSX_+UNcX0D%@#+nF7 +(0&gFYGLtU+2j!d(B{B$;ynK-Iq66+W3!9&6CSK%I_&^S9u(>BD*TT!LYaNKD%SnC}nv(ONv@O0#ULk +o&7V*G5$82C0F;7&xD?o9JtdG*9CMh++{+WO2V%4(C~VUHOY4I-qY^a>dfD^x3yO0d|1CUUs2H=hp}5 +r`tXY1%#sX%N!{<$MA#X3aSt0S(f|kT~?GNdc2FVTnfQoi+~HpKAxjz*$>-4`TdckvgJYXhttE+>j@x +}Uf)I6F=0KPQ>EQRc{C*)9Y>2r0=F-s%X$39qXCnD)9s7wG)Fn$KKmDY>B%tkAJ=xA=ZwKkzJ?liBQ= +851pZSRsga~c`j2bN)daOQVn?FU-yO6NZGbjJ8=;MT5ppzvCVe)93=JPb4lyD%JKPf?U1C^>VIhWv7& +gGL0fr5regO3Y3>}0^tqE&u*bqa8m}vlYLtJBsz^rUY*9ar2sm_P!qXzZE5&FlKngRFN09FifN!?H(M +zCZga1N_R5Fb$=)Qpx}GlWxPSTctA7~*4yk73CeGmoKu3@689UviEn&=6{l;T*W(P|F9Enh~7hLtKu~ +ATA&-ATA&-ATA&-AT9=IkQ0y-kdu&;kdv}fGlm)oaS3rrF@TuF5Q!m@&M_pwkN`shs16_-KsJEt0CK^ +wQWHT<0Pz6gI}qQ2IFc`se2L^sBwr%=63LfHzC`jRk}r{bg(XsRi4aTDh)WpBU;z_!3&uh<)=>13|Hv +AwW^kA>k|AfP5JaVB3N`SZ2@<8`kxHBk8is~gF~o!+CO|wIWCQw3>Y=KE-wbL1H%30f2?qEvIL6=rBZ +J`(qw?D!Okp_U!FEU<_Yp4^)M{d=2}q2F&`c0Vj2M9)$YudS5#j^7#@~>pLj$q_U0{n>YOc8V%JaS@s +X)}8+31;#eik-*G7nh{v@ZJ)?RXFIPDN`gxW{X2JZS2=t@A-$l&fkS)_DEO4r+2B(x561n~J7trb?%Z +rz$6c*&z!Q=T+o1*1SiAMI^O~^8{JYWxAjtOCnKXHDWnpID#`VA2DFXdc%q-iCwUbPSWt1T%O70nOs_ +OdFFcj{DvRH{yhfAbu!CDTXB*ye}S#f +Pw{ND#g6H}Q0hNUTdd5=XwHiG&$~FC#>E?Ci2noqS4m!!0Eaa1jfdNV0T=qd;Bvjq+Ke;Q4BubB>^t!f}=#Trs0|zi-oY#M4(}2QPt(O9#l1rNqRVNA`UqhZ#9Xs*^m;+k1-RinzgIt$!L{H`o$|J`zQ)BSaKM{6`+ln2^EOTz7s{?pSRh*qWP^T%NZ!t4SEFdIHpNJy69cm +%gEj`ziV$z3(tJ?k!LZ;l-a9 +R@{T7yXwLel*=sGkMY#JH}+^0I9Sf0cOqV-l|vsS8ig=!Lg^>j{Dme#C~S +gBwG7U=vcB-k~ICl-@Vq%lJsgKqM4$QvA(Ro+GBGVdEC3I +mC}MT4CMQ$gVCXc$?rv1SgD9R*#c@D$tFY^bZBTXre@X%{^=2WsE#?L;3Po?ZPeSaIJK;?{z0y}KY|M +yLDN6D=!iZ?&%q8GSNovtTb&b{4wUxYQVoWG7KYMek0{x%HF=5_QR#nXz%u9b)C|iL*tlT&W+to~?Y{%-!hVmmEGn($^w(`>^{>Ty> +>XVAgnpN)-AO_&1iFuD+e~cv=($pqbt6Wm8Ea5e-G1Y2M4PySe^^vbMwKoyTEmc%tbi8|Mt01u^LKV| +A}Os!+3Ufqre>zv&UP1bKA4P+&(EATy@b8Xl23o`)^pldsc9xuNwn9!Crs$bBAx)(Zhi|?r!rd1+P5s +Lzawk^^Ju8dW^l8T3^$8@rJox;-xQtyjalN(KGt0!*NvR$zPD|e$AnhyS=zyB-3bqmK6zoLt;YjHA9$ +hkB9W_i%RHA9543MYkKGXC@#x5hrmHJFJfOARm9~?-D)EBj<|8F#rHJ0 +001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKl6MXJ>L{WovD3WMynFaCz-oZExE+ +68^4VG1y?S4WMR4%8u<6_aV(D-C)xsa8eZgbWm(M5voXDNp9*p+<(7^k|~mUah*nsdqE>GlF8vSGtUf +%w4uGd_CI=i`tJOaF3wL*FK)YS7h%tOrlO?(kivJ@#L3(8wCA%7|IY!)nq0UIW9hL7noNsA8vrt2gv`)8>Laxtg7b% +EGa6{HetxrVBToL-&m6PrxNfM^vzpyMc_sg%uVDl(CN5%bcMlO)d5@NNY+UuFA8=plL^q@U?JjPBF$k +zNxl%qdUkdYwNc@y35p6@_(yNp&M^5RoQXIS6lAoNec6L%>P#APvoVCu62KSiz9A7}TenfLAC+@@OHARRG9?5r#FxV(-=kkN~G{{i4>d@yh?*OU&C+!yg!|u{EivNZ_h8zZ$C-v&(3czPj +7DM>}pEKbbUO%JwN$yaXh8#57X^|N9aCGmaXFQ#Zh-%z-qILTdlN<-uhvabFzNc!1nW6=B1$ie5Qo-3%lFo~X{D?fP3%9P$`va$f1wz;kFcL6@9{t}%uVrT74Cf+^^mVBAB)) +Glj=8*4_;F!BH+8v_*XlS4GA5pai4!(|_=8KI3ac8LBB#fQ=wX&^ox%7)?L7^2b{*(40C^Q49C{79Hl +KLH>212fs=jSu4{-tM_F8dy#RE$KHHp@E-6Q0;@O0on-9qs_Eo3Bf!`dkJ&rIjBAmXR>5r3c3e!y38H +<8DmI20yGWKCt-Z37|1B0`I7=>hDiDFZy<9*!a-a*I6&V}MolJwoIWZ7&N!fD3L?*l1D=)K%wY|O7-5 +(LS>}cmC8<@4;m)Nf8j}!!mev#QzPt|#7y)ZY8U}PGyP%2WbTlqCO3UOk#tzX&5>BcE3?Ee#FFa@8ah +}4Mq31_6`caMk&#Mv2M&H#)iTtQWJyj!|weejpQYR&R%}R0{XEX8VO2jjf9l-+cXY?<^6vw$COZeNm1?vNex<~DjP +>c}WRY)2;p+dC)@?yqex-pE;&jDL7y|TfnwiP@<{v3@<113UI+p8M7qw|e-d^-+;tOycvkwnSlDP1O9DS;oMOffWFQL^ +_tg~2U@@S+<87|?Xz_L~Q0<@YQ7e|;Y4llQjO$T!D +PZg9|fM*7aZkylKp%I{lXzH1(eS#kA!N@K3MF6{G)jzZ}@(*QkK&{hxBdh;utyyAo#%=F2D9XwN?-Zf +QYCcuj=(3fxctm}eiq`X*FjW(I6KdKbbiCVvVhD>FF`YvvBz%0)7WZ$*z=_?Nu)4b-8ZGj!3^2t%8s1 +E%tj=5fAYW*AL#swv;_%|c3Gn7{#3Wk>!)T7X3-{il%TT#&au^o2}pqykCSO*6t8zu~ESkRG)-x;S{o$lQ@VDfIn@rRQI&0Km}R!+rOOQ~ +jLn}|>JwUjgsHCuZ)1lUjcyhk#XPUo8Z(Th@2&enTRrGzzaARW(XS`=-&hED5!h;s#H&nio|Q0nl9MM)Iy^DmFrsvE~oBqU9ZYX-kRvOMDnXeW3NGdH_tEq{g% +e73~QG4CL65Q*HRO0D4hx1_}mhOIz{z!fN6)xP|NPjHgNi+VuLsGV4L?%v$t^2=3#d|P$P~e&-A?;q+ +T@|tFgIk*e)D&?>_B&gvEi0xsCD8wa{Geb!|tbmRqx+zGc))Y&(_K?+3gAv +ONnbfR|jIyYsimYXIyvp_y#PTKM)d(#lx%`lXoO>yBp8U1HC@1iu5fl ++eT~kpk95xef5{h+cdMwY017W{(z8@L7zHC{F$ioPPsQO9 +KQH0000805+CpNgtwn3Z4l705&WD05|{u0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>W +ppoWVQyz=Wnyw=cWrNEWo#~RdDU85Pvc4we)q2^9dtAxc{uKN5)wwM6~loUwA>Uxqj_4HqycM;ont%0 +WLNv&_bWS2w{N+TeOOu@+uhYwUtPP6ytmi$S&@cY({MR +UitT6SSrS;nKz+=~?$PG(^KlG6U^0ZGT{f<+_wA)N#P4VgBfp-NQzQ;l=%rw +|_dk5g#0pBx-#=&ro@2i^L?bL_v;N16Z?r4ilE(w8XADDGZn=w1-U;Y`qyaeKh1b(8jfKbHbJW5 +*Q9X4m+J?*R0-6kFDg_qAlyzL1Am0Ym;OkFi6Sqd36CW&+U(~HI;D1d9@V&!3@3ACnT^23bn3ml0XFodFS2u^xbG)>ggG_b(|wDj%b{_D-dJ)K +;Cr*9|2;mP&=_fMdO+c1k@$T|71lfVaKXcc>5IsTIiVd5vSe2rj9q>$$aNv`^LxHkd7U`#LGPX#xR6mo7%9-?G2+ +sKDO6h3GAVu?2BC-R>tj8dE4Vjr=CP_B6wT(o~}WYFl)rmg^y7yby~f;%if_n*M}Jcy#$rq5B5GU?R` +);dxM=c8~PLG*Bkk+wfNyZ&>{(zIuRvFvt_^Bj%x66B2#JV_o1(`4!e!HmWc@(T)*`h~dRfZ;Gp)vq+ +;&;bXy+V`H-A48Q+<1ia`k13hGK7#N5WEzgrsh5Xn#(Kf>QDsJj&EBGToGp~c)RXEuV_xb +}NGvyse3+UxapHg1lFdIOsV!lol!`ws3Ut~_>xj^|$A7DAx&IQkLR44_aySE}P!bOaI!7X2QkaqS)1! +jb4;(eGd>y5r*7ZAH_aqv=B8Q3otoGFWw3BD3XZjDtovkUU^ojQ4O4Z&7EEvFQO#uLnsEryGVr)?s$I +_E||*s*h_IZ2GNejvPx!!~m3#04^QAhola(#WJUdeuU2V16x8IG8P^50`ySWl7fxIFrh*RayzUB?p^c +&7z)P8#B42Q0%ihN31+aSMJ}5Tk|a!tN#XDW7Dyh)A`lB8L*!$OI|TGuL1uDfTLLfzFU}T0YmP;UN!P +(bz;(IvJQ%xdDbTnuWEZMII1sSD80fHbc@jh}B)E`-#RO*Lf+;%npcaHkmxTf~=q%~-BJ>UuK{5;|!A +!!f621|DDd8W<^RSQX@H3deof4s75wTyv01yebAYuoxBsdjTCa6cmNPvJ1PCSlh0xi_Gh{G0!B3PQ(K +!TY;1&&u3kqDimg*Y}vmNkNHHRxs0U>$H-y5a&<6dN3hq7?f@qW+qyaHNuBFmQgy_>&)_UUr2v=LY@5 +j^lLnJW``mT71|Y^aany3e)CP_U9Zr{Ue?Z)iY`;_OucOrXA7!-TJB?WA%24nwg{J;^)|ILz9i8`8c# +kM|_~e{;tg|@&}Pk^ED@tSrhXn7guLK$COsHq}5H%nD$y4HUvIj9;^X842y#sL`(J1zCwkUEnNdQS(IR94%3|+bS2#HqQlJkv3^7<3JeI!1PA3?TF@VTowmq>#RT^=3cKxL7{F-HdYbTWv)cf +oD*_^Cr9Vn|2r>~J#JcG*JE83m)68Jb77hO!mvSsN$&|IFNhTgs!7y{Kvv|H$C@%hm|j@56Rv@vngdN +0DWB8fH@AUCu*vQ$+Yp#o+=bN(T;@g~%QbPCyz&W3x5hYdN^#&CDD+XFR*~u_gSOaP5eL;ADE2|uz@Q +Jkh8IMG7uLbEa$hL#5OqbYYTa9YR<1XzY5`fYdGRb3+RHhbQXH5SsVN>-ctI}{6&A}`w}Qf7Ezc?PUN;I_(ZN0;ZLFymlr1kDwxP|M7QW)T~Cp^1g%7!{}Nf$9#Rqrt>vHShcz*`WGQj6N+**Dk{>h5a=Uj-IdF +iF80QEpVpVjYdaN`jQGB0RqK9rr>@Fw%!RUP9J`u0)lJtio)!m9^VLh*=HbtbfqF{q!Un5}mPJJElxC +iobR8(d+Wddxd~4f0eAe(nS=zG0=B^M_Z6NJ(FbP}dN)17^4m-xZNnH0tZrG)7ZELAuzHHU^z4 +o~z6$t9P&lWpVU3ztAs;0SqvUG)CC;KSo9vP}*!H;F5{c!VvcA=5Ywg|!bp*xMqHR-**5Y7iUMR;wS$cyPG{mN~)oh!Qwq)b_D(!w}YTg%g +-LB=r&Jp~7Fpy;iVlh}g1v_>%b;=|2gXX(csMo~JvSZC$s4Hch4>pn4szM!sW@{dX8!D1{QZ=)(ZEs# +{cYc=&8#8Dcte%*f&x!dRe?0Lm|1>NAI-&S7;ola~hf(Qctq;f4{1q2}1oC0RpYe_Pn};hejs0Jsu6* +y1k-gr}CjQ6^ZllEKFC~Wj4H{^j!$F@v!pMkzC^b0?pZVL&OO>W72En-(B+4#OB`Ur4UKPfFdow;r`_ +1|fe+=>zct2GCn8N5U&-yP=O9KQH0000805+CpNl>?%e#Z&`0QfKf06PEx0B~t=FJE?LZe(wAFLGsZb +!BsOb1!gVV{2h&WpgiMXkl_>WppoWVQyz=b#7;2a%o|1ZEs{{Y%Xwl?ON||+c*;auD@ci!D3s$&61R3 +%PHo>C=FN}}w72K~NAFHPoSxI +!>G8?=^$EQ@yEy(kt+Cw;_UPt8(nXQnCs~}*aXyojl=Lb8XOgBdt{)#4Su%~Qyr5~C$gH9%Z1w{^^fX +JV1S5Zw-(;H4WkLBJRUV(PKbKWGjpx#Go8(!E%VM4vs|z@$%e<)XPYW4Waz?kymB;>6aiM(8mze6IqF +2YSiBBdGTzJj*=_pOHbXcHbtQ|(Qgis> +{4<@&5=iNT%w&ORE*H0HGR5GtWGb^#Qe4tp-76mqQ|}d!>jntD&*6T>?pu-xo~yaP$)dy^68l`w)_5E +ca{Vf<6n6yG1&H2iVf@r#BxjKHt#M`4{ +^A=<4d|{N~GB*n(+1MgD3}$>SUnoDrfb;;dQ%I2?RBxjO!c5l8P%&rWZ?DD>}7Z_ZDyuj&286&=y#(b +diA@#nLnE4uuAb$M}pvQKm^rKVVs=_9$N_zo@~b1*rRRh*<{9r_ofw*$1vInm)uuJcW45S_q4B5vS>rX1Od?fF!>|H%c%{W|jP +2tvn3j0jW;nd->~?tQJMKx*Z-;xqQ5Z-&gZRHmw$MEzy;2$hT#~7V;Dv-j9?hSFoIzOhY{=|*hR35U>Ct|!r)* +6!wC#0Fr2_}0>cRmCkRV9pTKxB83@L3APfdF8Q?RhlpTPBv3fYdF~$+$z%}>~DrS%;MNK3&k|T5Fl0v3=$ZmGBZ@?7%0>;MJ{YZOcHW9fM^8rFO)bAV4ws7@(AP#2uDB{LW +v1P(?|_gws;2N35Y77NTmsb!KfH21Tc)$L!=XI3(QV{Pm#I?FOgCqY(PAL*g!zK0%{bHCAtS5z)(3-A +wZ1+au!O~p$Zj)gu3Q!l?1PY;3>&CZ2sR({?cwD{-?XipX?&Ki3Hs)qDoP95>+)j=q95rx`}E6yXhuj +-Az;-|JS;SY83r$GHklZLDNkX8qsu<(CQ|tQDAluS$7lFS;oF@GJJ72!Dbgfrc%9C!S9^B!hW)pe=KA ++mE|Es#(u{AyQIK=>VOOT*<`ps4o8uB&Y2im1_%3MBtrGLka%hjRsYz26itTeaVGDvNy3)bwqW~=vB} +Rt+v?8Z?7oJpx*QvX8$bM+=Yj90@Z1rNJH9%vKk7U%4}F8Vb!}XzZ?-yv1lZuue*}&d0=@76KDxH{W&Kd|-N!u7wQHSDl@Kuvyl3nFU|`!dU~1F6~-yy7J~(HlY +j5+$L_jD{Cck3ztT)+ghkq$F2Fzxv-v#=9@KVyI2>@JZ4sAtxUTAhSt2btF>8p@ygV%1<^9YTNU!A6L +AZ}E_Z202Zrgo7EJ!dz*VBU+Eo@@#fO8gChYy0-4l1AgZhTag1*w-hqZOcnm*ueh<4KxeLEDRd2?k)z +mwg1n+3fRb!XS#rW@#-Xhya|z&&Rc0%2v_tPrLexixRSFX3%hUdzD?m1yEI)fTonXIAW99hjk_b;H_) +!!#Q0#$ad`SM6EX0c(}7jcshakKl)OU~0j1JM+6p&lfr~i=84co!``4*sediKWmL>1ZL^k6#|n;tpme +>Xf0e!mJZC{16-N91N*~QQnuN*70=qC%o=3eXt#lIAiA@0>si=&q8$cCf2>u6p4DKhxv;TV2>LTJ>wo +S9vjqY>$Gmgps@+;CVsU0{Q>8Mec6MbyiJ@h2Sb-D-4uqJC<1Wy3>%u6|+Z^ME_uPw#+@Dh&srG +t|jKzg%4%7=Bpic~c8r1UB!Rvf!x&mxF#gb1^ho(8AF>L3>ATc4IDe2Fs6kW#L5K<-laY%x-F;$wI#; +nmGL&*wPA&UsDD4O3a+0CaG-*Hv6UugfpMpQhFSO4hI@=e~`O7+0d1J%ZI_!(}BJF=+;8$&4RnU1-=? +s-=Xcm+FCGByN!(X=InE`#p>*S+yt|JPwXnu&QG_=b*hoKsj}5(wBTmJ;y?`Ce!#73Zei%IjTVX9e>` +g=?;#Kl0#~EmT|!e#eU{y_@vD#-2l}B~11^rW)o2zeJ5FH@bo+KUt%0x%yDIB);Of9iV^{O*I?~2!WS +&`tgFyE}VO@E2z&ihT+nQ%>)Y0p|k@&05Eg>W9z-76=A9NA8sGKagTzAvOdr#Z_fv*;}+aGj_$=!$8{ +P)4zXS?{-)+f!y(9eX8Ch+Y6yNY|J7W`6iwdrpA90a~Kp}U~^5wsz6Q{(>K*qyJhmB1G(bI$s*UW>q< +!S`oT-@Tv<-$r1&UW=d~RbPu6h2*X@ehxMwSoc$cIcIh@-21!w3x=#>~|lzccmz!>70^lJ6MRfB9i$`FOLOC(}5+%*#Z*IB})kScN&;pA6 +M287rf&QqE7Zd-W#wnXD>Vz~H7>$brUJ%IZ9Rl(_xV>Gj2%C_0$D5kCe04uao1Z<%clZSy;6e|2a;H_ +M;OHwxk^xIMZ{WppoWVQy!1Xklq>Z)9a`E^v9pT5WHmND}_euPE*4w28!e>Bh0+ +jP64wo6JU+Hzgje<|DD&2^s=kz%%1L-G9HQfu^f5PMpkXZx9ChrRu4ts;i3(@80$QqYtMa&#&m>{N(i +N?vy@UT%Y`lwv2t}y`$-)qU$_H&i3Cd=#gS+1f|&FOw!N!(Nw+ciUa^0K7NW~2|3Wu$@{q?*^a}xDNo7Vi>+&&68~Z_36 +5r=hzSgWQa;2!q7Ueepdr#|ZMYAZST+QR677rpyiqiS7S&sQn**spXb<--H!yJveRQXe3IQ)3^i7r$D +r1VjxDu*>UtNSFLVe&;hQ)!_nDrl+Oibu=TnFey#0HL!C;wyIFlZw%=b$?ZPffkYjVYD?8eS)v|qEh3 +BH(uc}kO +tFN%r+7hWR{HcUj}beFz76j}iuJFLpq~wVIuIBXrC$=b;11Kz;sr#XC0UmH^dT!sJ@oPza|0D6yLCY5&{1j~biqk36o3C$j(JenbRiaHQh#VSgYHO(_sXah-oN8IRu(P37q?`0)n2nld +?96hLCZ&kU<)2cZa+#hIBC&oIYjO9{`n@0DEI`XFHcOx0-?rC32QXsQ2HVm;T+=(@T}X0I1lhFe46Nc^dIW}L +!1*Iag0+`Vupby4$*vw=1Jfat~9|^0kHz2CITn!C;EQ470p47hDJl5#u6un3w;mmLW|P~(S9g=2~

  • +ZI&?blA0YW9v%ArP}qYOmRP+y@{6 +QofcK!E0iv_@P$E+qJp5G+BaSv}sqPCJ*Vs}hrH +Q1WCYww6Nuxl-v&6-O{J_y^h-agNk_ASCab$iXN)9NB)v@sJG|4?-~>>uzMmlK52pPYeP?i0)3+1F|o +6KRzND1j7)*r%0t2QTk9L)rk+`=!eY_;Ha>eK1=UN!H?zH;3Uuq1V1r@d^jQ4GXa +@{6wS`)0kZX`-Zu4u%_M!aeBjP``qz@WV-o +eH@$9VWpnSja!oW?pn{3r%t(RF2i>eF8ggB~o7HKev|WvS)ot>=Eh{&XXr#H@htXmY7-MV#lC>AOwtl +bouSK>NOfm_5v!Mj7y|F#PDEOq1`RyGZ>smv?-qFC>seu2TK)+Ap_-R<;_^!WX0JVrEm9UYnE}W+ZJ*Ygm05M- +<6-Ue1ikayd~2z9k!HOn$6*v!FKDmi{@qh4T-YV=vD^q-e^2x)pfjJ7fII(JH>&`M21ikg*BzT^l(hD +xu%czmwE7b)fxD<+_f>t(RFuc*H*n*~UW7yj4?!%& +K7p>hkM>r%}BMhG1)92jkG9m4(LS|7GgoxPD~U!yPZ`MTtB>8!?XMewr!83) +FJygqe@gwG1>tx#TbcwHyjiqx%8Y>91CO|v_51l?N2J^I=_JF!1_gl|`hQ5JRuY~O)*;J|(93R?}l5- +|}`Bj6=yTWFfDprz_n2>9!ceJA6wDO&OMC>x8OSsJ$4^~?4cspojsUY?Qc`;px*Hn+TLUvRaVGT^Tc3cahov20-=XaA08rSfdRML$#G1kM1_iH5Ejyv4J%k7%{=TEW_FnGaa+3wz`9MP`M-)F2jM*B5>Ma +RfZqy@MAd4U(xYO;PX&xtF&!9&Ta-cf7#yU*!0+sN8;bU7P_>0+gE!ZwLKZ>hdFTndt?)=i)hO +$&;JO)8wI>}f-N@wUkJMUcuztRox$$is}SsBUbDH{{g)HI+`j;kEB|`g#QHd(B5#`qKpSS;D +_PqMv8ZS6V+GQQyZ~z8<;MANtMpw+@$4naAJtSpK0yHRx%&UdFR1xyg!He;;wHzfr@;U@(#T%ZqBz7p +0b`>4W}u^Fo!S$}!+9N($v0M1?A^q9=v+pMd8V0Q$-MkN)^$kwjnA;Sr_TpON=pP)h>@6aWAK2mm&gW +=Z9ms+oHR003|l001=r003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMy}$dF$F +$T%u_;whpJU0wa^W@;;44VURfZPOoEt!+G85^`%FciyJRR@ELI`+T*XBg;j3H%%#WE;;D-KZ +ArZe2KA){gvs^E}}Ha-}@8ju?Rzf?<`~z>4&SQfO`n;agT)&12=*t$)b6lN}C*U5=X!mXkMr +P78u8I;->PW1nN~YWlJnpFjgqLiu}iNF9~>oPOl-ra>*1~-J60uQXhDz&Cann_<#m6&^K&9cw(@M*lZ +P4&;shhukQHAU^0eQ{{eorMx$1L{BVo9SPC4)0>_s4Vi|BWj8RE9RBLn`4cvD|)(=Fq+TC7v{6OB@-E +qI;IA9M((1KxWH11lHUTXxy$!IumI#nz#V`+*hnfsEQrFe!W7XmYhlf>mg6o>wR<&Dt6z=yf}%CO8H! +&&8niyg9DpH;&^gwHx&gyadm1wMmNs0zGEj=h8Jxl>)VlGnF_v%;%Z;L1cLH+%`O1P;P&K10)XAcU+y +TSSUf?^}qi)lIYZ$!ye2fQf^WLl<=VcPB1BCBv9WoHW&BZCOh3gwbR5XpUJZbeI}yVXBDBfx?PLsS@i +8b681|_1@6>9Ir~S!2e1l8FnB3X;Py;CG88zb}^Nqpy2MSFR3f=rI$3j7!1a9 +PUj+1oB71kwSO6hS2#~b;0v~Yub)cQ$edep=6sSN%q-dKR+1028FGoG>&{<<(8n@`XVp_@CSG1ls#Z% +Mc}q@x5G_5v6CD>958c0p)PDaB)9krWln2Cij*S*VZh2 +Go;0b(5#N{d=R=G5TIbJ)7V)*t=W7#R`+UAO@wJnFv3^#L-HLg!h|g-CgiCK4M|@VwH^|H$fMkB&5#Q +are1mO2?}+a%oe!jQ_%=vxgzFGrr+E@Cy=ffrbyB`TX7&Iii_a!L`(3`lwx2ff*|u?E&`t-w0&YIpvm +4->iEp@(UE@9>;4ds#qpXgyP{@T=Xrv0saQv@T|4+Tg{eO`CV=d9lAYW<0qeX$zO*tmF$QP|us~rDnE +172F$gf0PCu*Wcdo|7ESJZS4YSs&XOBCIy?ABmI)7)Y=3+z9SY8L$*P&o~~<$<^;@m8|Dv9ZKM9vQ?v +AWWwmkBZZ2Iby*qk<+!IU)|Kol<2K0@i3{%NSm6B1zYyC>U7a_BSogu?N?f@f(mZn|5&(br_MQGHDJ^=0qk_XZA6)qgTbJ^>%gdlUWvvQ6^EhM7ax$K +0_^UOaon)Oe!!x??IKcNCt9(YxfpvaR(bnfqew!4+EIkyw7iM?9nK)7PtNyJGY;{NG9-ZK-wQP_D5j&z<-b4A=_>Bwy +9=S;~t&Y}@wZ`Yz%MHH^l-l_deJ??Pr@HvVPC-e`=u--IGejc(GNO-n@izuM_N^oqpgiWHyoo!fUV_~N4Yp_}%7r%&BZtKA>9>8AVG` +h(73FG?3QUNAixIhRVr)Y2i7wA9l-WgH8dDEY?5LK7^6vFs>h$AQy^0zhk}t%r`1P6BqzZyf6t8`2TE +0@uLz+1Ws>7^3AeQ8ExtYGv_iR@!7Qa7+Vj*7Crxa2(Ps%{=Bq3FCdOQiNJKDz_^1yj20>WM6A7D@9NDM$^ZkSb+p +n_xhm2Lwyc5YSk8Jbtt3MixL%r1YfITv$R|0@B +0(#vPFG#&x#Fl8YHt=1~Bf*fR$wumR4S77khs1d?KSwB6O$WKI_R9v4q~o_A>zqeXljP(Ka5dAb`rk` +TQ{hD{ojq(kaF0q1jp%Q?RczB&jmD3v>+sz#$5K$4t_UDX|!YDvwC5&C-jPBL`q}i-i^ +fUU}kgOg_nJQ*Rxrr-x>f3^%|oEBbeXG2(Is9txc6~v~?cZYr?kvz0s(DYy4Vo5KTsqoO`IK2AQx_Dh08yIA}@iHS6JsGL;YN@QvId0OVr?g +xsS6vfb0+$jg!!O>w>&CK8oy%sx0(X1kCyU=Yr?#rklP`m00p=?JIP9kB*qb3{fR|zCzueS%W#;=?zEqB^!QPRB>-}WcxNVF+VQ^=&1x-VqCG$ +KeqcF8K>+p+UYT4pv<=1kwRSJ!B&sX|FoBdkg0<%w!aE)hJC8)jb`?AB|3`+*xO`;aiuC}V&Q8{-#28lVhWP=_GlrPbN2;Hhf#WrLZoD8;H +i}rK4-5)-bhkqX9;@35@~Lrb3#k57koB_QBdT#JF)WRj>gVR_^x5Th?yi7_Eg{(*K*X0)?zs6@thcyw +($(ASBNz?4Jl*T^M@7!Ho3hf$d@;pOt|Xc3hvw(%KdGnmH&9Ch1QY-O00;m!mS#!LjE_560{{T82LJ##0001RX>c!Jc4c +m4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKuFDb7yjIb#QQUZ(?O~E^v93Rbg-1ND%$buNa9hM4 +}wftJGd}AB+o>mVjj&MbYVm7JCibEM9AOoyhm=@2!Cl1C{P9MT%$Myq$S(ytLc59~zCPvjxp({&*3MX +*6H@Kj;_OcB@VCj?+?$t;m@qU!|Ocp$GMkkdo0V7cX2JWRe}zhFeOx<%w0A5VQRsi;uzi_Dv +u1RHNZ%_lj;MOFp;0W#aWiAqCg~|Ms+#foD5f1(QQ@earH+3`!+w7Nikt8 +rc~Vm7u!cfzxPIa3VG>{ER*OxE`8wwA4@8I_n0}@}$gLK8`atN=l2sH`cBk?h5$!7cF{xZ$z0F%IR09 +I7R8}aF+b-HkPO3p?DK?tv%1NGS&dI3EzG9qvs#Hk{%SrQ8m_t*L&l1bi-;_rEUZo$PZMllcTRhRD7lz&< +e!2%1{vZq24@_cTNC9F@rCDw(G!BA?ap-?Tg*TebXYrHkelm*}<0zuZG9-@zFN|mYYVL&;tioU!jeBs +M^OM9*%v&PANt}Ulub?Ep944eWjQ#|B4H}dw?br*4%?Zb+mJ-9-6xILoP^x@e&x?|?p!Xy)$`w}bRSW +D6cJ|6$u$=up>}Hof4FF>KvxEf^$|oWN^+YPAyEIb9I_QIk+Wv4b=zkb|><@@m5hA~OXuSCPA8({~tC +eYdNxkERv(>6B3avJf02aEh&qpTWcIq-gojI12Hv8O!uHwn(2E_anrU{9@&!Pr|m&wnI6UQt6d(Z%FH +^YyEVG}hSx!5Jwv%cc`5jH?c@#Xg~7b6A;H9#A&{nW&a5V<_ezFr*`KORA?Rw9|f-9GZ8ciMHX<;2a0 +TMG-D(RwX#f3DXZ!)11iyXU&7*Mzo43P)h>@6aWAK2mm&gW=ZkoXPQh5004$e001ul003}la4%nWWo~3|axZ +daadl;LbaO9oVPk7yXJvCQV`yP=WMyiiadsh?M|=m{cBY56(Ejjt +g+5@-!txV{1p2yppiPZtcJCZM6iqrQ1R_na%Dbz@&{%pXPQ;I)~fcOuJ1#*y-f`#TA=goK3Fg6LvcNb +oP;H>b6^Lwz%W$Q|#aRp&PKXXvLYIu>0treh|3bD86ML9P74X#qfyXRbvy^B9>R<6R +@!SUvhwkq;q3^k=AB73LjUS>odjk!#>nN7Ty_mZxU$NyjYq9!KZYr$%m83nL9EoIlx;fBz8p&@l8WcEfZFfkOkAliAsCz&JU*m|iTti0IER7FUz`oSlD~u@iQEGFx1 +n-Aqqr?D}SQ{b@ewGB)SD7-BJ))FAJMcnwY7M=+8rp1OXJ$gY2Z)0;qm!HV6vj~q_3$9=e>mGL3p;to5Fl2 +lZ^JOQrRvn;YeNxfw_58sx@TPvZsHV9R3grtxPACMbz_K!PvTgF!Y|U~lD8m^( +~I|Zt0n&Z-3t=-j=gTdEy%2n`eY13HsNkGM*?oUK@dGL^D7*K`yk-AFuIR!u;CT93D1n}2=-drx+Pk- +MhG`mT<|SDzbE*;kscTPo}S+q{Jx&w7yQ2D_d4oR-~+)QjP$tR5A=Ln@NGTc7JOUJ9}50Z&mRi@P|qI +;{)pns{*MHIB>97m`V_b$_|8a=3%;Z0j|G3M=Z^({T=4tKQ{b-PyOQ6haKU%iT6`(^OFe%n_)9(C6MR +q4_XOY5^H+ku((_k>ztZ!$;B!5n3qIHL*Mh&M_+|zR`g+}ZlZ!=??zAEom0V*Asgdmz7*(`Q(=bO$6M +2!TQ+-i1;TXB5kWm~i+Cqg#S-1RK`|Qq*r#xJ^%Ycjifpl5f3+@p!uQR{AgfCVB!2f#X1#XgLwO{?h3 +K8vO@t}vScJ6xcEeGn^)e4~2DOcJ_Qlc3Yov2p|xJn4!dr|R~sQK#OLhjG5$AfXJl@*!b>lL3AakECm +N!2!MR9i3O&mc(ME(j&vpoByU^&N7FQ<|)(i8FnJN>K@#=>8EAR}eNk%Fl)B+8+rLOz2aC9x5~L>ichoV-JFm21PD@-9 +0$^2V}c(UV1A76Vz>vKY!@Bnw9tWAPymF@N-A2*okJQfq4+pMA#s$U +P&m#|NE~G-dgIgcafU+SI71846{~I77jhm45@q84AV6848J`48VB&F=1>L=I5A=4Bpjv7|p&s`gik;@ZPk;azU?wLk!v>W2G^YjX<>1VcM7WK4lvlH%vZZkY&Hp +MwVY&Mn9Ys^ME%-(H2&ay6joE=D>N_O*CpAe&PY&Rs1?1sXz-H+}ji6gtA^;?M9#d>G{}hC>-03ii#|->^GnY+9|PGvDHqA9iIK7^qS>vQ$(dt +4vHFe;w*LUpg0d2h;ueTjl@|E`hYlpobAPV@j2_#;4X)}d +mZ6@&_cCn&&lr|6l6m9NTQWdPt>U5x0(Pqkfur`x8(q?h2pZ)iPELK#s83cjQW=f)oVsLo5qH$h;mn# +~taj0MLQ6kV}@`%nQ)I7khPXnl=AkPDE6wjO{W9^<}^!8_n@F^3`U5T8cs9I-OQu_}Y)~JDDWmioj!& +0NKF|4l!-*`s)BrWUxX|HefS}j>NU4H++$S0_K7JF7dQzU&p@nd-wHGQR9^O1aVO$d3GehEm=$DT#u* +t19+c@~9Z&mwW;Srm>vi^P#&ph8#c`LAwo5|{g3s;Cb@ywYk9i +Kw&nSW*k{HfzOXkgUSSWp!!d^E-c?{{G=&-fGR^-@lZLQ~1wqayl2U& +I<0o{|LNaadGNf5_WM4$1YCd$i>^{S1@h3jr~CG(DXx={2ktdP((rrI@u=RB)aG9!M)`PTSYvPR4)os +SJdBtQY^PA@3PMvbPDt)Qvtazmka$A0(9#?^02ENwI6Bet9ib=pAUFhzMIWAyusfcauNDdH|M=%-K+8 +RW!Z0cyYoc9YIooJ8uAKIW-U29UkB_HF18}!OC>o@4_Ttu46&Dp$XoK9LT@yF>zF%@dM37d ++U8G@NjNK&Rk@v*7MqkR=erb6+tshA!00xg>g#mA;X;>c7e9GeP>BU7PpY$_yZ78->CtY-!+&#gL +w0CL7y8W&b*zF+wO`rXP}hcLtWbiejHyFMPqv?DhzH}SUBc^|Mt`(F+uCgwru<`9QR{qrA0ZN(!#gcX +{gI5(`}=>*x}G`GR&PaFJcgFkKXrw#6Ga5|}O@l$1Xq`donE@+nudU~?#f*Ka +_PVa*12slciX(aKSYLvy;3~JIc_P&qMDA4-M3HuWcRrR-UIXECicsTF +Z>Z3UQT>*6FZx%b5pe_bws-4QDf0}jDF1-X%fZ2GzLdTF>s85b}UA8QEI|A4g1I_Y{#$c!Jc4cm4Z* +nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FLPpJXkl`5Wpr?IZ(?O~E^v9hSN(6>I1>F`f5iYnVSDSkc +6PHsx0?dCqa?=p>m>UYxt<{~G943@MU|wJ`u_TTl;khT&b7ep8VC@PGmkTGW}c{vi_<^qxOcrF^?O}+ +=)2VEkGlV$GqxAb1x=QmMoK)1m_^i;b526jK>k-m5u<4=p1IQ4371T1ZfMR84~!6b%+iAZOuKcKuC0Y-CLvS*Gmha6KiCx#A5Ha}FuNXAcTzHr$S`jNzfVr +lC1q6B&e?OCcWQ1XD;9vhjigj{>PT&@>7WhY=4GqZeAoK9*&>?ySULA2c +X;!i;&b6RsFa;2z0uA>VSXBvuY?$UgW7G^bNNY>d;~$cQ5TCoH{*11YbaNVZK2HKMX@B1YVJ6Gdob?1 +f#3VLOV{-4FOJ^{+~H_?cOQ6eKbYKmu75x3-(a)Vy!^#M`FoSzzu<8{@+RHsy;ah}!Pd%&O@)P8cz*$rtfc#5)_qk9e +sbJweoNxXi>K!!=pO7)6OlQU*EFG&UnmLJafGs%9!W=_IHHaI6|xKjOFkZ9*2jscW0}g;UHi66oAK06Wc)ii8QZ6^PWC(41e^N$~(L4;yD}GdMVAl!_B3imktiNLUTZJIRi$O +%aTQ!pc<$=$TF{v%UPOdMecb`>*n8q +8$Ok^KloyFa!<4GC-?cx*&057}t40ZWPd-P#zlM_b@aIbIZ80meeas8AZ$3$^vo1snZ7!gE;XH9MuXr +8zxdC;R+40#H1gxZ93lYI0$lr4T&-{WYb=1}Lyqz=a<1Khi5swQSc^r2Ce43UY2(LLL#?DA+>uK?hU1 +i>WWr`*;ZOs8oDznd98Lo!4*^xhD${>EHqEsFqbg~QILaWch?e+dF(yseTKsi`x(EbN*G0Jq1PJ$m4q +@ZA@QB!*mT`h(5(_u(8dYdtD7G#wx@o~ixdnuXoIOGF{d)YVCOw3MVq*G#teyh_~nRkL^AM&=`s&+xI +PbMW#XHv}dFH5Sdn4eR~S-E&8v^OKXq)rE;MAz5*8%=}Xq~A~w#ovnETWX$9bmpE?Zj*4Q7pcg}cp=i +{4<`BGBv^lSM?PkuY-_UnW!|4yg6(s>8OtBg}P@-UOdVO{+(XABK~azKjO3Z1=p)5T>YQK +L}c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$ +6FLPpJb7yjIb#QQUZ(?O~E^v9JR&8(MI1v8MuNbLcKw@)*6}{C}_W@X-Xn`UEs;bornZzMhjg4%l-Q2 +IgaS}>W!WDX!kjTtD&%8Uixv4(T8;r&?n2h^_nKyvmzrYQ>S)d7z<_?nti7)l*>I;AVV+})M!7WM*Cz>QMB8|g89TSDKtK+y;SJ~6 +2n}oOzta63=LqDq>QJoh_YP!1YJc2>iq_^TP+tUD$O0}at;e?t6@PkRWCHiGU-cU6x+m@UtKr;LJ7c> +sArfnzEx}oUjQRCU?j{F6G@R;cu|5s!ll*Aw|vtI+McQRmMVnwkCFkhRNp=zfOMIOyoFrgY#fe{r{q5FBf;mk+yg!xox3Pi)+%5-!r<IYVO1N)cfa3>*ojgGK)y5#8Q+GG0E}= +!fIwY~Xn?d{{si=H10|++R()3z)AK^9OI>U~?%wl-L%ts>p984v}&vv68qXgmImv{)Fw-7$6TIA}{HyT00>UVKDnxgT#9X)FG7w5y#p44kfsT*is9_wc%F0@S&sc};#T-h6FM#$5%J8i1s=kOEJW%dmr^y +MC$+Jr(=K9LZP#smalf`)fR%@ma|Z^q?-yP^H?>-*aA}umspbyJ&sXc+`xnW}a$th~D +I&vc1Q|meXEhXpSs_I1yVPZwZc7#hs%30INST;kG+&KUYqzvI##V`=+x0HTd96u&|=@j$lgsvgAXW@n +-k!_BMyxhfXJbXcSV|Vqc$2@u$xJ99ek|%@X>06czBBm~V+CU*u&Nxra*JPv{Jw1b-!T`r|Kq#1`V0xT-!{ +b{k3qdK9si%0V5wsI$;hfBDoP!EAFk6&ah+Xvx?WMmWpR{aD30JIJO05bpp0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&W +pgiMXkl_>WppodYH4$Da&KZ~axQRrrB-ck+DH)o&aW6LA8J(UgH|V98|5TINWvWugo&!C7oo)-!(QxN +w7X8?{`#A>4LG(*)82l9d3k2$nb}#NoHQReA6|{7FdhwtQ*Q|8 +CvHZ@Xh`Ca&!6%v9+L?|7H=Hal@DU@qMFlbh(||$tQ#9IVTO?5&CxZLTa49tXRa>dDKLiXjsdBlmkQo +eMm1cA3CKu&ra`w^8U34C;WyJ!Vs +2c!ar8Jj5d=?4K)p-(hMutG>QhDp>R1hR#%qs8^j?E?DKJNVk +4&->HG-6`1;)1;;T0i!FjO@FF~kreB!UUE4QdI +~%QAx#IK6sOst>8o{@P!9d=(9rvC2Y&C75fcv)wZJ3yOCA#RWhABQz`4}Mnoj!U+x^(_^a!cj4guHS#V>@;)u5RP$YS|89L@p3BB|A>gyA*ijW)$7MTjGNJVr75bgVr|o5 +ELUpUv@*}2oW}6r1G}lZ^hjtE4SP07{r`5GwIvS&}klWMj=)N@HTibu`GA^i^z*z%pPN{^NXN|A#)VH +&vR5}fz4;&tRE6i5i6zye0!aW$j~~#&XY1G8` +EYxg9wF_Y4!@cakyQebc@&MbUT@8$L_o +zXJDRkE%dWu&Lt)rQ_QD|Hvd$rXJb0A|Jr&>|~8fltPg=%noRsF^b7;r0$U!$U(< +U8+%K?_3kNBHj3T**Bq)>Ykz&pU?1s=tjPb%edleRub19DGOz5v#$-Cj;V{w-E&oxm`F*8H?Ukyu|3C +e7q1oAk+`p3Qn<_6d`vAQxpWZJ}pPhXc)iu3uaCbi~*^;D)_XlH|y!}GSS6sU?@)u~(H#E&(s!Pu~w! +x)YqL9gYv!stH=Gaf(pjusNk4X{o0EKU3|5*y{UEjpYcVz{VTV=@!=^ITzR<;=~Uh=( +wJv62+P;J;q5Awvv)1Nq{_aHqj40VNIhoH&MuA40kz%w4^T@31QY-O00;m!mS#zc!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FLiEdc4cyNVQge&bY)|7Z*nehd9_% +5Z{j!;|DR7Wx7CWE2XYDYR;#YM5>V2jqZ9$vJ*&1tAu+|;5J$GNUGD9(-#8&a5<|P~oz+TU&-^^^Gv? +$(zo65*>0#v{?`<(`X3%4QtM!3KeZ|QPDB=|%UPc +jZ3lA4tap&wF7k?eweBLRyD2etsIfkyfvk-~E$f?KOq98%Afl!XGn@`&-|3j)K4@pRwg#FfN{`8q)?U +*&Rz6|M2Ar39l}gQjKK2%#l6p&bM;R7h%bh75CCFqW2sjMk6Z3xpLh) +SPt=x}0&@}Drwhdw(bp^wfN`7>Aq!?=`^cn(m7tc6NtqFFT`ar`3c8Six4+w~gK4JL5oIotdA`a?^fV +A*ie|mLuJB9Y}3;fm|kK4oPmrqEGuE0}taEe4%Q9uzGwc>6l*C;pwT=&M^E97W*`h))Ti;~{yPlvt91 +e}{Ov|-d9Py5~5L3<3N+wtgT(lgPygk&aG#?%>kYvKh$t{7Splf2^iyb=rAD +_>2(`pIjK|@9FxXW4pV96VYW+jn5b+v#CrQtC6gyM3>aWEv?I>uXsr +#wAlVzGdvJnQ3Vrq@8g}!S=7w!G_rxP-ag^u0?sO-YYJ11LiUUa-^EDb%6+YKf0gdG^6F}&ZCS@c+!^ +eOefg-}ogY<;gMZyV@JCy$9rqQ&U%{mb2nVC({tCj2iuz!7fJ)2&Qdy}i1!3CUyWj3t}8O5Bmg-5B{s +St$CzS$LWh2<}i=^UDsO2rFYA$HaNVpHVLDp=kyninveQLLl0nITB9sHOXAsjud2iD(@vGd2X}#PrxI +q5(1H)w}!eAFamycgK0C)(Whs{vkHw-fFe}{QHkuiD^}`(K!rRNQz`R8i7Q24|x)f>UmAWAY$q{|iTl*gsBOC~Q|=^kS3hfyq%KXK +#E-$k;4E2Odn63wgC?J3rb1J>MWe#GQk+hugB`el(E>OGJLj`BELA1ny*6BpFM?Zo?z$V685%wusPV; +)wvd+q>x!8rsZG!l$`2&|OJ`Ei5|VcrvY7R<}EcKganLOD{T)wy$Xjm4P2*N{D_c80b3cIxDq5noAmc +h-7<^Ycx8Gm&wIlppgKrI+;_=yagtfWm5g+}>0oJrb|)64u6~fBCK$w)TG5szrjWjHenITg};^r<2oh +!0CZyslPWeVbQZ)p@-WkLV^s +E|#6WoH`3GeW5sp0ADa(ma<*RvbhAm$vnn3Y!hCC7}~VYPNll#=qVZU;wPTX +hwA_1W&7%C?X60&(>Dm_|T%dtLE8uGY%^J}Q%0g=uI@rGt2F5-Imb2MW1bXeZ2EO)P5kIuPuKb9ayXv +(5;5k@VIoA|7YmG8AKdN0Cf9y1PC@>6fKL4O<_DThO<6oC4I*67x(@AJ1}ahDV!zvBY=$iiUI*ukg{2 +*vlmg{8GlhAV%-32XpnG#A{iB_X52A2zoD2VtD_2kvHDdAr53otycL5P)h>@6aWAK2mm&gW=UWBAZs2 +3003MH001)p003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMyAWpXZXd8J +m{ZsRr(eb-kEHZOMTsCE`xB%5Xd+p!a)zCn_)$de#TBbx|C8YGp}{rV0i`6fGyZmTD2bk59~GeagxyHN(^(U%6P0WGMK<}TVy;h6)Br*v!zmN1C4$YI(K)sl;R@X +g)ZmdS*!*RHL5pE%1-)H7{!*kk*cAaUnv4GiPS618DA-u!8MRV14hDpYt~X!{gXAEEmfqp)}>S-f|jX +yCt>%nl{v(b0EG$DWqLBgKqQjiq#}MM6P9jmC>IH}V^teencjK$G+n?LH7SKB6sV}1dA{Tpv5t+Z&BX!HZQt90k*X@56BBK^Nv-FBtU~v-rDzRp3Txp&*rl}9m=lIgw^yy5oK6cpwQ$>z^B}#*SDVzyc97huq}vs`7y(u +t=L`_Hhu`(Cq6htD(cb&{$;{qH5zgAghz+wg!*t;KoPr+ +{wl6*k(f3#{gOcl(;vk6+;Ajyu6u?RDHX{WDYI_urB0+HO|p3il6CO9KQH0000805+CpNzTxtyLJQs0 +3-_l05Jdn0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyvaUukY>bYEXCaCwzh+iv4F +5PjEI3>*Zqw~l~qfffi5py_to1lR<|#*01*v^28WP^6ZZc-61(kQ6OBcDkq@f^aTpZihq9X0yy`A^7G +exPtXgBdf0rYY-|WC03Rz37t}c%PlZjgT^ao=ul)ca?Kj8S}4oLS*Niqfw!H~7TCrp;VhQ%oDJeV(~^ +A6;8%<>e2C;c&w#$W^?LQ;pkI-Gd5}MyQ;cAxM=z^@*Z2VSX=WWcOXt=;m8GA60m8!99ov^%P+L +n#dZOtqj?0upwlWdDRx%dTt}gWzSgdXg;XT) +Qo_W$rf$7qhh9N%Ue|LfU=Iq<2Y9LN&nd&vMjrRC$vyw!>AJ=)OPC`upVtDez}Em5uWX@SISa?43&&s0j{T$dg+#l^$xrYKX@t@7;eP +F9FElLA$RK-Py#F~55rhbm$n^Y_>iKfiJe^lfSa%RjxHm;eYh@^C<)11lwQ%G`NmXfv9`b9wnBsxr~u^_k1v*4t_xxg0`Hwp9ik +H3BSb6|#Fabf46=mNnte098f7QKfFD-oV7?acOWycl+e5RnV`Vz6<-J7$rE8yBNw;Y@>YTAJXJZV_v& +{~O`CEsheopcTyxv`7rCK_b@1huqLEk%U63vgDH6vMjpZYp6p3J@tpSq$cv)0gWn`z#B+U00EGsRvK& +Aa{`pK^c4YUx*gRs5i8~s>mvsL$0UMbs%o@6>eu|psxWB(Ac`<+CzpAYtpa(a|*6}rv3(p$MKEuLwc{`pTj@ +N;+~c(<%ui7tlx2C9<}m)e__<)4ca}@bsL^_vjn4HkMNAx(I~##p0oMA5qWv^u#MmA?mgZ=aN~c@4Su +JMBTo75{lBbEa9?#SZsOO^#=K${w@UXn6Da?F4ItlN$`LW_Wx7LYsf|BKrtWXl!?%*QAC;4mS!DkLP) +h>@6aWAK2mm&gW=RKV5jEHh0022D001=r003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX +<{=kUt@1V?GE^v9JT3c`9wi15NuOJc>l3PdEv=0je@Z#**c25^=w~Ouep-2OVmgt0yEU6+L ++bzz2Ki>=~iMqte_V^{TMGoga-wd;^%Z*qr*IT=-)p9BHrYdVIHUe?r>e5z9sl-SU6=Kx5NF~;F73LkH|M5Osb1 +^!QoJuc4I|`()Hxl+P^-m9J;rOZrsUbTVAN*VeC|3vjlyhf2Ap2bpj2Xl +t3Ol}zs^sjq^`n&|c>70#5m$|R-Rvdpk&ip*fS(fekVhA!^a! +OZ!I1;X=(-@XCk%cab7n0_IyqK_(t-txn*MrCix!b)AJI+}~<`%j-fd=CStnof$YY2W*8o?}FFu|{ZN+=I#V#OH}tuYYb8j~^IYF6DA3apyE~oUi4DHc4@PV&VM``*bF-0qqyJJ +jH-dzvrMV)4<&K>PU9Nf$V}2m;3|XL0dj-V<-}zARJ_H?%rg`qiNApZf1Z0 +$3A%JsD8y++*Q>33-QW_EzV}7FfqwgWR^01)3m*x8lGl0;bR4+2?RMg@7Ux&{BvD&!x;}$;|Y#Dl&2c +ek7|Q=tT}zl9td;+q;gHel}r)FNR_zRawQvO>gaB(G?b4V=s~Dt%LJzYv)U$v}P>rTsW`kc=C?tk|2n +4)IUoSq{7k|y~+=ch||bk8%z3f^q{8*$40%4!y|{ffR$qAm3euVN|@BifW3EXv7;Q56_NEUBI5cS&S} +X;-`-hqCm$5qxD{qVj8qPQOIFKM`hzbKUo +n!kUA&dKQL|1pIC~s?5-#1RikwoE)>+_kY=K@P>h0{sTc+|O@pjC)j>zWXsS?BZctP_cyb!A)1H!Az*6Nfex#!c*(dk>w1f +pgM@E)P$+Ho}pZb21dY>3+%5H`}D>`z>&46hUAE?xPu@g)f^4x#4-L^wgr&%zM>1y#yD)Ab^t;L|HS% +@xb6PFunl7BqpRak$%BVGULFYZniG6Y8!5f4waT+|Cwe7yZ4zK~1r0vkwYyUg&%K!k9NsTRQ%A +=$>;WTIb#R +ms%R8lKA9@Ld0DNSvFSpejRhbAZr$j`UrPUyV~Hoh)r5j!=JYWj=X=lZ)F1(sTowTh&HTQKb{{7HkHT +9j%Z$`i8<-=vkylDHhOF6lw=Lea{8Uq-T^qyh>!2-P|xO94SR!mX((lmACJEUZVEADM{!hxee^+kd|i +?jMdu|R)(N-Y~x6CUvp8nHQsP~L@dLHoHv+qqZ|NUIZ}CPtY`4mt5;2gA!`l7b2eN;lE%?5%AUU|%X_ +V;VOp2vVkPV7k;Sm`dD<>s$-fqVZuk4~>Z^zx9|hnXmE_jmMTBOem(h6LFW-G?C|>j1hK0Fk$&Yuv@z +j6x)ZI=`zwHDjkiMtDz@5o^(m +SewsJ}~3#kvae#s>6~nTeGuYloasNBU{xTy3EGgz|Sy04)=KVJqMnT+Nd7dMKRhz?=$j~xZTnr3s;zq +ZG3)11j=Iw)~7W%mz+KM12}>z?A68P^=H6AynQy`eua62l;@IINI)NoZd3HS$=dZ-W9CB}fVuT;*x_KK1hF6H|hU;1Zgcn)ceusVWJBHy+)?b&X=3s=r +I~vq(uf;9ELgBq=M_tqp>cFiNFQmRIOF~`)s=#0{Q+?n_A@zt|xrL(Do|+CfPNL?D0JFn0Tj(OB^GgY@u@OnDiwBx7(k7sEm3Pb9xqI^o`(z%5bb} +o?b8gf#s-WJ)q&6RSPPTFFW35hQF;Aj9a#T8-oZe?GAQ231$PLk?rLxW@lln;ZY2rua?rsL?G(u{R)? +R=kG&wY}jw$Av$r*!s_+_aKjg?yH&erms=$fX5GNYysO16lk=9J9u8}n^l5~ihr^C`%}%;SZsx0yZX`E-Xhi6hB%aY*Y>fZ}J%T`q*qny +}6QGmlklq;}8Tf&}0wtv2#s=)-$J2bH}M@MWpSv;wux%p*m3sBty +D`c+N`8d`%9o|Nt4|m1A*fOwOuLx#nxqzhC^< +)!f->LbtZk#w|0!IIjVu^gAp#;CX@5$wkFrxHm?;M|(I%oIdsRQ75Z=2z6S2qii{DmC%e#anPU24UTS +4ed;7$#D!^a;Gju3C3JfF#9;}K7oU`F`pjWs2$kr@rq2>6oS06NabcKDn&NR<6xQfMd6GI+^$`dk87d +f`7%6OMI^EV=!@ST}s?(VpI3=Rp)g>XdsqDcK(e8qVwA_?(F3?FBcvEO=qCQP`#7A+6M?Y8BM+`MpV> +snbI6_0u=gmIUnl26<05jC6J8PVYf6J5%3E;y6LaSFAP5Xg$d}nQy>lLqr%{uVn4cNSZd5|a4JA~2n8 +ckQy-A_SdRI6(0zQpl*`h|(VFtbzfg^0V(7x|M6zg*5;n>y}j!`7>t{!F){#{=C>L|jldUOT$B9U1Nj +Hu$zA*DHqAmCS5L%iZaG=m-HkF)DHwrC%{!PT3{=)a^^v^6sns2#V%%BmS@>0C%MQLC$I^ds2Y(vafmnJgCX6yCP^S(|4$9uN8kd(HJ<%CagoYk +Kt@aM?eio%i{8{bWuFuVtAa+mG8CN +niu8YmZP?Mzg>`s?H+r+h~KzC9kseToz9+MBN>G6G5oOsEwx_jRP%oVB;pfY(zXz@R_E?t* +=o6Sj@b-yUniR2posAP1JNFRb{^e-#OQMEM$PvbaZ +^Z#z6;jocDL8)J~{pI<^^=M)6E}T$f-&Y`B|6W9R;InIEYhA^IJ7M~e-|Axc4;?)g9QUxfjiXEOebJ} +V_Q|ea3fM@RQv)p1<}K6B_WuV^O9KQH0000805+CpNdaCB44MuA0AVcv05bpp0B~t=FJE?LZe(wAFLG +sZb!BsOb1!gVV{2h&Wpgiea%^mAVlyveZ*Fd7V{~b6ZZ2?n#Txx@+cx%h{}sFzgXK<9(xh8EW5FSpxL +dI-$u;hZp(_+xqHQg*sEJe@-(mmzy~huUl$18T51dgn62~1vQ45xmtRQlo39{j7owE^B6UiF|s@6O8k>}as-(;%;`Dm6JS)KAtndLBHo5?k~zCQn}B4E +WTa`pN*Dj0lIypv-bj_j*lUEnM)Bqvf<*#b;Sy-&1Saw?a++U$vvCD}4drsRSn$w<)vq=5Q@7r-69Cp +i_uqa5H%v&4xOBK}I4IqK_QPk0JA!LC3Yd%O(EmW?Y$XqtjGX^}_{e;Fz0h6%7M2KGuaNfKI+1v8Rhs +b;d(gOx>R#ERnruxV90934)bm307vPb^H^JhKxTs}Iz~3%2dx3SC}}BRL&5Tz;Ut&H<$LW}=F?6{ +wn30)c+zpX2ox1>s7%)JnhS|yv;6p@AvtB0L`73$2X-a3%yNasUr5Cu{M@lP0kF7Ye~8c|&9u83^Z?{8Mo@Mu#0w$*Y5~eHSqB;>A%o`g1gTJ3F0S%;U3@`3!(;)Q#{VI6Qd%A| +%h@A1+2)&{@6N>{`_aT&dNV&yy!l-l5}zb*D_iIJm%)DpzkoPIJ4?2ZF!Z#@+wf11T!KO;y`Ug1k{(=s>aA*BbOk2sRBc5Cpre4BD3KsjD0WbriLvO3w3+;I3fk#>LO;Dq%5%GVl +rt2C(Sch`f>bl^6Mr&=M4ErW{5ul_ +HL!dru0=H)F0Nm*vu?0Aj{b7|3E>fIjmb#%2u&ogJ~-;)~48x +XTgQuCruqRVYZB3A)I!z_Bzg=qhJpAd#Oaf{PZfmxICMkpZtnO^n3#R=O}UCY*1Vaw$4B} +6fOUL=g9pvh>qRUO_@W$%$8)wYskf7jR;u*j4&iaeqyX7CwX?qFqKnd*fw`rA%qQDM6=0OYpEQ1I&BH +!?@^K=Uy~0W6#fFEmg~#&`1^kYRBUL0sp1=fr<{M0f9!t%JpU2S2AW2W}822^(OJB=w2$|L$zjNd@~0kxr@buVC}A?;R +Fc_(=&*UtF=tKAAo5!eb_@igT1axR_US$oQ4w>|A&k(bIjr8*DYTivxz?8Y>r2QWyGjkHOuirh<0QqB +<3kd71T=EF#}A+=wSs<8PrVpjFzJ^Z6=)rG_9Ddt73|ML?2J&l5Cz;$rj&kv9|rw^Qpc>rk?d!$PZon +`G|dGA9^%^-Br@V*gZu%*xm6KJNAwqDii?#Ig(J$$KrM*7|4!D1B0)zEX+O=^K7;_P|220$HYwE=xu& +r`_Fu~Dw=@@477HAX0%~FaY7X&+OLG#YJvK^hT1AHi?Q1;$6txb6Y|yP*Jb8U9$LW6Zt@JW-|tu- +m8S+E##%pKgq(aaQ91zZz1`e>t8lN@&{D+Wb7Yh5Z-GaScijKt{P2>}>(Vp#*#T=lqZs{mz;z?w|&vy +^SEd_;n~j5;{5`k3zTuUC8|F^0daWQA(%S|Nc>Y-!<1(2xrz9TGp&>b6(8 +fbeh~6{}S(*2hL`$-!kAI^;pCPJ^Nw8;$2`KAHeJ@m1`bf--^@amD_q!QA3xT^F}3H8O-&Z_ObKL9+& +loTs~ElwwHMYIi^!cVz0u%aa_kZvm+rHN{PPu-U-c4XFmX?nML$S`~5)2BfF==nPZP93(u|wQ;KCM=` +cDvdBR(gIpL!K{o!TMqodH*))$@C%7iUph|=|??~`AD`TqK;J9Jqn2hz%o*f#aHyDJz^vhbBg$JHghY +%kR4Ys^s>#1pk>zER%8Jl+0|V!x-vj)80xig5{9E-~F~CDRMbmx^4ktsLVBxPK4hRkkSSX-Fj6pQt(w# +7E7JT5i6Nbtf4dFdN#1^@;Ie6{t4*CVI5&t8)aber>fgV(s90+BCEp$`y5=sK|n&`b=``*{MZb8j#Tj +iJ*JO1JP@^2^S@!9P4$-DD;Jb&}^?DE~bX?YuLpDx{79z#n`{~2JX^Ro;&rJ+|8DizozV;f^0{Rxc_( +5&sVYXff~)@Hbs2dxyeF>D?wSb$qho#8j*J +4a!Q~@O&c#1mmYi-+bFoy%m%J%!!Y0LW0~u7XD_E|%PjWhz{DP)sX?j^QijIjG^^ZU=VZkl?jNOi2Xv?|=qeRP;|gEuoek +p_!0`Oge8Z7FVKPvCJ|CpluHTkxZmta)nPCQN=T20O)k+!CaX%HiN*JHc-p=E61mZLk=at0wlR3<36e!`XH<-FzLD8s&5X7@g%}qBvb~@A}0M{-@D4-&G2gE_mFsP&aKsXlS +jAFR>iSrQ9&;Ac801NXr(cJ*Fo-~x+DI=y5sXDB>vho+K*F@#9$Mz7uCNARwdPLNPip#22Fv52Ks)L0A@|doZ|?o?L8C}KSt=Q;RM}(tO*F{kc~!FkJM67>kbWD6Se`A1^37j#;i@W&i_41{ +`K?Dv@A(g;ezSj|&indRi@P`Ot**CEP#F6+r)%ClB1kd8WT5H(T#I@fM^$q(`(B+wePmLbaj4!`wy1w?f?*0r@^aAZ5 +^eAo~jL?dwx=`0Dv9(+a632Xf^K0!h7yfR}x-rvKpEeRJ_+Kf`88?7#T#~-%PcyxbtEdCs5)=o*v*hrUBkEX(3yUgEO +I*L|aF?~`4)t0&ViW^z#R5~m0Dvos1A8uzO8hu8M?CZ;wti`JCw!lbp<)e*v(6>XtiA^N(m{m-GJ~3{ +K+}`K>nck{BD_-i245{lTT`j#U?uI*bv+eDSsQLX_4|Mn=)&$Q!Oy?@z=wDDv0|XQR000O8HkM{d6@O +clqa*+TH-i8GHvj+taA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vrY;0*_GcRLrZf<2`bZKvHaB +pvHE^v9}J^63jR+_*2ui)AUBxMvj$4oo$jylLBZfi`^Wa4CsMO#R;_#|;dkt!c)M_ugx?fYHtBxO78? +qGlsipC<}{l5Fss;Rfhe7@@1u2J)OQfzm1(vd7B%~!qG=Fgj~so;%1 +I$GiIx?X-%ZQ{nLnMD75l)#5(`MFb_GLyV +2R`uWT!8AGF?%Mq{`MN91BlT&ic5QM&jcDdGH^ATSF#t9`F)g(;R(Z05E$JdxiCV4HvegN!?e%5yeNp +B0jizogF!zOR&bzA9DxYubyerk5pTpo){d0Df@XI4P!IT$X)Rmbt8PlLI${L!zt?QD{ksiKn>b716k7 +y53vu{!PTjnys|rpURwR8Ua#Xu)`7v87ooZdqw^_T~%r~&3D%;x2eW9ARSQW4#-bvKc +G}FZ=d9$>Wg~yM7&ad`!z1*m+;1Wc2^WLmk?Gy87 +%oXi5{*j_8ZlU&<2dIvCM4*~~%C(jJ1b!|}&Y`D;K_i&y!^==37>2-<6&a{SOo^J@s<~s(numgaNTP} +R@-x`7-?+rQdT69fm-mX7LA`1qLq#p_DAIg*L2EEDf|chFBy6WuL0a +Aefsj2fRU(hzEJhDDN9dD!4GYLVK>=??}?*vfZxrRWJ!nir*pXO_xw+gz=H7Zg>|&gWyT%GEUCQ^iA` +;Q+EVqGu~0RV_7e5AoAv1#GxaFUH5;)zm!EJGCTePmd=@w(m)@Y1>^{TqSv}bTtAFQ+xz)0)DblRdNG +=R?D&jB74Sdk|mrsP;Xf6&;VD+a!Oq%JG`EDqiC!6M>VjnWt06(kA|* +RMo1(%fhEY>rWmw02`j;>iDngtdvJr-Z(Vr68Z9Y;vMlj9{y{9HicK-s7H(_S+$4lx3H=rD-*})xI;2l={il0VYgX{osTC|I$G#cRBdgCGNfHdPQ(Hh;VKZc-74N94&Jc}Bqw-@a3TeOF903F;vXN| +)j0AFtNOgvAaPiF>v@sEVl=S7{Ibp3PQNNDg8VDREFwpuO!Sjp1GTRViGn65FnG%W0+=PR;v%O_ojyq +)C$P&W=@Y;EZ#h%^q$%<=brvwRHx-clo4WZ({6-Xyrzs-@ZCwFDA$4F~)eX&V^^@?3M5uAYv#w*cp91 +L*Kw-|Jg33TB02QLRE^;8*9(>B|a9VaKII}ESm37wQ!N38iHFAcVO#y>w|iUnm`7{4@`{O2+n^YQJkE%$vM8M<&sTVqx +G-o40M#v9Sj#5U-Zp{yFmOy6$l<@Nyvg;)^PIf~$astFH7gDA|G(S+qo9VDGvB#!I87$;AqoI}tzN?$B2&!bBqS)A0QK)!Y<7&tU~ +i7!vhPlwaVq_WT0nF?fmV&4F+&iMH=Y*D5?cT6}O8v=Da^usB)I`vx`Os-_k3Ru>C7Iav76(ue|Ot;1 +Zp-Zc3hg*X^#)hHG6A{aTl&WaMb(UdPA*%l9oE3;#Dz$8l;(IeCV8@#JVl_2ThwHQv7$&L7$IRd`N+d +vOoc4gKayeX7DVSPw8Q7WY)zR8$u!sy{m(fP>f1Y6tzT#+0Fy><?M`3n+wMY4b^dnk` +Sp>p6;Umiu{_yi1S_C{!Md+K*)8xauS0Jfv>aNTU022u1MFYo2vb&L(wNgEzZV=ubH_cBrh}T&K`h2r +E9$3x1chb*cN*W+*_PjM-pftRFksj8&#r}px{`l}AHlBaH@fMip1+A}iY=>`|)&lp#WC2l3Z*G}9=77 +_CoNBCVE-ZV{hcwO+GTaf{scb)1Ji`Tum5A*Ju7R^m;QPCk)2WCcGp3?_l|lH-O!z|j^8D-PA6~tmzr +T2W{^rB`slnaZlPMFPgChw{$h3k!{H@=Z0Z!V6(08bdy?sx(55?N_;8{#OEcON8UJqV^r-75|!e@wrI +Q`+?io#!LbMa$2&#AG_OhQ9|ku_%KeTrJcoMaT!cM^;*2Z_WR4<@oJ$jcd1Cv$tz^4+BJSNPfuB7a5Q +N$#KV-^Nff7O;qPUV;#4%PcAyhA78OZhPRJ0RY>^J^*>=zy8~|ihPZH5V;~-xVv4VYZgcH8u$kqzs3_ +ZI-sS*@=PRNz;-+}A4R@7QfW4Y*KGbuH-&fr;k*Mxj>OAm`IS_*jqxAj6fAR;jK!vaKb%uGx +VKsv~Ae-afEV&t06^}5!(E*u=M^ct-(~AkjZk7-*A3A4Eo}gM04z+AhGy3_C> +cAlZ`-KPBul +D(%OrpW~35zjD}8Aj9Oho5}AN2PA)+;6iPh>;?TI7m-n8tOZExxbqwPi%{_UZ+L1s>jEm5HT^yQZ>P$W!sA2&sc6Y74xo_0thLk=tThoS^8uUaG}3>TRvcS$pwQ>D;skx(0>pv-$i{hcsyYrR40yngwd*8fAPh@(JfXrjFc9nkF`lfMd*?brxnt66?q +l^3IY)_)j?%GcpKpU0=9Bp7(tPsqwhKu+d4$-I>umfn1;ys!nS1tPwwqaF;j(KQgheuC;L(Yr*AnRX* +v~*m-2ef!J6qsp?Nh_O79l_J32RoONe0Bs4pB)AgC1*OdSm<<%dE*g6u44Lv_Yewg+xf@Oa_nwkOeNr +XgdOOArL^TK(i-CWvn}53%DYmV#9`~gPY(*3ag9uU@dwB8yV&jJ&q8H?2KBT`Wix{03J%j*Q(hAtpOB +=HRdq$ehMl@rP4cCMI@s3xJKHehw*?IOA`-6NN!9l) +k705NUrjWQ%+p7^N3OGau8moR{NQ@&xKDrroj`~2OKPe%sG_W`8sp0wZva3=t#rdV&R0F+sSI~>6lw9 +RRfS$n$)($dDZe49Jau4)IG3t$ebu*0i50hnMYgVV@sA|{c@@2QB<_(&l{f(b?3aNEhZs@%~=veq~Q7 +|@Yv-0r*ZcZX7)amDDw#DVn85XMjJWd9PtejM5|?r$fN5#zzkYXvwQBg+RZAp&s6on~iEdrFoSXaDwt +0(2M^Fpb8ujtvZ!$&(TQpcz`@orWB`H4@ySds9s_P2dLX4I)H$k(P47j8sAdB~C#+2+-xvqN}jq+>a| +mwt~lDjgb9Ipalf6h4D4euyL@OET2|>j4x?1d4i{qj2rU+MePTAa-2Mf_UDs}OU2&y>WfJjl) +vdK3^H6BrsV9%0e)-ft;E~<*h&;P|))R!)QC_ek0kN`Fpcv4pOoE1fpzG80i+|X;6AoiYk}<=1gngQ9 +$(kJE^30G*)J?kTqsk9j>{;p@`yUhS1U-2(_vKI=1zgSB+*0@@pkb(S31BBvvm-rS3e3-#ta(K#Jy +3DsqFvV7=hIdm1Hf_4Fe+%Kn^dpIrLEAcx%hBt(+S7CAXax|(_DUIV8memsURyAh&cA2;N~>cs)vYAy +-*>U1zDAP5GC#U2+Ju*Y+@Q31D`8?C9BY>iGz7QhC8FxHYlny_qZphK$BK50~Dj}?<_*7Gn>m&p7V*v +x^>z-3XSm-^H;63D_{)f=DmxUCKg`H>Vzl2$BRj{_bTMhj1nQuc(2xBI6|Pc)N0inR%XjG@Uh)1)AcP +Y2*UV4;qL0H9|xMMPuP7XoJfxla0Y&Oc0QYUt90A_cTn>>rvpQ^Np+TmcMwV;F$77P7HdM*!V%Fc`WmY>_lc=mQyLtjlzb3ltjZ}WCJ(Na;K +xwh3{%4tc?q=*%N4iNM3-XCL}EyP8|LQJ+dg^&DxMt6ZuOKM!4?S{CvW~ujxRG1OnS_$+rf(JuosGFK +|2Ya6&;9%rn?X%1}$|5gpxra;IkzafBv3bF<2asumc|c{*no`5U5fzc +Z$ZsK(@BdHS=N;PE44}8ZL?l4TmU3#)*Togc}NQcBzVMCAT426(ofarmE)JQ_gyfBFd0@ntnOuxSejb +QVrfRz@LQu@z}bzUPn}9cJ{X7iI_)YJKhZKG10*=D|)}*dENyl$r5DOWv+;`c!^x`J_aG@K8x#HVT~8 +UVONh6`Zs`jFdetugS!ETq03E%DF}`}{riCdDKP7%Ap1{J*7Zlt$qi)D261RhIL>b{)&qlD>ren&cbo%CX8D?fp%=V|%F_XX3y(5xh7dPDjJmU20NcPMJ0%&2n?j>f%CXuU^$~^;+aN1){Z(wm3KLQ2D +qTXDOOPdS;y-rH+#2Wl4Ru0rSjG{2666R`qq_~dIp}3sgz-6_-w)9|HkH2lo-asRKT~U;Ii(!E~4B2T44Aqc$ciJ +#u0BC?qYfgYx*F_$hus~U~iMe6q?ZW2w8sE2UZ8-PHA9Ug0Yf#*>J^V}VY}m0Ebc^Q#av|O50bf+#Aj^jw;(I^n>>^P~Hhk-%={ftB)CAvkS +rDurUG7MVyn)DB&m#07rcbN)kP3Ux6+m>cS4(QNZ_~`i>O&Gx_7pq4|8y>wzYXqMf`c9Z$5K8;0B%Jd +E?+x&WgS8YHY&safM!C1at(@pumsTV-jr)7<<)h%|g=C|!5LMZ1Efdm>vAYsa^!I74Z4!Ej_b&kNMbDX$Y0SM8lo+T +R1ajnR={j?-?&Bl7H3W8eA~FA-Ud4lf_`(5hPUkL=9GA4ik1*{PO53Et&V1dhG9P;<8uor9t=$H=fP- +RR*MBT6Zyp+6sp3gkV7|wFPfY@#alEuc +xWOwpi_cD^hz>{r&?)u_Z{Vy-w`$PbBwKb_=Wwjg9zU7F|DJ~XeD?SmKK&B^_s2<^oMRfQ-T1NwKo=( +guU(WDJWP{R;SWa#Wb_|142Ig*{msQPP;ZkafOg8my21$ro_Iqf&DUN4mP=3z*M%9T5?qOfJRXoum~j +al$zGJpK@|5hZ}Ed1)y_z^Tjp4t2*T!O<|{~>igiWn93Xvz&O=PdG&M7(gy>C?D;+T8(7s<_8Hy-=*Y +kF4v%Q}%Ja+EL$!~G`^|#~8ru{uB=XW%rS(13lN~cJ`95#nROU(E2rb6;Vp<%f5#loKv$g}aXnwal6p +qSH|dhQk%Vdz5HQMM5w0mnyKx2Ok#(tVMww`YMN8wx0Dg_rWm2_ZB@6f79-xff!_DZh^CaOga-B9N7k +L^FuX*rB*6j4R{Yz-kmMnIL{>gHLv3BU#+|g;Ma-6CDX%CrBW+d_()Is +vIm?lbQ;SJz&&i=X-=eFq2cXNS_@=XEvG=EuSm~@M+ +NFXoCRMg;zPTk51R$|>hE_Dx1XrXwv7A +kOu&rUS=Mg%8a9G{-o*(jmd26ictgEV(bB2H{#{e?#WxPaX4hYdNCT1_r*+v`4EN$o`gEEQ=EE*0lK~RB>#Qk=U*N4PG~PWDyWoWWSymRve|1c&M@ +V)l2*&GP6*a)jPR;dc_U*0B*n@lCtv*GN%F&!pNMH&i_K6UZ1g9@PJMQIx&{{9U8SI1p6X5ZOMP=HsL +dgG`V@x!$}|7*M)6u4OuNndknvhIYvs~7tZvHXUrbbB!D1an43hl?8BV?1N3n*69$-NMm+6^cks%D!B +q-)|-BvCc-3R;}Ll1pMh>*7`#lnMvU1H>D +A$7_Jw#|y=>UMlyN%Q7U(Dc(S;LhXX8r{%TeRP!L+4zFW{xK(<0K<}t(7%a=H*@d5;E9S(c=pQhvQpR +_vxPNwB8!gJq8FV?L#$@bE%#)*D$IlITBS_Sg^1~1lWGoVL6AXhPLKk99tS*$3QRwPaVY1_9JI|3%>gkWpv^t{F-6NS%Lp^&I(iEsnGkhE*HHrNu(9>CD)FqQL@*-2@I8xu0_InOuZJd*W;~o++3>v43dw@|GuY^qjmY!3kXV@sTu% +2HOIo4`IWKPl5m}cddK{k6#fP3`v-r9+x*2ARB2Rapt--d@bXuK|X +HeNnT|$kB~I?%HO-@%_r-La$bQyj}*}4JwvvwDA91NC16u9{O+(`>{_b{)~dz&?_`R#Sf=8Cs-wwwE2 +TM^+Va!<1n@-u5dgY_{&iXF}488W|0j<5@X3Tj6vOqPci)8kVVj&n9aW|g;wfQYbh*8ZbC!g@aP}N`k +0wjY)bA8mma9hZa-Y +N-eHzlU%BC8s{dL|9^jwI5tc_QF_6;8956C+7}m3teNZ0d(0;%-|sHJCC5xlaEI)IPcpeK+rY9+Z3dZIGnM(V?DubOeP2CcGm*ayJH8gg;nHb<^!exjG6^GWa=Hn#jo;5yTLothA>@#Kf6KlSp5X&Jf%5qsPtsiENQlKEWJIr3SFI16EdC3z1Jj5H8K2Hl +zkprL{RsGSupd8U((MMeG|<*wfs=Fx8#f>> +aBf!K7?bM7Xwoj)Cz&HQ9;KLjtwfC!JZ?7Bwox5nr_Zb@?(1RYf>d#espKuULo7QLd`jaOk$)_Cz+`g +R#h1$8#_Je_$}UhoWK4&Z~%}1H<*o(FmQh_Az)C+u?x&n!2xI5{Nvs%W +6!MpoLYS1(cfAYWFXB}Rcl>cRVP;xv;z72h*X0v4U&H4LLh@yi*_V?yFW(8JM_qoqtMnK?d@6YT?07`g!UCoF6-R?Tx4eOKE4eHj$Wn +EYu1spsup0)FmFDEn#Z?mck%{}3{$%Ta8rs1|dp;t~G5iSgUHXpw>4<89G@_|kseZ|-;cM`$P-6(wkV +g|;FG5!$f%x-a1^!oJT9`B|Jzl8?;Dx9}b#W%L}3rjLy4Q;vn5QznU^c>(37|on|SuA4AontV@EJEkF +mgYY{qVl@`714CyPONF-+-zE?D$^a8R`3as +WMZ3}P;=HEdAaP?99Q#OlGbB|az@KgF{A{6hxk&iuzC81$o$A0(KrJL{A~(|O!(~=I#6&3!fL=NSiQK +ps;&$kFg6t1B+&MMjl^esfj!rE0XU*!D;V>v#m{Tvf|(T==WEP2tv*GB!U^Mhhhy4|_~T&Ce7x@pQa;c!_+)ldBV^aI7X_2FvV +-nHMm-gcj41_ii3r`~pdD8B&r|9ib{12866!a$7w9YN+$e*;9O4!HxCLp>r8myUf5yJJQKQt9j047cq +Eg3%9Ns;QrDFV0@j{VYjRd9^=q?;N`kD_$_Saff@RD+_$h<1ZvPUdNSDDgF)BBdpJ-9Zh +5cLbZ@yeQMARv(KH~dD_0%zR^n*KqH0wjcwUu-W>(9kJrP8#tC@fA#9xXJNuFJo1&ssDFcQc)r5}wza +4us@KLRki4ZNV~OlahBA=tY|f1mapfX9J)vk@vp*fCgl_4CRY +`Vf5XAdaEU&z8s<%qFwt!))TeI9TlDoPw!$#^ +)s({8(0bLWn((}7h*;fE$dCMe_i8>;a8KVKFK^FxFDrgHq3|M&Iy{UqN|{xs!}!>2&EqhHb;3JSHp-Q +ySZ!*QN7kN5H6-7AZW$R1EozO~@@F)L^$L}}RR&ZQ~m^3#}hyYYL;Nwz=}fc{`KR8$?JKMlJmgUJp}N +G;tja^lC2#0rj^e-y!+PsDt0+<&$oMuJX!I(1{F7xJ*d$Jx`SSOC-vL8DN +Wi}(k(H${9-d2VyEYz~4W1ye>#b~HxK?RK#!EFwaJ#R94UFi9>NLW!_3i;J|@^*~}s*!xCOh-X(?xYfwNaTLQ%40+!KUaNxcY`FU1T;Ko)}2wEIg47EBI|k4CD5G;?z~!*Bik5rR +0>!%}W#?*Ml*^c42)5Q@(*llPCa8eijrmdDQn>U-(0EFpBqcXi^P^XgpF03O~UlRg6Y9KbGf~m+~*9q +7h0eZiIvXh{x*xNS&s7Zi5*o5){Amexy=1>QxZ1Lmk>>ikaCayDidK%{w{& +lwsPnUqj%lufFnq`!PI?q@wM*uGhfiFtFaMn}nSkBgC0tR&pZ(tuPG@2;QR>2{!X8gHYAxL-jqT__MS +}LOr60cI}0<3$PEFdp$V?GE^v9hSZ!}2HxT~Ludp~pAr +eQc-j@npPP%fWjg%u1B<;tI*&V>muD!LrA*gD9duMF#8!QR=Ql#U;+MbtZW}X@EN~?@T(WWCKErQ1_2RF;hPB=yhCn4OtEJ7a^k)Qet2yN0BQA)IO`{J^fzhg`%@DIt^>I#& +kFsM??b!z{gFQRD!Mq9Gg1l!PIp?~4k!Is8?Cu^zh$#aFPa_85!_w`{|ofuST73vLn3hxv_p3&cVnM- +tZ%Nc^rIR~q+mY-9I7Kvx>L58`5Rb0qoZT(}h5fTUe425rSk#0V8zagiEEnI~PYELg0hgqWc2%yF$=b +|>hu8)!&kR#9rxS+B86^f!oA0w>7kg;g21B1WL`2!Xidw2F!*N?MTiiLF=n^q86H9mT6)>CK=w<8Go7+}$>S%aoCHZhWjQ*y6sfS +gQEyTK=?`AE1(6zd1ANsYP4DS<{xS!vL&%ziRyx~1h+D>AL{?->7TFRsQ!C0yEdcYxxI%;kl95mKan3 +c*TosJjeLLtC5sfWH!|xe8yT*_IVhX2X`Ds)iaMVY^sQsm~du%E)Xb8nZ2Xz5`s`*f@VPi!YW>leqyS +Y))pDbhoI^B^p@F)g2dMEIP7j)?=aF09u62{2?(W_PiN8m~yqf%j70_s|TckIlt!GxDx=S*KXmaYWRr +(wlKt)dyE!hUek50tZfpYn&focP{ +dt7vdq;fK%rJ#i$0oJ7N_X4vQQ6H(x(!2_{dy#=E?7||I9^sOHpEZFaS|HF6Kp~&8`V&lPB4Wpo*2{B +QctBb~*=c$>5?A~Lwi4-boT)f2v6=H?o|VJp%UXA)dsONDrjF+InRbKpr+y>aJ1??3+Xh<+ +vEOeo^kG4{FR>6gb*ReA?b@2eOze+=21dAbjS2LKmEO5_oPcqRlAZZVr^K*bZFpFy`-92o;4YGauw%n +7N=>4Sz2#;xV?2DK9o66@MfV1?X(7S=03hDCYQusv0V!l3YFD$E9zO4v513ielQX1c(x>`+)WR2m-+ +g|oZHNYTGERan$p#!uj?cgi?<(jGcx#5N_0r$sFc$eB6g;j^P{?5}Pa7q2=ki9i +*p--5g^{}$lioS^wIa`Zo+(r2*WM0_U)ZcM!g8D;?x^yG)M~;56B8EpWn{Wl5?vtTe;j-g1jN-+-+anO()k^o%{c$c2by#X6b(pPgl1EK$gJavb_E_uEM2v^ +s{PPpjRrR#4_O^bJrW!%6yG=B-Nr={)rX%HMKLGfJ;?-s=L(f(^lQzdF%F)iO@~i;_Iv{t*@oC7eb$S +hY1;f3VpheNSUY+SNshrlzf-I#SUlDj41ORs*F422;3EMVZt>7eP4nva1s_-<9k+b!cKfnh;24s@gM5-|D+gbVp|T0By~_l5=sTClkd4uXn2X>c3a?nqIMH4)PDZ!iZU^?`& +++DB%obMV<+wutx{0T)ocwwIY4qdhXdm$MySu=wHVQ5AZxsCg&=35Nn&JzjuE8N9{yoY?-6Ia~LWApa>n{rMlE$5n(Z(H$a(`;*uJ~Iwh9QSoik#!KRINwl%SAW-XE;6_e_@4>kPr-BQl#sBNksE%CqU< +CjcsnM#YU;m>HZj`P@_H%D4g$$+{5hc +!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFJ@_FY-DpTaCxm*ZExE)5dQ98L3juxZ;rYq{Z +P0Nu%J!10BcwD<-?E!GA&UK8(CCEDvdX6zkPQkC6SVxbi?$;7Rh^fFAwjI%4@MBNs>3JsacW`zNRqWeP)N*j`AXE6fa~uwBtLb_7#(}S&mpyMblflWwM2m{C+l@Wh^J#hDn*EqExI@2?~WdFIY); +Y)N1NZ3-0!w5kf8QpH92M5KzTW2tIJcfn#cBk;`UbN%}>q7ik&$o!>&JpKrfb0Ts=2?9qmy>M00n(j! +ul|jMhBgnR+L4Px`GoE@gMg +L2_aoz6cAFqk1+bw2}Tsvd}lZ$#sRdT~<#_B{{6Pl>p(V}4k$N$2Liq#}<$`pfyni~K@%Zz+!gk +lf?^jE=%!6X`!DOTHB@!5x$7Z*lHxg-U@H +Sr{dTmouQh_8~ofBll2oSZ&g5-K%-Y_`Bs#WJ$lo7vOn&&da7jCvM5^XW6Dj;0Mz0}0b9yhPJg +jbvf>6@URgI0zzcloe&M_gJH~_ks1$1aei2JDvd`m9R@w@>FEZ?lz)KDKH-U5S+(L3yB^!@4@`)>Z-m +f+e2ljA(4nN365kuKa%r+91)KP-BMNWd%0dVVkN2+22`e;2mN|>pR!7k@RQN`TrWGXYXMf-u~)1cTlm +-&m9j@FBpYt68ErIht%t-Dz5D%CvyuZHrJ`lZLT$=Y&nk9r^3Y;M$am!3Ufn?GPkMagw%Gi3)-@_Wer +~O6S2&r`u1o4XMZ&ckPKtr6zmJdPw5P3QdIU~tT7VN=NZYUqU~Y9lL}$4j +TqU8Z0{VeZ|681r4}Q{z5Ub&8~TDc^2At)TY9U<+3c(&qQY}Wi#{XU18{g(lPu&kOvY1ntW$z<62e&l +JdnKPiqpbmAMGKft3kI%>rKp$NrKChB$TYkm&6tBti=a2oy~Cv=&#T +bjrE@XL~Bw^{`{+(;rZA%6B6j6(7rAV5q{Dn18&@itTP|$dZL=DU@}Y#xioGX7YNsFhKMT-w_5+*)J4 +HJr;(PFkxSw=$!V%Yz1RB?QDji?_mIW)j$^Lk^P#D*w~$D3$bSvwY^=`Twj1oy0d?p|k6X64lr=e3lC +!t3^e6^Js}q4y-3w$D(uc$CWi&P3T)a6aI=fg?zTU8!X`Xdc2+>kD>Y!c&9oaqIfzWC-^FkQpLIf)kY +-k-U2Q&1Rp$;$|;xgR=se2Vb?y*gmL^JJFuo%cglT~!`fbYnQij`r%U=hLJEL;o`(4x$N_(MZ%c-cYN +u?_)L<2&dUpM0*^cBB#1c<`qM^la#73>m=}z4vgy^Z+{dw{ekV*I))@ZRw0ASqq0}TrG3}2XzS+0R^3e`>p6sC5b9h&wt5WQ~EL;U_kKo|U`t)A2(l)-zOYsjSx8LqqUGt1?bd!6qBYvb0#%Hql;`2W=nG +XJ-(QG&P@6G1WBi6}}T_&deF0JExF(nUp{y*G59B+T>FB{$xy!asmWaw1D%@rHU^-c?%JQTCl+bZ1R +OD=0WwX!WR$dQlhkvK_u&44 +7cKVnSwLI$n5+St5h%r{2i4DH&9>}iJs<3a#H)^aX +woLqm-fPvWq5~i8Ttm4kQ00c_d-UZq|vgV#agej$fIG-T)d^!At25G+6YRK`qd&_h0j}Mey +*Gc0F=^v}%wY0z8P5`#Pd;qjNo72FP?)MJQWHPwME^AB*EG7XKjAQJ%f`0}0L+m8SOTSSM?1A4V1Z*z1maCwzgO> +g5i5WVYH3{nJ^3Y$f-MNzoOWzj9*!*+qTw{9U((kNy_kt#ou_|o6rAw|iS?PRk83`^vjnKv_!!_Md)% +Chs$8!Sr@{h*BlURy1_!*cx2(sH9)Y;2Zw!ODBlPWbTt!?-N;wD|tu(C$7ZI2(BL!0*vc+g3cE?J!!J +cI&j)36$+@^E>|Q(Yjy5VwOD_;n2Wc;>D!a4}Qp3-gTRwR>fcM{?4+j#SWUi))vcJd)0Dt$ct?T^xWL +s#Q#s;0QNOE+*+aTNZw$N%0Z_M^rApT_#qU+f)v()?jV0y!(#!?6JHBlwa^OkyN<5`WC;~bw~eIyw$*>$NGa-fsk +H30rd0|v5fQ|hN@5*X4JNMZ7$Gr^AnE{hj)m;#*Uw2s1WJobY{1QsxD#p{7eFWwC+N%Y>xBkRScK;ge +MH>6zKnlFow{K`YvowO{M%?>T(sc)%;Ujxt%!R!*5qD?9Ejh5xL`VVf4ZNqD^NAZ$ +MWg$HJ5dWM+~IZC;RHE+cBMNEcoyVJVlmh&DjKTt~p1QY-O00;m!mS#ye4ww*U4*&opGXMZI0001RX>c!Jc4cm4Z*n +hkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFK};fY;9p~VP|D>E^v9RTWxdOHWL1>Ux9HZBRNMiP2B1Abf +e7Va!#9Rl4k7mZf<-Y8X_SHHAV6W(z4p=f4|+u3jva{^}PnW>uG4mL#jTX={-rOm3^PZ +Wv#xGH)A^=-(4FoR)bm(ngkrvO}x3NSm_E-9TQh*RohoCQZGcGxmgi+BciBV5buXpB3)c)_E?Mam8yT +?2a(@b1937xJyOVuy-_iR@Y@c4;GFtn$XiY@%Xb-&P6JUCg1<0ME0gE8ZHY_oB3&36nc6EC$KBN|NQy +W8~5ZBJc(%RA{@Mz2L4Hw`$VN1u@z>jKAO+m`!eM?@GqXXf({$85B%<2fb7iAPjz{>zaTO{6*on>D-5 ++-{I3CQ<%KL`+Zrp%nSk$DV4a%`dS5*YBG*SK3p27XK?lO*AJ4tQ9w%PF4r126bm)YFJfi6ifKg} +)Odh?J*Suo^G`D-9CjwP@bMS5eQBq~KeC+3{p@aq&L+;p{*E{_*^u7ch4=y%9h}<^oBk0>l^mfYU1a! +4v!q-w74|XR1`5+=^O(K)tC+ChI9|_=J7l2)5*ao|P1NrdU(57JltEqF|Y5M7@;-@CySRH3-^-8NfW_ +tkW_9@$W#b*$7yim8>WmR*QVk;2{jM>+5cIf@G4L-Ssu&MaEKIu%&RDiHt4xxCY4mbpD>ERAmErl_34 +Sp{A|n)I(Yv!V8FJk{|gV0baq#$bL4}JE9skrD_N!!1MIjDdO=uKpP|xkud_9o>F2uHP13hqR8zQTa +W`vy{bWBMWc@@n2%}&)DEak7OLSzD%dTrC12(up5XouN`&A!^`?RhJR!x2;qEUWtVV7{*^-pd7^NVnE +BKZ+BS1g=nJ)7(y`jZrTc;ucX~3x!;QyG|zIX)R7ail?F+9e769)Q|NhVe-fj_*>n*{B-DC;fH`r5fA6!i5qiW+_ZCDrpSK8rn6bd0|Cy +xU1GZv-osKLc`MGma?<#dO-)EbT+X5_;FzGuTDkX-DvMqaB9z4|6TAYY+R^0Z{F33-;@8Iz<6GNDl}& +d0TVoj$@Wx!jvmm+dDP}OSF|^e~U}&POr#rdt-54?!dr$E6D8z^YutD8@x?hd)&^RJ+nqRK}YS2UW2eFg62@vTbSWN)_z(kr=!Y&Qd9>%3f2s6}&+7${H{nFM=lY1Bk?8w27=-_B6^+GB2-rkc*XbQrT+4C +Au{4l!`5$5BT_J)X)%N9MQ5gkl$|Q>c459Z7RTCPs2zqCe4I!&AX5Og?)K9ino%Q`#u&rEF?cih;cXu +OksUH7^vLl~Q$pfvCv;)I7Zbl@b|X10or&_2NFBRg(r!8v2u>-BK9$Oz&g6T>@YLBLfoXe*sv+`twYx +l$%fjqq*R!adc`^Q)nn7fpF`M;2Gqh-NxVR0o=vrUgRzTWKI$hYYXt_ia}HXCJha;hBbtx!Vwd9RW4H +r`-i*!myEZU!FX=8ON?kfCR>`kHAro`kV^@*am%b59A=?(?hqecx}*$mXLo!HQDQ!yIEt@cy#kxnwz~ +*mc1f4(luH6&+gxqUwUBa63O=8q?^=bN$|+dLP=%&w)Qb&p?8oS +D!Us-s}5k7XhB2<1}=1j{B#W=iC%s6+MQ#aEF9$pV)|Y)t>h9RNZjjeCR*sg6Ayj)w$wMClENi?l^8# +!K%`$&X2F(H^T3YFG4(i=1zl83dR)tKu|=;ThHycIp!Tc(YRcU8IMRg3B?(R3)<8?2vU&pD3wr8 +)>4;B+jw})Q9nEWAY42WNcuxD2DI6+4+RjXsEx`z&6+TdqrvPuPru?WO)!hr-)?zshL#>3t#a^nHb2l +pIM?Lg@?25Kuf<8trNTUV-_@(EYj5-!qm>?Kh1d}U3~Tzh5vAl2wN5;qY!tzdD-D2vb4+~?gcW{T29XShq-1qG<&=SXet*O9g>V#@z=Tk!&^Y>g3OPAakb1| +b4LM-2FYRK=h#gS;F=oG$3)FVr%MMgUq%e&;xGa_59}zYx%((jywLiBNtT0pKt9BRim?Ay+cK9;(tpem6{DEhMaC_raW=6$(=^cDuCpfN=-AFZZ7`*_%pee +#BjUVEBq&V&2df-z#>esvF9)ZV)?v=2{nWhs6c7;j%Dgi^D%&*43|wktHW$JLSalLM9{AA&`WJsFbmmq!Sfcu<+_*Lwid>kJ!4(Uu|v9C<3VkQ5rrBAwj?iWi{3sXgScWB+oY&R +=YUEd0)!h8~e +nvEjF(2c*cg+sMrZ9Fc3)-KcSNP)X{=59}p}?&Ar%>8_D#!v-LN97|RT^4weAq#MWwrJ^=sS$Wl~CKE +(Id~TAuP~>sXcY&Z6K7;7DIt=)8r4H7^9Ky>ICOw`$@Eg<-mA^ekbX!T-HWam^5AxQfx0biqipveyaA +gZMxA;m4h>>z&%$G37g-KG1D!E6Pof%Hjl;w?lF?;{Vq +J<=Vo^~#aa%sH-#7JE}PO7wm;1(W#ln9$Ej)eOes&q3yWR9j=OYouIv%aK#(SDM@6kGsCSSW)(->%dj +PBzk1#gCcxRbXtww3IB~W&zF#*j?`v&hbbhwq*y}k(Qiiuv$tNl+}+KPf`Epm?ckoZP`Zf#qd_%6l0oSWBSW`Ton6M_~QUXK3t<>`xvU6{tkH}Ti;*Zy(b +(IK^LT7_CX{pvJ4k7=JQ81+Mg$b{F}*wxxmn06Q21Bppxlh>J<6X~~5jt8PMBgxjV7pX?$IK{I~V=#6C60aSI3umO +kC5hQTOw(jWf1>a9lX>GsCo-eD2u +1PyQz_zC4Erk62H&=eB@WO<*^Dt}eMGZF>W7Ja=2mE;|r|c=~=ydg&8=5AktJhN8w?nsk!ty@M+ncaHf;CNGEUVs2`B26*_!BHQ>wJ#mf{IJ +%`XevcRxY+;4Cqzy8({8{*}1n$U_aT@Cj*ydoJSy1}q_g0{i{<@un9<{x*Lsey#Lt4?ba2cZ7vw&;UP +8l$_>H1zO!M%fscgWuF2sQXXYqtk^cle_`5Yd0_`o)ZNrd!Wg#4-$H*Lxr<|tij^15F*p>>mo@=ujaP +XPj}4`#oyN{C4uykYU#Z&Vu-}-M_m{DbhYX0UZQ>*7{lg)-h)|%?`8iw)w@mSZ2Ii^v#Dnsg=ioq4$9 +J4j|Yy2MnZ7dJuau;+w#&Z^j8jY7Jq5nRvFaZv%yOR1{8MQpV8^C?F|eCvy0>L9!BJP2>s4Md~YG|pZ +KA2_6d7yG94+h@Lf-I0I&d37_EF%a`!%y^)n$c(`U9BSD4|wH909HYhns{Amy^M5&6DH1!0S8@l^<|P +rQpjO1A>Grb~%Gukg0u|VJU9^))Vdjo@luPZDNQ{jJ1n04(0tv9o0kW#wvyzrV2 +{|8V@0|XQR000O8HkM{deKT~fmsJ)K2TC4>IqXexXW}YU6D0w4W?FsDDP1TiJpg6rLq^feJ*=#o3Y*<;M$}9L7{lfp(@ +mAk*y_0zxeZt3C$=Vji59Tucjc0mc6*@aRGvAl8e&V%2SsW_yENVb0VD9r4_B%=1l)U0KItG>%@>*_D +b=mNG3zcCVL)&FL!;ZDEG?$m#Kdia`Ofp&5C|Jn4k+Mv#*X#SsaCDDHTVQo=u21gLjf&Omfvbc_Z|(1 +GGBfn|N1ITGV)OeiA=wNl(LvKMo}u;?9!Uw`=-=HzSg^M +9_^F8Z>Q-zWZ@Se%nz=r8Y^t|dkxO98p>_xm@LtZzb&TPFwINrn5n4`{&su +k_!=`tte}^@GYTs;oW${>TU6i9u-Ci?W1L%17uL($A)2(}!8GrqN18EBk*6qvthqOdrSge`-pi04 +7-^JinGK9~s@~K>3s#EXxdODE;VrJ(rL)7Fz>c%r9D@5?+XG@P>a6T?j=F1f3+nH~5kps(97|ZDP~~} +0T;M@qy#{9dxhX{^ba_ZZS(_h&oZEO~Rv30Y{}|bHiDHN_hv3QvQcGUa;$GM1xURvZT*4mQWOalquh3%aJk1urT!eHzCBAbok-mF#v~tmsxot^iDM--eJgnLf^ezFQ5OS6?8A_llt(kl=IVo<>W5?PWrTC5FQ}pHG73l(CK&>wvWI(+Z-0 +MetL<5X>#<;QBCMeG?sp`~2Li@p`71%>H4i^4*R2Z_YdN#@8p_@v!RhE^z!Wb%X8pq)$+XIfjGb;UXs +4^>LH%+m7D=lUG;2ty4Cq#^lz=p;Zk#l#=DAyEk@QO%n=jHwoO)Xt~FU=d?CSNXK5L=NfKA$R6iU(_h +~{zd14YM`NkI$8N*I5QYjfNcsM4`YSoZjO^$b?B6u93mvr>Bi72ArRAZYKv}`vVn*u#HZ?mtYf;f0A! +P#B*hQbXGV4Oc4v-?7M<4H=k$9+4X6WeF>br|h?*{6Bz=n!r2Q83pZeZmw>%uxf6U!q%ynSM2N3(}Q- +Ys0be-~KMQ!-F@I6@|H0pSljB+cpX8o9+lDGYLXoB>>|?Um3-iGOCy)oji&Mwo+cfyfVNGEUqI%U)LC+li~8z|X$18 +Nec%+0e@jkMc(^EC}@ZG1I>K4RgOq^y@XP&cpUHZF9q-|4S#5&o3{3I%wc=M81d!82etkoMg1!fhl_C +?dAMreVq9o`5-kIV6(4iQiNQ@10z2&Xl;eY#-Fk#H<~@_KyO{bvO7@nxbaODB!;nXDjNfFtJhzZx=|_ +)fnH4mw;0KoE(@@6aWAK2mm&gW=Y39ok1NG006g0001!n003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb# +iQMX<{=ka%FRHZ*FsCE^v9xJnwVkwz1#+SD^BAB;Co3&+be6+`8$-=WE<)ayPc$OFL;sf<#b4O_3@IT +2cS{x4QsH0EBo>U)l*jSP}^=b{C8NO=nfPW%GH~sHPJ0Ig{I6St-Vsb(uFx%=Pb+42P}CLWv(#E|+$g +xwGX3UyJI*-2Eqvu-|2==ho%wNhmu{$*m|GSf*wV^x#q7h>aChRaV`|Tl{&V2PX4Xndf4qWLea9{8x{ +UAHNbj71cYrG7uB-!%FPDVUrUE*T*9)Gxkob%2b#i_W;D;)!wOh0786Is+&zyJc;yVY8Ke>)f4 +cbPHOpsU7}W%EY@>%*ohhmSn^uvdo#9_1+NbDY{owR^)dn`*_O|u#do9BZobN;D2Q$N6WOe%!9En44K +5dMEzvXfB`p2$@Mq0DJ*QDJPbx!^ohIvfhRc+-NN4!V4w$QQz5#}uoSdw3Ue~~?EaysSj#ZO#`FB8Id +UZl5A$*NX!RUOzhd#oA}JWjdd@WkQLWEu>C6=4L*T9N`1+Z~`I-`4Ezx~Vn+b{1PAEw^i9_AtT!Io$S_%Je%pFEGi@uc +jVvJkCY|M8!4_pb`|Q9|E*&R(;S*q^JEzFbmHP6&O#Yn~dGZQ-w35EjEXG2(B^aBO@gilK3n?p$vs7&H&VC~bn!Z>d&tTTBDtDq%2bj+IY6aXBX~Nj!#(>jw;={Zy +nSV@hf2X)k2mFf&@RB9Lx*ivEl^-R8~L_5L*dgZi;q<16@4j2wzJ +(lNw)R+F6;wPp$}HR)M(f%j(H+^7aQ+akk@lTZyV>8CdG2*zjjrHWi5)iVK=7fNJ=gxZE{I>xy9DU}W +Z;)-F^hFLxOkiJ7+%Kre0t@FmZYDl;4CN*gq?NCKGKhU{YEEu{BpU>!JTV!Kl{%7q@x>YZ50Os<%jbq +3rlQ&?xLEj#Wy+mPc?w*V)(d=f_dX&=U^mhADg#k+ozyPXlBitp(VwhtQs+#O$_2Nv*YDJ!`~HP@Qzj ++}3`@X0`;_Z5c)E0nRdfOA2zKu!UV?@|j;iwHOd3Wx?iJd1)H65x_7R(S(#!X2_Gkvybg*{s>FsdnI0 +)Cs$Txg9_lUhO3y)f7l-(w<}ba`WMv$J=in=kIQBKD@iVe*o?Joo42&+>0VhMOQx_!SOL4c}-)&%luLw^B +GRkm_qKVZI3Jn|&y~%{2(^$}%@!JKv9PSZif8u&hyNI2`MtQ+7;anQt`_J!BCm^faQJ`_+9 +RG$0tM;+bbMa)J}Z&R3IuSTmn)8982abdGsNp*Q#N^uqGhKs6#c;F$D&H8`Ul4f(Vleo>tRwAwK+rb=tc~3!JnN@l*C +5{a*|($}YUne!JjRE#3CV@61+he@ +dXajFt|K6C~@EHNY_{ZTaAB`^l`BAGhy6!RRNX)ylud=IkBAQH-Wm9Ve*0kmX>Iv*X@PG!SDzAc-A0v +4-zG@1Zxd4SMJsLj=4;rg}25q)xK?G_w|B}q?euf9cNB9irt*(g|~)A+IS*yGu7$MGb;(}vAM>Po1yW +=A-*E(uyy34y7g!y+(<|8JDPly2xLuWW;{iqi4p%)YHJ8AUOG;ex +9M_{cFp7Z|eaMVH3bG)+{JZwVWeyor9kOW^j;mH#h_wt^HXpo<+`fI_uU|l4dp^1B;)ba1w8{ +eQ%*W^GfnU!C)|9m`HOVIz=foIOyVlSM;Ry0&GPKWFyxbGl%bF(oy{Z@sVm~{VAKdvpx*^A}GidfS@N +7rE~>zi#Y;nBc31r)`>4lk{OXnda$(S374I89_EbcT+A59P<0bdSECZw5q6m3R^uXy(` +QU=2;p%0l!Ak4D9~;Y*$stRU9}ewLRzr(7d?=0I4J~Y=;rC@rNwki(kCgNnTY8XMX(}6U*I`{oyHJT* +2aOrSa*Y2#e%fz-iZ{uw7FWE#E-CX=qQP?$G95Tx9JZwnPY43)lLAnOIdF6u%qO7A545tZBc +O~1PX~0iL+O!}V*I2Y8JrNxlWG6NoU$8uWYcavep$DGiWg0m$(1bv5X1;LFkKaxPjZ@oS2|m=;m@emH +YK_uS;!>K&$jgB!&7BBz?Nef0-qm_97P#nC6@5>sv4DB8q}o_Ek3aI&glxE84u;f7J7K69q+!sv9i_( +O{RSYm`s3^ewn&y8J?P0hi{cBFa(J>Q+4pt2;?*zi(lnd=Db28O$;6@G3iiT`{cUNxi1+{Q;A&SUGlj +rHeO*#)k6&;dF0As;UTwJI1ZDknE`P=XTE|%yKTVV>jY65nMTAClm$}&#QY~NK*48it9QPmD^^_V43? +InMuoQpzm8#SO^yvAh_qnP*Dl7jo1Qg!?tyFfwMWNLe9_i2sg!66nod+>bGKdb(seoU>IY}09Mng|!vt3T4XmNm#GPeFFkz(ST1=R!;!l1I9D-&an6m>%x3GOjCeBo9f~*`2hN`l4%O=5-hw}fIN2n1ooEQUo&WYPR$99)=v^<&|%0OK{@*qe0h^(ualHtl6PfM0Pm@B$a%fwJ; +xbOTA;iPpBi7fDhd3pkX7Ca~U~!#IqgfPp5ba74M*uX{Z8#w2`(pNZ*moNF^WKLU*B$f +5&maYFhVeThv5WIJ7i@yaTz&T0vRT)OhLx1n`ZEY*8u8}yi~s)36 +c#@MPWQf`<^Vrw72_!8{y-sO#8abc(!uIcaG+SKElz5ghkyYBb-LgJ@%?NC$~rl*K~c%}G)k{yELNa? +eGQ>o5q2ly6-hKsUXo2c2~Yljq3N(PwM4(?GMY%Mu@!3TxI7oHUcLD|>hm0NZ{FG-8VKcWV+|H&wT(k +P!qDp}!H0ND`(;{ta)=tiP$}8jdTR%C9faKDCC2o`Ta%{nLd7EEMn?GD{ +vsjE>?&AjQpyYgjw5bit|1;C~BYrL|X^J&6=B`Xg_+g92C-zB=ZPp`>1c&_8W9)C~4%hj8Cjqh=6rff +HiK{FF>##o<{YNk9~K_|3Lke`Utki9uL#p*qn(CL2mMT#z2Bzy=t4@pY}&i{U7DCz}gMFBJlB;X2EP* +4jk=jv6xx0=gwiR^kP&XvA|3cx$Vvmpc*%_W6ZtSa!DB+rxz1b%BIX@;!Cdyux*aSLJrSM$C)KZY_aI +~o>dr2#n{oce^tr0UiTW^e{>fb%=`G)OYPBUD}LGA?N9ZbC7^e<^m+AA=(!LOVF#KkT8ifY0;>pGMloWiG+YXw{;7pN}@rnnoqV@u7AK+ +i=;R=DZt#Iy2)C9*3UEvDO@K($tbD#rn&p6PZqt$-gGwi3;KAE8#&dfzRR648UBlwbF +)sNpq?ldgg>2U1y5@Fk7(BWbD@JV1cF*lwbS3x1@E}1uAj$Mj6D+eaJD1SV6sQ6%t{F9NV)PN?8MJSt +Lt7v8&lA+P`Q#=^y(W6f=)ZjiyvybPa$+DbLtZ!as=r_N^Z|$b1k=lQEjd)c;nB@@+2W3^s9azkflQY +$&=wT+~d1+f%B62}6J|$yb&D&;c@y(5X9~yboS~2N(`yY+0u*n~E6uur}UJYTMCQCvs;!6{*CJR;CPW +hj5LG+ +Hjf=1({r9^#|W^)#EX&;<|&m?e}#i>sk03or$;F%CvqNw%;GO(=9!qc6&Hthu`U>AN&1XiTnFaGl+I;Y>!Q +NV{h!}6lU^4^S8zjEF-{(BjwiK_RQ@g;>C>y*3*+?m(whA>!#iiV<}hDq#Xg?bJz)P|ME^saei4x-m_ +b5+9|9bP^rHpwKS_J*f4fNgwx~^Vyr5qB;?m?`NfN^Sp^9XzAo(*-Ee#fu+7_gHv9GYyrW_-WHjHYT5 +a2d>4>LI;?$B@3j>lB+nZ%ibK0`> +9m@!2$Ykt!mrLBY@ie;5L~KApfKx1H4yTx!$N(78G{!M1X*ARilp9t%Et%=SW8shdn>^OH|=5g? +-Qi%sf)={L?^jbAZ*SjFe1U_W<){G}_;)zZF;Z-8^gtfAI-YNnik6zl$bWFD#*KPj?P)h>@6aWAK2mm&gW=Q}5 +00062000000021v003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kV{dMBa%o~OUtei +%X>?y-E^v7R08mQ<1QY-O00;m!mS#!5n4CII2><{A9{>P40001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9 +L>VP|D?FLiQkY-wUMFJo_RbaH88FJW+SWo~C_Ze=cTd97JnZ`-&Me)q57aj~#mxN^6}z69_?wsm>}G# +4ap`>-ekTB2=jBvD7Cl6Vi!f8QBiBvF*yEPDJ9Thws)&3%U1RXitAw5w%Zu_z*GUh+y3x)nUDC5!a)# +4KlgzfX(3edNOadZJYUFT`ZBLxy39V|K4nF*Hy)e!*Vt+?bd +&pJz+G-te)ot69h&+2J1Zy=O3exQ3MLXkdO5WgQK6PGuZq+KW9n?MY!jDpRtgZB`ZMJ_$##=>MGkY86PHEyW~iYvP3KpX?kzCUgIEQ>vnnGSgGb4f)$(BD8P+peCRJmU`(H?V1MYFpWOb~fsd{DBuOhcDFYJ~LNb~Vz5{BI9LW_Ume(LBOUOY=IAyyaa3}%hqTc=qdx_*N+bqpfsc{f0NWw&1rCZpX +7K#~S=-^LyT<5INJIH}m>`bG_51uE^mdiNfbrKpkiFv+kTxALS#j-qt4vS^uD~iE2mvoC_L8zu#Mk<< +uL(^i!dL-SQH3z?LKVTb5)M~=KER7#eYN)4c9kP!BOFrUuXkMBsJ?VXUXS7N?EmF# +LjBY6D4WW$SqE=%R`uy^b%N^J0o^e={#Ij`_M5bD>rBxifN#b6)UX2RLu_x_#UCy(Af6s^`Os|y1U^L_<~2hCk$<15MU6f9|_w*qE3rcMo}PGw +p)OQ(1cZDg|WUMm|Ie2pB`zJCg7-1%qp4gFdW!wQ`KzVS~lG&b6Qt9>sWvoWFyh-P%4oi55EQd~K?WF +|RD~_0A^vbhnp)>by^}G#MsuMR(}gkxsddzekZg3Qn&-hB*h!SE&&nnytKN=I|paxdZ?yIC|T5^)aZOEeJ3chgdThb +oyH0>Vj-}ax_WANid!-y9uXa+Hq8pSrF3Cfr{`JOM1*WO;)HN|E<>H%Ba$NZB=Q$(VPDJKc9?d8GnjoRTt=!$x4~ +cC);sFXQdV^Uj!|&evduM2!YaH*bx3}Mc)39T0%FG&3#k}$d*A2uUbPjgM{&izO$6_@T{VdJyoQhnx^g@Ojzaf~e#x0&ReWVG6|8P)_LtAOcK+v`M +|E;EkGu>O+u|Vh8GxCd=l3$wQ)y0QBNz}>rIw4uO&6`N_$RTxM*wsa^IJM`zA|DPceo*shlS3_Ox5Ev +bV?tfSG<}qDJ*x)u!OYv_XjEUsi>RB`+rl@b>(Tg_N-x}|17ZR2Cuj^0yv`D$?=Em;#o4}*GVF?Ju|h +)+Dv4R5D)lk2HWDz~)*^~|!d9+E^qamE{U$6-i@0LgH~S9bG%=R1d&+`DC5!;7s<^2k<9pz}J_J_a6wr1vg+`Ek^jtV<{>t+RbjQ +@z9~h0R~(zYKT^@XrVC^hIcSC)Nd^HtfN^YtiU-S}|4IlW2f7thKBTNgigZboTxGi}Xc&o2 +(3^WePqWbE_T5=|=FpCbcfU?Hq3~$~ZAdl1)!+etPVuniBcgS@GPV&gq1zCKkiw6ikX!fX+R|Z4?O&R +i@rYs4j4R2p4$}E+^bTOR|Zwj?D1PybSZbbdQ&c4Ixv&Ag@lcz<{aQB0&dz&2eeDkt^F(EP6oe49NL# +=<})x!c+nb*+um4F2lul&~-0hHO}1@=la_9jcg5M13jw4H#CavQ9?I|;mrvxViq(hcH`l4 +v4s&{o7hXFW--=R-+n4MaZ_YJCmN_dxN8j!XCsSXQX;#>*rZUgM{F3i`>FY_0SN_i{Pt!*t#+T{(hmp +ovS(~N?rR(SL%(;W*)c&wtvaF6218%%;J;v^bf~*HQDCiSthyIR?ggi97>qrMY8UP3jaO{lXU*0H`U8 +7UhsOqEDJv!Ri;XV~jubK97kDjhaH>HH+7!3D#Wt{{6@?}Si^kONFkWz*XY6gDO(qjGHdKGF@EgJa-e +IGhbtwRt8&7`s@Iw-F)jS`75SdHV9uya)(yI2kVa_dM55Ftn?ELn2ef{b3dL7+;xyH<-Mqn;Nb6@O@2 +eXe5me68iL%i$}|1rB?-+f)*MfW!sn{VfL>)H1Xl;I}pCy;nI&@aH_aXF>NQSi?H3XBBpvAU;$Mlt$& +HCyOw(7Ea!WL2}-edkwf9T+52hL)PrQ{g~56!)0De*9|82T;rWn&Hc`&zL4<-ePX&cVJ2 +nTBc&w;A9Ta_g>}4d@68~P_RdiLS+fA8%wK+>MZHCR2AdDYBTrf-rlgIWFm^ +NNUicAW@6((!Cl4|sKjwk~%p;ez!^i#z4&puxHzeR$Gp5`xb~+fRJ@sBZn%aw$i=P;r#`B4}!op;OZXTAmwrs-GSj)LX1ja-nX6 +UvpMwwkMBTrylqRV*b>+sjXEzNXVoUnfC>15YD0q{kU|p@62G5zUT(uSf@D7iY`n9;8TAubmTSkpR#- +JDflgP?VRvS7?z7{>NT5UwJeJ4O_I8fi-=UzUH~bBk%IneZT00LLh)8%5<3In}f4H#QUbAm$On(O`UQ +M&~9_*bl!V#JUWHH4ET%>66A~{q<&?$!$(A?8ir=S9p>0)v$@@;&SO_RhXV_#tpl?h#h>uT4gjZTut^C0B#o7WcVt()aURRrcwtgSs?<4~v}v_@X08z +%$@8au^b0rHJiQ``RHS1reBZydccBtzJQ}$@&OgAG--DiO0V@!Y$9Tt$$m_vI7iZK>itx|$QHvzN{+Pqp!tBr36r$f)6Emy_q_O=u9k{$h5V}Jl**oRzlVdnNZOFs%tc3@D%c3htb~Qgg?aI=Ac2A=7S$Ddt2sbHdxBzEEPke>as%D01>m=FuG +^|TVq+W9mR5g!ZINi6cuY6vk|z&AuS4rQbR<%c!Rz5*3P@6cSp;)Yq9sBHLWPn(OZBmi9(T_1NN{s1J +-9FY8%I`M^tZmL8W;uuJX?F}EO%%<+ff7QvmNY{;97qJP)h>@6aWAK2mm&gW=SLDzYK8>0006m0024w +003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kV{dMBa%o~OaCvWVWo~nGY%Xwl?HX% +y+s5%be#Lb>8GtecOLCG)*|0OROpVz{BrDQ(9oGYaz>&NN#34996zfTUdw1^+z~Mnz$@oh<{zxT^U2sd7I~8JG$SjXlG#4n@R*#r>Xka;Z5xTm +3R$tvYrsp7)U0S~FQq~J|dnrune-~?MANs%{;#f+r%*Bo>qTq5m(@-M+9c#Muld~$m$SVn_fWPHp1MQ +?AdEf4buTn9YV&xjxI2?zb8Bx74jDq8R~Ng|XE{6Y~HBo|2d_O{^owy&KQXb-ePvvfa@Kk&o0G8_)-p +#=P0nsRz_9eoIBl992bF-lXOR)iB@2+Nv4)a|ufSB#iC`fmbhQF0315+r34a;kQizo +oi>tW>4x6M@2sDI|1BfFiCASwhktdoiljth|tDqXR4p3+9P5R#l05QGU>f_@-!a2U +}q^kxZ~$%UoWJ8blNbb0>vYT*IL-o<$KW_06SjpvKoTSy}*192#@b*+@}PTvvMapPlI0{|xnkPX1YX$ +RX{OLg{voa+)##B4xh91mW+ps~AScPybH^Ie{T3BhnK5^6hlI3_Dg7_6+Ey=k +f$u$d-NfRILja{*|u%T!1laVo`D%WuLui&DR`7;)Kk}%RmP5707=L-l8_6U_7V!r$_=6jO^s{*_SN6K +b5Psl92l9uoz12(yyz&LD-?enq&G&KUKgg&M5IG +O1sc81|1SJ1ji{{ZVwMZs5R9h*;gaJe;Ds+wU)I)S`=n$$kJ)`6-5fSnAM%6(6g;>C*VQnX-FTk$2`x +CD%jc3wrFcS~ky+$tkO8;HBB255cuK>jgZsgial6LUEuKg9w;)VvOZ}($ukyNmIr<)67F1ea?VZ{^xla{91~LHFFdCuVQ^DC1>0_HM@AMN0+Gef5^<~b^p1|4JAK~ +n*o3pc$vod?O(7AbnwXE~GWxEd36_)$0SH$yqhWi~PYNND2T;C_b6FVTUQv`hW)J6DK?E_|C~};3g;S`_w$JAi_Y +^n3h;9Lcs<*JUuWwDFs7A5WlWU)0t%^MXbjTcP)-98j_y*dMEp}Y<^GUt6_iNqc*55<=yr+GQjNnRok +4>7wUbi2;`?-$W0v!^ynE@{jV4pCSreKLK|L +9SD4APtED7_DNfii*h46me^fITjij#CGt| +b5`E%@DNh_#sKTvWpjL2-gSl0?uIxe9kV2vB(tBZqtrI+fWR>iby<2dqC}EQFU>jwbhl7A<)i<`!zU~ +_Pa<9N?j+grDHTWClD>1~a+_1hJu~v&~WlSBYswb*Fw|dw?3PC$=*B92+1xrpE&x42yP*b^07xLqpm` +mw}tSXv0q;B1d9_n)s=fd(IC6ufoOReP&EuK6%FAEyy;SdanYm+p5G2YMazt)mv%>z()L|KB$&4;xJC!C91$7Q7nwpJ`8_7n&ot#XlFFCFGBl?)!#oT +5E{5(Zy)|ZuHulzj?cOJ$*m<8ge}*!+Sr@Zm1tNCe?Cn*e5&qmm#GlG_Lw`T68`dVf3jFm5l +l~g9`-L^Dd{?YibGivNSwomtvj0kaKQ7B+%ies`ABWaGhs%?hOB{gx54=|R +yTDaS`pf0!5lnbnJMwsHPh_{?{UV|;Rg8ez!UHQ3F^O=FGyRr%>VRWgODe>34XMzNM^e0@4CmdG1NOW +W#c%6wA5{fjAzjP2-QcNG|Xc>{E=WY(paoylS@@4)HFT9f2^c-aR9 +i<9}R_&}X38-g?O?crzdy>j1!bYb+%jOvx);%-94?k{E?hK!Ot5dv>fBL?B5*=MX7 +0mb_Bu!|5r#K*>?{X!=*OBuW>4YLkaC^OBVa--os{pD7yheO%LCl{JEo~#jT^9ZRnwwW3=TuJaBdAK8 +_D+&;}2k3kux?=|0K08|K@jM!Th{#)8Z7)oAfyHuBErlhbxmKzBjsmv23< +`Ic(R|6rumIIBcOyg`mh+I6WO6pFTwc1%P%OgNrVteU*~b%)pW&KIM? +PJS`q}9Te9_F|GkyfygPWKIroBH77*l1o4CNS9!GV#aw-dkdiiiEs=+c%m^kP7fUX>XS +RVN9sd76z|I+dE*k)_^VLY-GeM&M!E(88_3r^He6)r(vK`O&JPQ63Y8bKRNm1N1=&O6VDbVsXZnyioy +VHRh28|&s+6ko6fHHNEq*~@7GP-XYk4BIq#OU9;k#OVCC63jO(v2kyW@*&>ZQPai5Zx6Avn$KC*92{u +$NqE%7fO@B$e;K!E?1z1J=ZmR>3i2{UEf43(8CFO-|z&^<#+ws<5WVRdlpvrEV(IJkkat)rk9HfimLi +9U9>jxN1gzv}ZchDXGE@#Re$Vf!Rwa^$Q9E@=a=!Z%9Q^Yp$NF3I*xcwF-`*#@UE!YW7;bD+UENzW-# +rC6;lrWf@!JVUqcN7;%^oklmlXEE4&2hUdQ*)9cyIXg(iLCs-dooSneOGWp=DqH{=fH`x#tkW^9bmeaZ~&c}t(Jaa4C))v-pBV{TntSQ-yiBdDR0VLP{$)nn%bT6{5#K9$3N&E4) +~UmW?)$$iLh!PZ7i-s>pIB;5wc=0>uRIg-VF#s?rr=y6dTCe&ZGYOg^ty>1^@sg761S?0001RX>c!J +c4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFJo_RbaH88FLQ5WYjZAed97G&Z`(Ey{;pp^Bq(e +Lj(B2BSkTN^BCyP_x*S~|x>B~l|PyGGId_8s5!t}H304~aw`AKo4Bj?ej+oSvMLRAh|btw^ +Oer@xqy=;-Jux_)!<+ci;DSqiDiMo3c0JZI~lqJO5ID7x7)g?L;`wkCzhsvPVmWn7U`iXBr-aGG~;-A +*|Bg@Ga)DGIV@ddqm^cZ`X}^>}`%a_gRwxhf%L83VmL{6)sV2#$(v^fHA*`?)(X|qJr6F#j#srmG@FFpah-)PY>^%d}QUr;@G^*=XT6Ivu*+~9^xO*T#Pvyd4QXohNJB2_UHX +TZ-;6;S%jCtOTiokp_qzx*q+RiXjXuzbTfYA20TO@ +x5C8(Ik*3Mb8~f3&n@lubu$nxh5)4y`F$W)I6nX~gALd)QoN*B+gtS-_6>p^3jjukf^vFiDu+WbJN)5 +>f>fn37x37ENJ*uF1P4ZfUgeV^k8|XlycQf!BuaCtd>w3bn|D31aO+GGn*Yy9nPW9R)mW*lU)ss5w^W +C3S8r%1=Q~IlY%rr4XF5sd3i8d8oKShE@ZZVjy?OInTeWdMPHY?|!h8FiI5Bi!IiGbWXNzWORf3%Nj9 +gm8MO-V;-#Th^u*(byrSsjg_n?wuVn?`R-wb9$-4SF4z;W2J8i)_hCvG`!=Zd^6*$ePExJl+bW-GRj>np=zsf)1Ds8kh>7OczD2@Dt9-cfs +zn+Brs7SZA5JD7W(1vpG6z1S=rp|#ahRBaRw9es8&i*fl8lK6+9bGXTg74-Qd%?HZERa&*Yf-twJ)B^guLm${HPqz+L$4L@u +4j?071eykfQ#iC%*di>KhM>IF&9i{2cNCQW_RA6tGn%+zy%Qi;3hP17c=|)>xnO=dc501OJ#?FMPf`*=Rf|i#2lg-I?%5@IcdCOg^we-gbqzGg0wc%=P}tbErLIoazM5i&j=BdaV(=$qhsBW4~+t6wY(lOSRhAb_p0XvK`gxoTw9GJQtduboz%jRT~D1Oo +&GR0#Hi>1QY-O00;m!mS#zhU7&nW0001O0000w0001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?F +LiQkY-wUMFK}UFYhh<)b1z?CX>MtBUtcb8d1Z`23V<*S1n+r8ZdDL};9Hg|EfrEDP5OTo@#JxsVRF;T +K +M3IG7-A^-qB0001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFK}UFYhh<)b1!dlWMy +(?WM5=yV{|TXd9_+?Z`(K${+?e!G$?E@6esE3w%FjjxZQ1v3wF0D+Fo%7BQR)*wt1FBEh*XcE%v|P%# +f6*x3pQ{@*$DP;c(vg%nX%t_9Kt?h0-Nc8+NY~p+)jq#^rRz;*=Z1${jD6u5!av&fcBM9sGGQ|7!%lz +QtcJ@z*QH^MnaJis2ne;%vsQj1s +?!d!m)>gCJt{&IO%>eI~`gP)C788Fj=gRB{uXDiB;OhjHXZrG}RI}@K{QIzbCsBX1ZI$)7hS$0}|9iz +_fE542uSjMgTS)9x#DUK2Q#M4T+=ets5^f)R;0lqjpJF~tF{hPqAnWdTFfK)lxC+BXFiEJ&j0Y@33ag +HfmJ0bdW_CpRcJE6g!2}4dSGC;m}xFYYmXiMW&*?72~zVlG^Yfn#_k&?h*r#kNYhCTYns67^{* +R0^H*lo^q3=BpLx-w>bL=166}M^iG+5>>6!6ODi^QfXRh#Zt$1+a4K%sMVz*V~8B2KFV?j3=M>i%tgx +JAY||yvg^*VTpZw#fGrJ6U<}KU|T`GtoG!?h90d#=pwjd +COy0~F%`R@Jgr-;41{ny8c{e1iH2WPxQY{0wVx^lIeqUj>`4cA)(f4s +}W@*35IpKFDp(%L-g5P1lPxt08YjY+aS;q9gEy7}!>5A{!04!ZQE}0YiyMYCdZb^U6@PNZmafC;-=MS +!$H*EYzcZmSm_YYCL1#v+G7%5|c|{{_#`@I>6J3_*{q>y#!}6Q()-pM$m|DLCWXJggtL~&T4)&nD`$T +r&_799(SPeLs@DG)(`=13@l>{=Kd@n*wD{;6LC4fZCf{3xx9J6#rPO8`}?iR#lz5sc%ByQ_dm`$<2E} +?+d&h?mhpJv!V5ecSwM=&|DIrhFY|yt3_X>EGgBF{(~SLXvG|^;WGNpOr^cn{?1N25a2RrNWVnRI0Qi +*JXo$|uaVOyjZ557|6sZtfcycK9(LoP*;<2*GSN71;K@5bOHAZ5w010t7Q23Jc1?-o49>yL_QEUSgp> +b|{9s-jO#R>jE0`U>Byn5(OEw3M%*@g|caS6MU-;vDw9mi@Op<8-hYdIHCtM6P|?qva8y4QBF +oJG9J%mnujrd4j&Ec4UH}IK!TVZVzL@5CLMmk3Yo|Y!y26H(kEp-5Itxwi*l#$#bN)Px_0K$n_7=uX) +xSA?q*IAF&Yuf}kVjW%6w*VfJqjOTv0dCG2AK#` +bnKib5Bo5azlFL1&#hhI` +LXQCHqnJT#Jg(64U)6*@0>k=t5j+(oRGoE6USk_B9dj#A|aW+#E?R9$y^R +jLtV1s2?dEq^ctT3^6Xq^}t4mdtQ+1e#DMpW^28brX{F_W#Sr~Wjq_5JX+7$48O2Ji6B0Z0$gM@vE&< +=iwnv%8|W|9G3=reMea{TLB&b#st@1lKs?1%YhPS6!H-?e5U9{NMY``1s2_r0Rmr3)Ba(Dal>?0d)*e +nm=5}m^{SukjLIhC?&Fw%cfJXwlq3!HMYq#D39o^Yd*89&M7eJ3$vz{X{peVrs4viR72Y2!Dh6O9Nh@R +d&(MCI_Ch?LAevtuqB4zijH&*-rhki4Xp||F6IVwqq_%b91u}yeA9^LIKA=bFXZ?&-Svwvbl1*xGgk7 +w?aHXfegWy+NJ?%go3vPTedZyYyf>>N!sa=Obv&CLviQ#nP8MpzOa)&3Qym#TS_?24w}AF6`Q8VSs(`0=b=~Vw +z<%>zcGPP_kgzx0x#p&bSVtMg;1&`6z+}!uM;p1)*2!N%L9L7=UHZ4@5#Sv{U3qf3RvsB3}cWLd19>nUHsEaZITUAwO0c!nja*g3^(;^AP{Yp|)?@s47R~!}q3O-q@29S(hB +c(v}GEG$!LEa*)0|$5Xdk0I>#2M`oOIc73>&Gay~N`ce=L`Dk@MR0TRlji-z#-Pn-BFpG6kaj> +BA7>sWP3`7aEGSFBkcWMKW;;kw{NE~!o4Av0*>m!1zRqg +QtzQ%7zSAi64Z*yFoaU=>e6|vic{d=dNGl-KAm=;x#nll&R$crBBiDnjEs)KBQ~{#7ldBDuy@|a)&$o +dh@`fAdpxE}0GCik!B^^y-uptHF1RvZ +UD2-%x(YJ{lj{!nwm4B{FV@mmFz9e$={Q+rqIV1qu^kpv^qpWv-pYPvySPq*BW>rz +kD;a-}0_K1D1R_zCPMl@(k|gYCKkMQ!nQ{~B|K{UmBcjuq{p+236-wpZ5Q$ueFPbl>e6;HNIfVmvGME +4$!O%myPHYe)*1#R4C#+VC(4UdLa}aZEBC3~eqTabyp@4dXumE$>+0bDO`vy|0%OC?zLz1qQ^Aj|U)bG +}_x5l8IbleG!7kqm5Ztmn!3wmhCr15$5l)K#0Z>Z=1QY-O00;m!mS#zrSWQ|;9RL85bpQZ00001RX>c +!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFK}UFYhh<)b1!pgcrI{xtv&s7+qROw>#x8m(= +qj)%1fNIbCan%RcxivJ%63#H0|YiI1~w4tSOQuNZWdE?tj1C1wewIlI3_Z5drKj7K_DV@xkSAIQ*OiV +UPt}uvMJ0#}uBUJLbhcXW81#Sei$I#Sy#SW^4F4W^UxOx5MFZFnGmI<7Ar#ck7H<-iRH)e)IZ!`0oey +fk%J3n*gwQ##0eTgI553&C^XFL;z$0!PY$G%PqT0-6-S!n5|OIS-fK2+D-5Hm}N0kwPgw6vv`@gL4>T +iz+AEgasZpHfslw-*`u3s;>;By_5v3uGC%h64UaN6!x~pX2yL{oHD|+x!WfRI8lSr%&;xd{R2Q}-0*hLZ)Phhz3-cJt}#^9=)t`Q-BE4|esDO)mdn|Cn8#joI|~>-luCU{`Y +>HoLe!pG_fmc6oaK`D}LiEBgSLmsdCJe0DLr0kSt&RHY&|n=X*t#dLo936hf!v-8=_A7dc(advZwbU$ +9r*@RtB<~Os`&*zglyZ$`CzFJIyg)<<0IlKHghkB+L)5{wh>V-Tu{S6Xq@o92?j+Ftm$!BQ89JyqtSJ +!{cXTN^BVV|zf&!&+1VG7($KAcZwWze+K^U3UD%+4kklV7KVbp>>=g$O8lWM4i_F%#>Yz`xU*+0`XB= +Je|FW)8_Qv~_+{Ab*)Hreijl&lV__kMpYwY$gg8aIT09U|voo9Ta-CZvX_-pBK}DBs-f<&Vkwjk!3?Q +xIGxGQczjPS>;)ta>rr81~maRPQ)P$4@ag41C_tZBQJ~NQ0R;REKMaN24!@!IMr#fEsC;j!o^_VIBpJ +uIEC6y*sx)=*iTE9^-Dt5&yLf(pND|<0Og>g67P-u=C%DA>>;%0v*4>dBvT47TTpQ~6`Uz}811VSm_1 +Z<)Ny-o{l_to0M2YpGKg03*Vnh~`I +_qx|BPMIvDTaiY`LTSwrdla0zMNjmIzD<(q^92X_{=kpZ|yO4u6TQJ?Mj27v?l*5>enBui4&eCla7Km +8CTcc5t$)7x)Wb6vGa|N@?G)?2Qit-91^gT$ZlDShxO*u(gKfc?G){k#%w0s`2-(digEL`7rz<03F!i +>?2P!a*3XX4l03iMK>EyD4PZV`fFhV38~G7<2riAw|IfIEuA&w1@RRNZ-F1F7S6f*uk9HZURu)+sTbgLWlAx|%wQM)Fw@37Xd?cYcz3)+ +1G+F869W@msyxhapdkqdl5zOJt&u?*EzxxW-vs`-I2c)e7lJ1 +SJ{Qax%zcOhU!a?-M2%o~;A?{Us!>V#CVnV@e3V&`zyxF0##5+S2NjT($uSzy7#)*Ld4Mg$BLQqfYSf +of21N&6fJf$ENPQ|hb4M>ir-a~hNBr^RGL9;pn!~hd8AK)PBfFqdZG<_u7oMhJu&1j3w%*&Nby$h +pXysIl;*U&2amVT +t{!Cd8&pxp)q_Xe)&)moBvasM=1XE142FPZTj(=DPt$;wxq%#G4U)*~ZFQg(gY}tX4b_0gn|#0=tcOO +Q%rBDdgR!Xi;PHqx_l`+NjlKSHiBN6SW$$#62O!<%ZXnGELA5Y~e@$!9f~l)&HbawEuzMSswpQ&DPQf;dN&~`xq0p0YI3Rvb9>Ep*Iri#hM77Y# +c;_b_Brh#g)DCJ8VgbreawyAcY)VDV&(Er`K;^AG1{u`9KoU!`OvKSR`k9$S!f~VFQ(;D@@eT6EC)=> +>uP7P#D708VK6RQtKkxO^|SJiw1QKT4;q5tJCB0)S#*`_fh;9sbVxE|NcLtHgqtJZlleiG5Z@V97Cie +j0(~0>3lSO1x$;sR_gp(vif&6w1@D&#)ZWr)@U$<&RT^b4ceSTpI1{^2li`w9b?j_y5)o6WwyInZB+m +UcXf`DaNRTA)!2p$+1>iGtr}Ljb^qYo7Kbi%1HqXbWmIepX+%h62Y(*aC5khKmFU54iqvpc5aszTp?y +vd*4H>9Txb}QX>F^qWO!yHD_*NKp~_`2gkQGE=<`4X5$*(f+@e8Y_@T9RsU!>kw>e==YfgZUlyc$2lw +-E7t!kLm#8MeKfp8MnyLaz;dO({_{F_S}S(<~|2XcQC!F}D;v_?@R?Q)&|1;990d#qrA*D>wjf;7P(r +YUaUiiCSi8f`&lu|QVl@vZ%i0hb&t?Yke0#jnYrYUJ7#g?HM~Yvj7&$OYHUP)Y>FO_g4G%; +Nbw{fFa?VuDJBZ;o6PobhkDK*03(OlU@J$RFo#{MmB2Jo6LFq;%894eAUT1i$Q4E2VBi!p;7R)&s(o8 +yswIVxEFstY*rB(eownH(y5p5Z5aa +(v&S>0ZP@EVf;1-RueTyGuc5qh>|>$OAf`GT!EO3rtYItz{!VBYE +WO)LJn+67tY2_`o*LG@TY?WXrK4!BTy{L|7C7oKK7$8+wse%Wfy+xMt6LN44(=h`Orm*8xvRyNjbQ}U +^!H4ns;Q@sep(Rem8YL_u9x7=LTJvVjc1)=dV1@2t5g4kxl)I`S>7*QyWSh7@q}C&jOD$&V2Ub +FyyqY*vTq_pM#^TQT6klsFFX8T&DIwfBJ@s@ULLUs89g-(@ny`t#B^e-(xmvkY>`Pt#(){e3&h5gZ1K +Q72G9w;6s+~l+xES-HwoKQ?5jwY#n@VgY%ag=Pr_?8=mnOer(KY19$v3X^f&_-gNWeH +4j@qNJmbW_P7CU7)D0*mdkcn1X`g@KPXWYK}T2^~Bm%M>nVPJ_9N72pwBmGDg^h +X@kT4nlZ}S0(hJl0$?DsErW9e!982Uhwomc3U%txm!&2l1<5`vn7!xYT>zs==3m*9y +z5P-A8>@7?{1%zptujcK;$JUB!`7#*f95A`o}XK^k?#g@Co-GFIAiA=4k?iZ&Tg{mrUtcXnUZ?{3-c) +b~6M!H&u48c6G9GwmnRcCuZAP#AI!?<2`^t=~&hLuisR-A%HOSZ`Smmub9=v(j0qB^6_4ZX2zqO_(O0 +;kL*OH9^QkpX;LVMQxh<{o;IneOgX*icmS#-Qs;U-)E0OJ4E%#yM>8rY5P#)4&HzVZ%ZToIyu?=LKJNpu2C{+M=aEn +?-1H5h`k9!P0nkSmLtyIq&4CMLBNp&l!p>@O2pq(!&)r<{C#_1*fRlQ{AV0Q2cnwr&&3re?gMf2=p{Ah( +ZO{Wdq0I$-yh9M!dyHbH;)diR3RQ(Z3+u(+{}JHDoGa>De3k=+^o>$=VIoSiE;0?3NUIof;MV?e6~^{ +frw{e>>Z2_5bow6>p|$Iyq}Mq;?1<+Vdsdtt^;RiMm)=%Iyi0G3wNM+0oqC&cFi#@;W}2($RdrWo?ytRo7biSwS3q4w=N +TWk|6%AL0p6j*J4oP>f&UT$c+iWTdko;M>c0aYppG?-L-6l-mZb5M+KPWJ_FNSo(()@3+F5|t8@epW4 +iad8&iKj&Z=dYPCpYrL13Lm~&ACtPyp)bS4Y^KZj|*{N+W`A%`w~WIJN<OUIy(8yh)y|U)soTLWsKSn^4m2I}7mG@>?|U+fbqwemkaKiobXX0o=2F5&p~gKXtt +|e<6*}5nWV#sTj#_zRXeqRLUX69}b#<0Llxw8|BF%*x&13)_gp`=a2`87*_xnt`LY_k?#&it_V8y#5=Y-~^HUS7d$cllf0q`-sgKrM)JfIRp^ +t#;g|Xmk@IVeFfbST;1h?ChEz!HiLWivO9Sjovz|kO)cMOLP2A@A3wDR=~h^n-Aj|c_d91@z)?lDmwL +VdeoVH|8#M@Ct&|KOM-5>DUcb)UV?(>fHchlM?LuB337+LieIn%BeWvz5>6%*liQ_; +o$o$^2A!td%{X%#nnqXcMdErov<(-0v&0v4@E*RtCSOABecKv=i1YHjER?iyF}-bnP`&Pt{?(p%dM5_ +))I7E)W;yFgTsh$PMlS3FVV51XFM(>;B9WfgMAeP_uSbM&G-gNCZhTP9kdKlndM@c7-9A&r@ryE{vCMs6bQ#A<8$Es!a$s^w`z{D8k3C2AJu# +78HrDCR8#y+F+(}$}aT5^&jxUgoC%PG58L>Yx|T9RQF#(?-~6shfNj33bLj#2r?VVSfc^{0MR;@$%E& +Hp}VBFWc6cD{Tc+{cx_hfMq3Lz9k+p1iPH$-5%hy>W3OPe`pnQ|Y^35MpPxUKOd9;l4$ai +$)5KCn=8BhhXvpt&H9Eq#m13OWHZZ0T^b75&=6}+xZVyM6-UMQNiVUa|il^rOZH$znqZiTJXy1`)!f3 +4k7Z)yok|CK=rMlTRTMD<`dO39DmNW$E|%5mrx!gHBB@;?uPCfH7l%)&G@eG +Nzjgtoe43J}0Tou#Rq1W=GhMNkp7=>2g3p?BO0vo$iYl(Fi@kgY@vU4dc5TG33yR>zdK +tp^PNYB+|;>&DYSHQdq?cB3koHVc48>z;3gg|B`8?f$XN-T@uoCLn?^^cl-2D9CPn1=dC(po?R>2uP? +l{4fyNZhQ%4;y(oZ5u0VoPU;M5I3NwNbZ9`!Ms&l=aub8N?na~-JL?>NXtHXUYAI0vqzrQArj +r_k7sp<#5Q_k-_Fnw&+3o@<{6z*fFMp`3t(N&u*z!`CHN^Wu(f4o6MO)sAK^YiNZ;cKE{ +7)G=DoB>*o{Y*CMA7KZ`&wPujePz@K?hAZfI(0R +0ni!%pG_`Q8Z-QX2Mkc4U>q(yH__V{g_g>Px>{mZ*#@O|*0P0zIQ1d_>+4(76c +;LJE%Viw1s!Pl>T7U2YUpI~axz{P!)Ulx@%E~XFNcp2dt_>DML`YSEp=6AR&}{YWoa+KP}%2c<6fFr* +t+Ey{ZwR@g=E-5azKmnoXYWytV+4saH%yx#hmz?o8AdI5#p2Tfm%2u3EGgt$f{#k>N1*paAgLKUA4We +p3WM~Nq|3b&oRQ)$vqtX+A~NW0ZjX!a@wr1vP4a3W0oyjqW8!+c&(AKbcnnxu|^FPSO?+l299N!=qyy>vFT$HY1Y+D^0 +Oo0;^QTkbV`16jj6h_IJ_$v&+V50p`8n_Mvz@`((Ed^~#JQXi6YaL3eA^zhk{-r9RTXP0?RS(r*zO +Us?u5?L}zl5J)5=NIw0N5$p{*n?tY3=I;PL$Y3jK@dZ^T{6NhQ79F;Vf`|{VW27l4r9(o{PBB{Z9^_G +%H0g~9E#X)? +_Z;v6+*a&Lf5@H!aq*E+ORsdeHnT!>M++%PiTnCVkjuEou6W1P*jENUycAY89;AjQI2Z@bPY7J%xq0Y +V{-;J?KY|WE4+cgWS|L8nN7)pff3}tSiISqzZ8m~8gWI=l+qFPc#Kkd$t@vzje!r2rgqKRL7$_$k=!jsf`+`T%tEroj#6@$S2wD`G%nUG7m5a;G=Fa{={2Vu_Nct6E*XeKK;&_*qlbeX7^5`t1uVq`mBq208a+81eFXmmnepWBsHAcS3O1&%r +gO6=H8+5B**e}Tn<5;H|Zo$Me856JB_bP;k_G`9?N6uCc?u16O2;`>#X1|;{HjwZ2vN!TwhP;&SbHe{ +d$QXd0Esi5#))FpC@WT`h0yhxtT5ux$81XsOJ{9hc!Z~DwYg? +lB#bqq?WU^Lc_qpbYy1X6LdHEL*)gA;@S@8tHU*NWn5OE7QUSd>7UA&kvgz{jLW(tbR+sU!+Ua>mU!i +!1wMCCeZabI+BWbrm5uUs1KLhoL78&Z$ +gNt4gANVup#tHB;CfYLm~sSZ+(B2&ILa0iPK^5vkUIB~ZzR+{;#h%lCicp9E8)RE&*f +#V!ieJz6C*V{tiE*C-9`;{JUtAh*oG^u)Eh%P;1q9s0f!84l40%Oz^0s$Op864GpsRrC5%*rWWwSXE5 +Bl}beS6+e|D^ZgUVX`1x(I#yGq>9LoBRR)<)_2Mv-PV0oS?G6SXbX)cAOdqJe#%2raLD9CAL6GNRK!~ +WP65V9E|z>m?6aBo7Qg7BV<@jd0d>%Eyh)VMhH3RXc3Lr^&+kIDuY+wLE1saJ%7h^W`Vt84Oj6MCBnh +|r!yrZDlaPh9LnEtQLa47UwV3hd2WP6!FNSI1MaitvZ(Sm1lGS3fZ +(~g;99EDk?t!k6>DS<*?0Z4bUSn`+r>a%gEh6m}KN_3UvJRw+B_&X1v#zV1VX4(OK#WG!Y>KY=DE)6Pt0K +8y8H~ye1DvuBX=wL*t{G;q$v6-Vg>M6H;-75yKSA2+!>8k3X_s=A7d6_!Dvmux04(sBJ_L6!~%>*M#G +3xlz+D>N2~CC&H+N(JF$cmhT9lr41swoXfXNDqf +PtfWHy8>IpXjT5B{u5m|E}L~ek*WiIbMma)9mcL{l=RGbyGSm~#P=EW71SNH5gWp>;2*OxiL7U_(O +DAb4Bd7%!1oQPsgC52!4c~G~8=yy0k*O`d +fM;4oWdZ3@x254ng~_0RQEdUXhpl^2#qD4Dp@wpJ)FyE{V>UbNYfzoV%cU)X8l8^cdki9sEIvm6h$Lf +v4TCI7O^yuTxUmP73T;wk-zqLFj|Tq_P)h>@6aWAK2mm&gW=RmRXyx4i007JZ002z@003}la4%nWWo~ +3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kaA9L>VP|D?FLQHjUu|J@V`yJ!Z*z2RVQpnEUtei%X> +?y-E^v8`j=@UAFc60CeTpCUP{q=N-UKho9=xb;5VFbC29r!kC%g9T?WQVJ5H`oj%=dkg=lcfB+u?1Nk +t6Q<+nYKWG6zhPhYN|b;EA%h!5J;I&zWeu1>aO#&TwUu8Sd8Yjry7s-6j3Y(MnJf&ad0Ww|Mdc|_6kW3~H8(rFupkmyvKuG+uwwnMwcx7W=VP)h>@6aWAK2mm&gW=XBooEroN006=c002 +|~003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kaA9L>VP|D?FLQHjUu|J@V`yJ!Z* +z2RVQpnEUukV{Y-Md_ZggREX>V>WaCxm){cjUT5dGbM#mG_QJL6mkX(_doN>P9oi6#*SiVDB@q=oSLd^$JIYq5|?O65}LUKvfLH4D04`#C73MFiHcTpscGqyzM;wFW!CTad%Xj?G+vJB^;|hBRV4|(m%5OaJUm@bo>QfAshuR@!cuMu{%;{&^u}v +-@Cakh7nPc2L^Sul9v>eUCU;rf&Wyb|K0R*CWplr%dOfwMjrC+@uQ#3EO6!otbV_G5IL*Gx9%hdQyJ3KU- +>Y@Bl6tXf@mAxi3D`TN`u=11O +O>RJr$Wbg_{U1Ww3?oa%E{>OfUbd;EF$(1*wZ7o)?R!bHzz7t`USEb(a_3;P@$S+kq +*bu=zTdfi7hEwk!#wfcM@9divo!)LBc~SzEZSP|bD_y-x$#Fef-bGNS)d<4(Q|T3dn?y$PdYDVm2z`gbWGF+WL= +Y3nAkD|wpNm_3$CamH#aNPLV4!N3@y^RY^88U!z#LEZV+s?Evr!Ir#(V%_5(*iDZr!G9lVsLe0zzWUQ +UP^J*GZAfWO*;=xN###nlqAEo*L8WI(xq)77!r8tl^Uo+>o#134sEIG+nEa*tC;xwZh= +!AvD)vLb_%Hj;wxFh7q1zr%LcLb0ViBxpG3Qt~&JPpq**iVcyNg33Etl_Tash&{N~XnD?PO@;9lRJdb +m!@|uPOF<^;TIwPhy#FKn_@HSRS#_eyKvT5bO8I#*_^gkP1}Pc4t;zm&H-T@K=rrq`{!eA<*ukq~<(K +LNDCJ@%ivqVfY*ZHoIzMV^*0uAdT`c*CfJcoXCXOwT(g^uR;$(UpL)#Drj^Jgl=j1L00&%ah~uV@L{S8=qRz6ewPbN1*o}tB(T*yFd +!>oe#_h3D=LZl}q|0I2OBR%xb^5rB +=H$`MJj{F(|t+$v3kwS)EP+}I_ +)f+WIU4rgyK&~$9d&1aS$9xnik@$KgsooZrK~N5LdU6AUx~_O~s?tQPpPi&bStg?D3-e6T#S7ZliB`9 +*m@2blMZ+J1W;?#YHi?T0@>BC{)CG*$4Sjj5`&V6V98^jCS2I!s+fHv)N-@u+_fYJ19o@c5}N2$K`B4 +{R4XU?%n>B$~=zD2~QXXfSfB#7jXdCiEL|XvBX&nFH6ud+uQGyF3u65^7|qE+e&_=qV3PuD_cpOv?o% +GlqYu^U~kUqx8cyCrT*^JRT$~?pn1nhsxUR+$vJep2M;OPexYC;j}o~Mb;5(#XcKgrraKRLH&}rBe@1 +&~zY=5X6?6Q(&)%23gZ6;k8jMpsb8b1nGIA%J-6p`-Nm*fPUCAJ!_)-a-`5RD60|XQR000O8HkM{d8@ +Oljb^!nYd;?X>2cFUukY>b +YEXCaCvP~%Wm6147~d*7U;nZVB`;a2#N+VP^3YW9C9Mo5*05jiCdC#lE3e6w3OwzI*BuU42Rn?^$wsN +bz}r^p^wDs{7$GF6=8~3-`p*++xhzN=D879Qy;yCUFd>-Y+PhIh6YQuINf`7qhRBd+z#Cy8LwAuo^@T +*Fkr2L1{)RxP9QW)F=A7)8UKzbYN@?HAnegM$TDY0q(N}et&LE3By$syZr<$s%B8QWe*dIF@m)8c@!d +@Y)%|t~wiP_Q{CW6wpRy*ziy$ksVR%K39EMVsW>a@Ws56_S$~m0p9+T3v)}N-Dx)I%L|9jepKengZavF1?E%rOUcFw +Vu+}ORo$&nQO?WFbm2O7N$w|dug*VODhcf@3UEu^D8jS9I$xyz<}lJGVJ2SUx~$$jas-lL+6)YXLJ7n +P)h>@6aWAK2mm&gW=WV>WaCwziZExc?68`RAG01+f6u3%udrc1p@*%hNUW2Ad(0C6AEEX~?Q8s +UBQ6MRMeZRgle9=qn6n6m<$Kr6_pJzsuRy)Y^sL$qO5AHcHAFJU=}=+&@nE_kuST?%mNsYo+G^?_fnjD<~B=_0$6YE{p|L!_&*Zfz>4_yX6`h$!w+c& +Nx$a1#aOJlZLwoofB_3;=ehGx7_d|XB@d}nnk@4HP1Q=L3#9GGAVfl!sLajYdjFD&P%PDhL;IFN}Yx0 +5W)|p;f1I~;nZDRT)59aI3~R|u+%LFQ2|B`y*gA5L8D8G*{W8SutpiF3@@{ZQ!;OuW;=JUPshBF%$WI +VYi%RNI{S6GeE!&JUV&Qw2mcKk9+l;D_@o9I2PwYsJ_|E+4ZS%CECG`Tb~K=!@330AbgWijl~X3Ub#X +*hutneHC@#&5V(V7ID~hw5RPR^W|?!ittzgmqH9* +BGeA>s;xT(W8dMg8F4llP&LA51$35SU9>d^q@!f|Wjf#~XZ$t_Y0=>M*QpN_S +s9P0ts?_}?%HL~BrX(=ZkUwnz{`BYL|(C-kjEsA%!A=t{@sN~^A$Z4b){&6o1n5aaqT&5xnoO=_Mr4P +Aa4oje{*br6J6;Nf$Xr~eZ!2cah1!u5rH++0%sVu%?TUyj5*pc422L?dQCnKO6Hm1CS4m~o+;A6DT4? +HO*0G1B41=LPal8FUzUF??tUK>f>mC?9vh^VMk|XWs9-fZj{w9ohTfpPep&Quiz`ojb~2QMP_XPjk~5 +~#$*akQFu{YpC<%@Pj?nFr@3{1#7%B6vd&p*tB%rYA|xLJktc(sPrWWcn!2Y(K;weC&b8A3t^4Z;q50w>_SB+bxetdiHPxYg9>=& +T7<5Ao1X_7xiC +KhckKnC|BG$!1k@+JpR7^+K_RTV`_6>~9>y^=Ui%q8U +~kxrQQTF;3tmCq1q<< +X8rNR2~6W24)^YqplOU@X-@QAwNA4qvFcHP|m0lniXA*ZCMmgYS7}es#4$Kif63%kIi-*?-mHs?`!V_ +aCpCR?4fJ_wUbKTDKd6>pw-EDZRN8#@6aWAK2mm&gW=YJ!ygu3j002-3001=r003} +la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kb#!TLFLGsZb!BsOE^v9JR$WiqFcf{yuej +<@2pn%E?G+ose>Zm36MXSM?r#DB+jQs;vfrmZh+>~qgO_cJX7uOLZ^Ml}MH1ZY)rp@ +5{4myN=tefA0iONqpz!wn=oIz*Q79KH57ifWSGkZY8Yr1uWxd7l=Gv+q~Q*~Q}9=ktp%a18$S1FeG`i +;^hxJ)HWEdmT{6`kcrg8F%`{6$qgI_sE%^O9 +d2yUmNzxLNjAX0U=RCG-v)RmkU#@gGS)(KrT!40of+(#71paAID(Iv~o`uIX5u}1Xj@W5CFJQU65)Ce +wI<7pI;AfmM%oOD;wkDx9@jK2jDIqB2C6`X^#0gjJ|a7lt5rDQ0g1=pjMVigcb{H-oPDUIx +N{_D^2f=XZ2dGI13w5mNfmae-ItbMjrc`4|2v!Z6eVil$L8eF;by6k@Aj&_iU9n+AIx1(;6LrwFkK)<$k1PVA8zgq@n{;JM%$oc)w}Gmy`aVJ!PIwDQYIB)8BT= ++ro8ibw7E>>-2s+w*qbSz5KJ&;d+Il;2tWFB=Xm!naPGH^`QM9}^1 +mWw$2REmINSlP0=EZR5`p@k1KU`5&rnMP1QY-O00;m!mS#z9=K&m@0{{SZ2mk;!0001RX>c!Jc4cm4Z +*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFLiWjY%g+Ub8v5Nb7d}Yd6iX7Z{s!;y!%%?BnMl7BP@`c +fS?GrF0zMhgCZ?@Q)ubQ;)W)*BxT1a`rkVwC0n-B1?r1Tk@G(0%}|XsTPn+@_r2w^B)RR3^(5BLsNQp +#*0UxY%kxfDZ(_qPck(^onjO0l(0bpMm6EIhc5$iXdNu<2z2eSGqmO_m7B$;vVV%^Qm9@ssX0w_blCE +q*DC4+ZnDw`;m=S(AH#hP5x#jB3(Y|HhvL!(qxnoU@RD7r88xtU0d4!=9BcDZF(FrTIVK>DKzn7M;f! +tlFvg*9M^W%$B9>jRJfuNGEn|j3kiTg}-5U!rgW>0cZ}G +T4SL=W%2DiAt$BwOR22mCM(DCWi>tMS)OzJC2hgV<6h>>GQy;V4IKXGJ!ZN<}!zMRS*8Wa|$LD%(#L2 +h9ujAbvuWh0~_2f=BNCLz&1$7z$)k(<3W2>2#-J@6y8VaoX!$k0|ms5P(q%_im+PKG(vHS`Q!q0378s +Zo&xLWeM-cATmjBj_9xlCOYB<%#t=p@b{;G@_7zpZG~SPgG75G#8GcqmRNx@ +IVj~J_)EYDr?Te5-h3Gylg0Bm1??V`5%q_d$^H=+fxS)&EoEmFB8>sXqntd_8`0Po?lhCz-Z36szFQZ!Y?4@D_&D;{zM-rQnOs%AN2$N|j3Zs5SLZF +K_w5(EaS{b>0JJ7g^Yz2ZHCbe*sWS0|XQR000O8HkM{d6p$E-84Umcs3`ydGXMYpaA|NaUv_0~WN&gW +a%FLKWpi|MFK}UFYhh<)b1!vrY;0*_GcR>?X>2cYWpr|RE^v9ZT5XTpxDo!ozk*0`u(b6m-lT`N#<}S +xaW0D{x537TD{#2Vv`l-|$f8S0@w$ujw|8dvB2tpm=5RHFjVzMGnP*-&GxSEu9ZS}-Q1l0@8RVqfR7tSph}jKSxnEK8Bq3s@?fdajgIV;XqJ?{7t|j^ +3;HO4c%yh4<=K@O6Lft*G{}lQ6Gh%fy~%ANf`|7OMRI?CcC!Wi!igvK94PcoZs1(~|E%>KNu^1+OYb3 +`KJF58ybS(pHZiJ<_jPCd*B}Z4^f-lQSBf^X!f(8s>E^cKezg@}gjw61*0Svr-()a!nP6>pRx$*D$!&iUdm!R)vNHM%*vS +&G1FR^eLIFBzMehB|JS*qcd=V`SJ!)3^B$ZH<(TsMkz{iBWE5)-Zxq`LbzxSp=x~<~NaXbulUh!1{Sg +($350(Ok#Fop~yr{%-`P*?p1Pupd+m$va;NYP6eh&=fC7Y75PM7~~R8i!sXP)mRfmbbAQx>AC&U_Q#s +ugF9LrWE&ka2!yMSZ@U(SrIe*lgv?L;HEi5105 +#{Dfff&O|)SB{C@CRBqw8GdQelZ%QZ6WwU+?5hms +T`v?kjBM&6_VO3nSsswJAFOcXt&xPj(gFE3uER0R(L)JxX?rcL=Pi_4?<-y;+tBi0HOmAF*4wQjpA1? +>gee^egu5LH7YRd3$fXN=6;2({a5L=ISn9ShX@6T>7esn!rtb)y!Ef1SLh{lAFi7DZlpP~(okOaq63!br +2$c<2QTjAMnS&ujFU>P|MrddN#(9PNQR#)-0|RKpmprd1iwL;J)a3l>GrCc%{*9e4?uR*e=K?SNVihn +ls>*iXLvo}i3qUMD!{jCd`C%Vm2Sm20!oIEC*Gc70c{q0%m~vXq?|o^#7fi +$AxfJxS6=9=1Xvr$qmGVFw3C2`A1?*eC!Y|q-3}ZI&_kL>j00{pu?=Md`_ +&I8i${UkonK-oJCLB-&yp~<~Ef2*bL`0yI_|#fh3D2W-#T@nhkM6j3>z@0uD$_H%*yMmkF`6^jLG$Fx +U8bl1!jpm?Tf>@9*Jnk|e)4JPjw9uK$}%h;oKR1y|sjyu=)tLVr(4s0h65g~auvv6i816KoQo$9f8p@BF&6IZ+1Bu+XQun;mK69_R$=*^fhp8`g +8;8>=Xv$-l1@cWa!{C;I4o0FH|GOUDMKU`vggYF{#8W@M6q`hcpqWM_95T?rpm_?1DLI`HW +M{sy`RNv&quRl68~bJ&u<91f*d!e2N)Iz={aKe2H{44HX+l>4FtPUvm_#Fu!?M-3AqIn#-Q5gtq+yrVBF{Y{No{Rl}IrUNw4# +)jsg{GM{6xDG*at)zPTAEbSCC`Vxa7hQqLO)wHL1Gx#gg(gljr3I-v6LmrZy!toReFjC&7hK3viB^g- +>nYvPXb65UgbK(Bt+56={=SxE13bbhX9n_&DG>Lh89ot0oO6@qOYWkuy$Q=Sra05eGeMMBS#uwD8B;5 +=}(t}ZgU+w(eKDg2@R%z^_IpeRFz)ZBg4?An)4)*F2h}b2%HVCX7OQ3(J$fli$l|a>uwakyLDVn-SJ5MUpus_@hDV_WR#1}m +k2km>KoQ{VsxH@v;A^5*ZNTSFLd}^QcIm;bC`06%h#G>Wa1*pxdNfR90dO24|Y1XnuM9RbocHo4D}0 +F7|}Z&FQaTv4d2Yx9-7@>Dg)QoLj|Gc +jq)KGuq7VkqaiwdMQpg|FjI*mf)lA%bfG(|WKhPN_?1S{9lZbqX{;rhO8|ydgB(jza72Q#_izje0kVZ +VC1{?QQ$A%jw)*5fYBTuz6ylH1dJG>qgmR!G&M1j=~S6Yp(riyEhQ;ObiEyX)+94o2DrItFWmS5}`ui +m%5j=TpGNFBb5Dd;vLBOK_ly9L$N_g0^+wM+eU*sdeCD#ZX!tM30s*Z|HV>)RZ4fc_>FgR<5mwA|$ +allqF~cyGk<0u=cL!!64AJ;tcmMex&1P`498k>zC>L_V(tskL-}v +OpCqmE`u9OVXthU5%z^1SlIsRbiRh$M7^d@_eC5;N5^C +mWQ5(01$k|7MG{daLwS&KTTCPZNFxH;zrFGr5Z7M%qLUkJ1VortjlQWy@l^L9h`eJm?xk>U$ZzW_u~( ++8?+Id7M5706;Mia4eU7vi9@>NPb9)2u;2%}+e$=yv5vk_E9b2D04Lt@6aWAK2mm&gW=TT;VJ?af0 +03q!001%o003}la4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kb#!TLFLQHjUoLQY&01@7 +A~~}C&acqe5esaW%iU%kd%5el;ic(qN3!OM+6{eZT{`NhYlB!ftv}a@QhubkRrV1& +QN@bornPQP=D={7~HpM1a}pQ%`(wbKWsJsE)r%b-|_!1zWd&Zi(~a=rq+edQsc*tMxTaxp5>9aPK}yD`};%|i! +5LLX!VN3==SPsOm#ch_V*2k;S7$focK_*7EX1S8s_*^aICMm|V`snM?`2MH6` +{6AFl~Y=$;zq8GD3(ejDt#)JB3lS4=K4vQLKGQ3uQO;eO%(50EH>$kwj)vC1zkfq%V=K3j+%zJ1%bmg1-HzwJAVMXlekODHc$b3^*C))Gf+C6A|a_DuHc$Vg1PeV%=Ca>9Q +HcBm+}nN!5jKGZ)pGV%M;sbIM>#lG}P#Vwxth@JZ>s}1%%RW!BOt(7oEem>n5%EUbMLBZ8W#n2by(cSDcZGooTnrBj5-ki9}8c|E$*?Qb6Xp++iqoUO +r*GH9{cv*GrLz{}s7giqtJvycBO?-$vU)ohMbuqR2ZG3Xy2nzi&t7LdX7n{mi;pxyW~YAx_03El8UrK +U~0L5deneyZA6Bv4)@k!h?Um&E?5!JI%k59Sd +R$5+CFiE!~B6CCrascDM$4?_M(`$ID>9p=;Mop)Ioqn~nc?-#8P+*-%Ad3H6v|I3RXKuQ1N#u@n)ZbS?sK(Jx!bES8;zhw{K^8cP +G785zJQ)&C?tnDnKD+}L^k +#o#Z4Bl8(ej5E6xwgIyA-Va9tPP~vwLIEbWOFaX=8Seno4T31iwsy)~8%gMW`}xx+Avb`f6t-m-h{Vn +N@5Ig3!0=Mt55zdP`zJ$@^9Z={K> +twuRdP?^<%$n<@rbcf;QUse;-CyUcCFre|a>0;6dL=+NBrvjpC<&=khpzbZC +9N2f_v7@&6wKn!qSK4IBFkTeXp9pVjY7Juax&*%ywt^b+%YOyM3m@@Y?dWsHzi0rtTP71ehie|A6^@L +Dn6SMp~QE24s% +CQT{xfjj0QrsH3x=)$Xg`SBK2s*UllyQY(QPHWZ1fJj*ZgkWh_up#;f-keKtsggT)P6k&%Hehs-n|o_OKrR^q_72RKcQJi9G=BR^6vW^I)VFBu9Zafhyj@hF +a86rW}+J~XgGvTmbto}#%8$3W{jxWqi0nOJA%Dm^EsF~zxO56tcw1f6PE^{!o7bjKApR2fGK ++7llPN3D+R6^)+Wi{*9j@B;km*O3klQfSfm=D$Js*)e&ecE4u|b|{7>>NdTdQ)|=cDkgYz`BWeK+ +di@#N3~a&OZ>x|L)^0!XDyyxBs-~>At*%RkAJl1RX;<8kbZUf@Bf|Et95LL0c4F1V*y`MIRZ2-I&?ab +2;S_s7>IlrGTD;`8iXTl@vm$bg>0EqT)zC+2ELZ$R1z3Y>7?FBzH#j_s!&$+4)#ML>5}0f +Xh8_g`Qhh-QuHlCa7*oXsQ4Txi2D(jwLRrGp-tW;8<3QeJ_!M)v&Qzz}Z%3lt?#8GuRNk=%=c;|zXu0 +HeMrcVMMBO7wAoxCP62(tArbYwH^~Eo5e{07U>uL%*dT=U!R5 +snIbcU$xbYV!~BNavKUGL(*#Wu^~1l0Z7T`-`pd%bwybYpvnmsQU&TrBpo-J%Q&Wgo`xm;JFD+xHze) +Y+u5*U|~(M2FgRj~Xzv8MX1|yau~;EQVhYdBmtrV7ik?JmIU8U*7$8(vbb#zXtn8zKt3x+3osh%oS&) +aS4ze_$(BWB^C2Q_+UrcNJBtxR#fEMG>Ff+o|Qem$d$#;{i&%#G$vy?G(EtHlGvQD6yRlUvpGjIibUY +^CUI@N_qKB3oZN?kvOlTS7ZW?|+M|T@F{zndKnbWxYLHH}09P`Z?Io7&NpJu>+vvyYyvD@oLG%o9E#! +0xTEaQouGtx7OxI|`7B6>V@-Y0{=j(^z`w3*40x6r;ny|X%SEb6jXoCPLO`S_IA+9xnFXYuGw#x0mZz +mxZu(KPn_O~wWH&PveIIlB5+zF +X!h;7(rS!yYO`gtzVZ8($84si(8Y#}_Q@n@*iRee}9;Hy>G@ +YR(vK-PKLbt@YRP!46Lt6;YpuIRgNE(g-Ty});P&7)I=Tu+rNYq!)-OCl)cGTb|#X2r6U#b&XGO)f(1 +dQLhrN!)$ILfoxYO4Y3^IBEp948CfEKQ0yLBJ2fUY;yeX% +=uZLNRyU&q{bt3cJ7l*f}GX16(TNlCyeUCP0r12N|oWDST>yk_IbjG;y6gdnOWyaKKAqMJUKAT9-0kE +j9^%Gnd4ZvyC|r{_ACUPq?>Ek4goc@(W*gAufSKE92Kn;Sax4a4!(-AisuZ@Fmv(6N88Ao1s90mQ)H8 +jQQAj7r%WI$mwX%L?uppZ~v=%eD(06H1wW080me_pNJ<2ZYW4XQ}Y5fDqYgQdi@e~5&YU=YuGn0vC+L +7ux?%9`i(=Ki8U%+zshJkqEzdEe_i!n96AKbRwO1u+-#fHFfjrK&yvlYf@%>KdgLfFDO8?f+=~i?d98 +qSqpZ9>)HVZ+)v4I5!WG>?G-40$~9;I!*M* +{h8oe8>2MSIm+)3dgmqgs_@M!vFs-KUXww<9muE&(|k`t6YDbLWIpO-L{Is6}0cTJ}xpmlAxl?5|cLU +R(LLKzZ)IgsoEZK7Db!s^ni0uAHr?k=^I})BdDN8WZ0GBeIwhL~|oPdjWz%33@>^r4)v;(z3mIeecZ_ +@Rc-s6?D=(25gn%tF+5RyS{@bGM0JR@GZqu_fZwg2IRQI3iH>&osZt*MwJtUTKWsH9mkl|>-EwufRERI#Z<+!!vOcU>c5qjnXpCUsgyr5*i-h1J<9unP+FBU{qGO%xK~G>^E*1@k?@y!^$ +NS*_Y3N1$lLXLc7PEd;2XDD@gdu!bGxi93sBc^m}1D?h`$H~SWZm8!6P>&vi>3ya*j<3Pvh|6Okv@Je +vC;xBG=PRq4sy{r2n4X_TnC+z$K>xcZ~P%>kn`0 +y$ttrv}2p|tcrQKEivbW#QTj8zwlu`-Oqn}&(5EZT$Hx2Qt|Qe@qWZr7nOZPHKz*cfY3VP9~jX&QgY~ +wHnwQEr8H1=h1=KZ+;NaD4z^IKXOr}!v;CV^LP+j#_)Eb!6vg0LU7gko9U`jaXeiD>b+Viwk=F&JGe*sWS0|XQR00 +0O8HkM{dZ??X +>2caX>Db1b#yLpdDU8NliRit{;pqvxf{<(GYan-*GT~*0f=Eb0O%VzJo~(Z8Z}0Bn +g@8z%&uKf;-WN+EuvqLq`|Jz7)@sKVi*;u^EfxzVcYCER<13?@&WeTmKDlIfTfu6v=3Qf%QPoFbnUy= +CIy+~b5j9&K+1A>9BUj8SCfiz8+zMv5+_F}M#q7WhNHcp;$+dLbEQkgXda_1kyl}6`;`N)ie}4XE@$% +L8&p*7mTipHdW(W5TR +>K)8@TY($>OCq%`H=_zl+LFXOqbU?8T~1YdCI!0;jWb!r<@X;)4GDtFT&%dqG0|LOQtsb4$b4U0dOO7 +<}HLS!#wl$(D7kgq6a;H8w>iQw#89>!i3dL6NHA#sq6jorb+G;Q^~uyOx_yb3C+|&~yLHu!^^AMHm3n +)eP*yBOumF!?(RsO*8h(n)3Sgo8o2`Hz0ms^*fOBBX9Xe=&6@+>;LW7YGL- +^X#wkTTcO1-9oS=f_4?J_)tp`7kLC5X_{4YnMiiCWU0=40$8H8Gg +sR&C<*Ln)BzuB)7pJzqy&s&e&NRzG@uijIiiv#+$||!!_RtE3`rEE|)*4RxFpPcCA{Rw>~cS=Esl!mQ +DLB^+zJ&P+UoRf{K?LBWG)`7vpVBS_P31#x2|rRQw~YOP@t?2MI<2dl@7oMeA@0YsA{3O +BslRp~c^$BnU(dKO}&avReRj*bz*L3UYTJ#Jh+(@g{45_w(*@T5 +y7#r_zjed|HI-N3JQ3p}Uv=DKp9uh+5>*T1`Yy83PX><>@BdG`D3H*$3yrCc`8o<952a#2KaXkB+31R +#X21PTRm7Euc{-Oz9*^ImYtqx^>``y%J9ggpq+;weT{ot5_@33-Sq1$4+=;#_+mdm@Oz<6PYPGxN>^e +obRG#HVv+l<16u`(vPwJ7=j$~Ez*YpZ$i0c4@#O{@(&hOm4g~z=?(SXm +T*4dQ!$wcpbM}r*a%I@dpWfqQ)gVXK3aA(~gyKaUBZs27BU?prs&!6u=3{T+i;fo|_DpX>Hwl@R?jhT +%>FOSVTe;b?7ww_wYo9c8bQtqgsIBPH+QNai3FsAe{}K%rr6RJ^58Y=dDWzeL(ekqxB#3y;Ij4GWefJ89i&$ko +FKD&+inh_xsE|^DX3I%_Y_DqT*20CW`g$;SL$bB}dRjYLK`(T6Cq`5$ofmc9m`$Zw~xuGPbC=frKvCF +>x?s!IC?)pKyY~r5d6`t}XHwkd|s|P@WI6KN#rio3OxzEE!VE4Fx0SbU0LX0IJl0w9@jAz10k!36|f< +7Wy7avca+`fY$7&I?Xl;mP)s(LqEZ7AfAJGzD6?Sjy|F*4_Lod4WJ_{66QqAPrOpiroMVYKv(9N!ta5;kkxv;;9^(Nu@t@P3E)LJ`q{pz8{v +DiZEY~(szt05DLI8MgpybXzqOYEqSgAkJ-bDDpS@MaVU9l%@8n+RQAP+fl#bVJyE?z9=xee!uJ?6;`e +fRMlb%>C|x2o>-9NN2qC?s^u86J~pkA38et*Ab_9Kief*FrR|I;0E3NMaICzN8_MCDk$+1`+Q;iPJrJ +zT1MIh$@rq{i%tFNKKjXXnKJ)E78~ySxw-q0Qlb+XhKb27?jRO?${vJB@kdW{0Jmsu*~!7Y$Os8-6fT +RtZUfM_%n?qN+cFi9}9{=ooy&8TzAnI7Qmg-W_OU-jkn!SXjysFHK0BEqGkUOS{13I;%5-#7Q_A!g=H +q#gAyEHj7I#a6e^uS#rVU>&e0Pb=k&y=kNGmX{ghVq(dH&TYG +fI=>QULAAlOGt7^izfqDXkyT9Zkl3{4a0Jkk2riXn9k;Y*izk3XQ5sVMWScPiWEj(De2bb(rdl +!t1nki5aGx3ag=&5>n<&)edD)W`d^mIq{hI%JsjX5ZPUT$FjIH|j)BMR7I(P8NZ4@Npv9^vR6p)Eedi +YCMA8pNrG?3JJg7Wxrj&6#rtXpgB+NGZ`lz3y1&l$}*oxDFA%j(=00bvV&@0*l$^Q;b6*MhYqIYp31+ +5zxA7`RC=A@7kyxPWcwiTjAAgrNm+zzA#6euQI>X&FQ<^k*-Bz98=DB`gsx`w0nam<`ex1yCFyvnb#` +6c@sb{*}N#lRu)MJ>dh&gokp?%M+180FFL!}a9wOX|nY6vA`n#>sKKfM*&vE{~8)rdyZbUmF^Kda>Z~ +Se(O5K*>pcM^H+NymKt*%E&RsGad|fa*@W?j_Ppn0BRZcD0Y6WF+rwiowg85|bm +eTTx1W4X3WJG_`XeB5p-JBR<2@tU+TO&z3)9^}4UWkOam`h=HDcc5<4a68_vwnd0JeeM0`S=oA1WdwS +n(MEr44`&T$)E_@w$ng$D^;d^wQk!|H)L(xkH#Y)U_-8f7L4zUeGjy!B>8 +slF^rBm&EE{cCtL&TREY_E*O!LtJdH8CL{_s3*uciQ4aCRS6Fm(yW|eCPEaA110{Bh +F_E0MEXzSvFoq#FGZ=?X8p4@-G7z4?4^JIDpdTL7QuR6wYTBK2gEs*EkdUOf_1s%+6M=10$t#g=Rp&sihz3zflVHS9q-YsZQph3_vFP +7f?$B1QY-O00;m!mS#z3nQJx=2mk>0761S-0001RX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQ +kY-wUMFLiWjY%g_kY%XwlrC4o`+cpyZ?q5Ny5lBWHdD8$z&gf=0O_N@MpxDbL=!eC^OG}hZgc4Pf+Ku +nm-^`GbD8IxlDqzsljLD<-Q(8^`$CYSlWi^3RhJ$#Sif$eq-+?dWP=iNdvw5) +)68W#U^dni0`QopW5c<;IHl#%ME{Oj@H>+&N>}6}wApz7>^7<}Bf@+v4w5TZg|WfquDP|Faclhc~6+n +@ZF!xd&;v;?}Y+Mx}#AX#&qc*=w53mJo#|SXoI>-un#G<#M(0qtxovXIMZP6|4A;wr(w$_{MXmc9a(uk{huI?~zQ_P3s)+INi +%R)H7%6)-mZiGg0WDtppr{Vq$AA`qPJZEEU-%BiOXPII^9ywc_;$ssEP*H`u>kb(EISba^Ua8ru;m; +pAwtAN`FxHkSrSS*lO8ziq5BN~sA~e#S!`AVHhWl(nEP!$%Rfc_j{FF+t9T#*@1SSz0b-1$L_a}d+d$ +J?mC{(3LW?hil9kf@aTS3Wy +~gE;A_lp0(q8`XYF}FX8vba`^XC0G2VA!>y3~Rj6{efIt=7WyfwviOfZv7SipF2X%|;wjjW)HC^-31s +08LO^zeJ?*BFZZujzLH?eG;?HN?8|aF)Ac{^%J`sXL7D_9B;*Fyy>ifJwuJyZas5&F%~h{4F3<_bfy< +x!*S`|(#X87G=}JV5#9RTGO*o4df#;-p0k%rSm;%UiW(Xs{GF(z76U@r@+G`~!~_4GUfXPG%Z2+tD-uN%27nRd`^5iRlsYqwwt>Mh0{;6a*aSa3VRJr=hm}tW)V?`O +uBj58tn&zcmkFFAqniuBFpSDH(W@!xK{yuC4{tFx0O(tLFF-k +oc3({I3vKV&5=%=muK-Rw_KgKtkub5YW>tgNe;39>!AZ3MJQx?GHe6oD_k)YV&OnV&OQiWGNvVu()+= +VEh+_hh7?Xd0p!rA*SbeTNDx}W3JS0?$x6VfxU?PPXvVql(LXqyJ+NqJkyPn6<0wJbcJ`fJGa$!))y( +JCs;dFG=>R+#aoL +c`?=f$h+2cJ5GGwACow01=7s5R01yJSI44*yM)`&qv;#1ZeyCjkH@sx{@H7>`0BqF#&txUlLRMYsBx- +5f@2%06=N9$ys#@&QswKxlLrA+f9Xw0>|NVrxQhZ$_d0?e_7$yc&+af&B1fJ;lLjgYCs@#EQ3c;)L_A*uZ3#jp&0 +;B+aBPCX!&?E0jz4yj^E*O8=uMtBUtcb8dF@*L +Zrer@|6fnB7o(trN{o|SdoB?hupOl_>Nr8GG?p`iWax?ouE6_QBe&dkov{N`gv*&|UFC;TcPg`6Ms?%liB>k)XZ*^F_$B-DfV&P$VAE)qfD4<#=*a*=V8ELSO8GA^ +l1;A=J~a>2;-r)S5PKYdTeMjR26@|fna67qN<-{)>H9326K@N$x?|NU5;WHIX_~aE^(iPfRFu(Wm@0ZVBT!a_L&&LxG{fj!Smxye1aPZA +{qk~c61@3oms3~qoOB#(LFk1?yL7LikLj}(gE;F&P1aLsg?dm$=akdttgTMV1*P|7F__fzNJwAOlMrG +i0FJ^N>MU*6Anyp#h7cz$<4gw`22XkNMlnZdelJqm4ZU*Fda(Z?~QYOL5g2;?0MiNnU-|^@l2tKgDip +97{NB^{lSkas=iQWJxIeD!eW*+&PDrewTE`We=wrH+HiJ(|Hv1WXJtSa;06quPi;T0WHA}&-dA8=(91VBAfHbJ~Tp4&nz(^)mG=c>9`s@A +u{qKhQ{n)&pns+E|P-NBThx=MzwFLx$3p2f~+M(~gm2dgm`P-a$0}TqSN5G&9mk*XSURI0AT(5)U@I; +jr43zMpdRBV=kf?f~1R-lFr=)1fvYS8@K%s&pmyZB*31_ia5vdHP3hr%)B%vW8Zcz>sKF>-Pa5<|BSg +G0?nj^c#wA6P!6peXsh4>>n6fCf#t}qwsvf4k!Dn^B +vsVP>~C=W9Wc})$~dchreit;%|rXFZ$E@t9(INKafBg9Sfc8V8|xbT2z?jdCa5e`a97+QFE!BJQoOe_ +TT+@pyA+Us-9}KL;9pP|8dTw*D-)0NJj-{ANPy#l3MysZHp&qCp3?T-pcM}-hF&u|jKkaJ{&bwEBNFF +0eebn7N4=2<$XB^XzG`bT*a8P-+6rXauoVDa0kolyk$4LzD|WS~D6qZ@^7``W=s?$T6&Vp28X}?Ws#I +lBh^d&3?R}r1!IN1bSrDiYtjhZ-g@z%CXsXkMxp7qLcL;E@K`93ND$u+DIo)>{D{)w|P=I5cCbJTJ?@ +idA;@cUBucHuOc#R3>1qT!w;+$P!(aEO`ps64PB@-EjeZkVX&ONp8uDp)~zR6t5KDC8*ZgEbpH_F*6H +ygEq>pd>7BVUOl1W&miUR?rZJ>}rab!1XzyVA$lV?%kC*fnBp!cLz`=xl-apn^Yk7bDePgs|}7+w*Z_ +?ZLMxgJr#X(q5ghvNtgeOTt$LRNy&HQ|#W#%r+zpV?`W#V1N{gs@KSDPZU4;8mQC8)xe}NB^-N$*+yC +lcfGaiPW{5Ryl2r`MwnE+KV}ErT_|;?B+j5whMOaUgmr@_IC=5huVr6#a&X>erQ$|?2VxGORt~%it6z +{->*=VL%pJp!>9h|Gta6*>7)+V>jJp_A$?TRMIE_BzPsh- +*Je+kgTERgSj>cFVJL}-C(fWE1{zDo#Lq<2uX7(khMSa-rhca3V+8P71PGQ+3wB5;N9JV#wcv7pp%^i +jX|T66ZqRD46~IL^vDQuT3)kc3~Me@)&s_VhgybBJ_z7QHgk`H?vA-<%Yfs5(P#aBvqe4SHUivwzO#` +XxIxlzQ5hu0gE-*}zqF3rds(FEz0r(fE!4vDE>F6ZL5&t?I@>wtv{O%82y{Auq%}`+fp;A)iY4swa{= +EN&x)%B)(8yndw#rn?E&;LTVldp<8$OScGs7nMASg^XC>Sf+x +3~kUA3^Xg+8<+7f{`|!`h6Y&e+vCA!m9?1#GBXXFSSv6P@Z7DsR`uGS(FD7 +2}|)%#b^DVlFHfZ1kC3TGf)XTiGwEYuB0bX}j?4v{kbhQb%2779D$=gr#w(@$Ah9g2WJMKf#r$xaLCL +km~Mf-3Qd-VVOMiyRKrUp}?cKodm)S*w=*B$N-{9lhmgqW>RUja4)3zGetS`u`hM +n7I_DW-mJDT%Nf1aUan1R_5fa}JG))bLQU+jaO1esCOI=4Zl}5Csb`)C={(^yJ-o~dXTI`V&iRQmZn0 +$Nu{Be}9l~mYoI?2p{m#b^|Hdl$@xy;ioz${A>twS&wt~mu_=C1TqGg1RCgDr2JKFs9WU +hPCYWP*=aMMNAS}z9>?bNED4{B-n6STo^2n&P5FAfX)L&#@Eg&v)C)WYTvt-`-pRQT`g6aVa??hKGm4 +bgUQ-9I;M@TKNs;b+eaDiK;Y#G(4oSe+I4BP1-wPLkWWrlTT)Y(Q$yT=>4yp5l*l6lF1MX|hM +#AL&qsV6Y@&zP^t@s|)oZ!RageF2WzHO1w288!48c5)1inxW$^U;_;irAvtiQ|B}q?0rr}_EQR7hU0u +dks1G?NX#VHb{edQ2Gu?6j!B^3BvPBz)6W@?lZZ<5qY=-@GRvKd9lZe%Vv?`_Wb_;_cr)8-VqP*HseV +ia_u{BMb)Z?R9-aT=!HpnoH4CL0wA`F(Nu2JeenL|c3|-%~`=Hv@HnKHze{JR|mT2cen$d0hZzhHyW! +$il$K;V3AL1djpDdINR%0q@9o#h>RuNg(xnTw;TGffLyVV;ZxLaHfy0;{j4qtVR1Cy!}Sx>lWX5d~bs +xwtGo1SmRUQ3<3-QKQ`w!PS`K6dtpf23|t$?|>ke`tcBF->&S*4A9qJsETee?R%?j%i*;CEw|8(FmU{ +)4&cuvrmT*v%PS=1O6{iO9KQH0000805+CpNyn`SivZe-t=RuY1O{J36zvD}lpW;d-ahiUzz0710S8~@ZeLCK(em;LbJiPq+<@?Jk +`-T0}nz6WKs&-9sQU6@3Hy$oFt+@U3sbhM%{y_{z02BH?M%Y4aPtBDMO3oApp|bnF8G$H-(p2VY9k|T +V$VDyWVd$;7(`y?f8#V>1f{Ue?2C>2s(1G4kU^Lgp4%~=!7<4oNrVf!Y5`-bNfkVJuGT<%>xJx_ZqJX +cbL9B2DbZr55Q53#IK##cqy +yfA>1sUSDw~_zX#l+*)GkvRJ(L-b_S%D)Sy{s4!OVD;%s|kaV`DVe#tx)2(}QslZ +((qBus_4&@|5#n8QN?#5Bo;sOL8j^pqc@;xz?>EK$)E4ddFBR+()_g={OP~*Sr}A)g;(dj}uHUjZGW@ +(Q}#tqq$ypApPVbGP5tFJR&dvnXy*S0H%2rt(|F5UvL^kZ4&`%5;8miN}(l=0Zd_FNg)J-Nw53N%&@T +o=@j;0dC4Mqi9k3Bu-~pBy{|)D6bHF2f}TUc6SL<(D5F7PXXpj%miI!|F~gb*ogJ*pu3x;4Ez?$?AjO=5726t<2{;09}Q^>jT^A +%sVk-Jv~qkGTp9xaArlFYZwNjhX}?h#Dzih{M$=D4GND3k_Wc?@n=|vMMhRdK?B}$JGMLL5f4#DDKK@ +5ijynoQx@GWKWp|V~6al3>vs?RAbBnHPw6C}w>mE3ohGwjqw<8~%z;doHxK(-fwQu789y>dz +~iMF5^Ge8gq2-*Mv3=nn$dNj^T6rR{b@?ppN=*YJFJ +#Q`>G~u6{79fXgLSPN=MO=Y~dl?EL%I&XqhQAMFnU_Vf5|jrQ}4#kfLk48{xy2m=DzfB+Z(XABhDf_P-2 +p&?;FNE;9W1K=AnjW(Sa9Nj{(0bhs7#g;__o+@kHf*T-#V^<=cPf^Th9w`Sa^T3=>(+ +#5)pwA1P{$er$OKWm`QZU8Hl+~Tsfu1Tt$RS7j=<$@qL!_cddv+mvnIlZq=SRjBa8L;fG_Hl!h)HNit +3-GLe#6%0RCCN~i%^?JQ~`e?Q-$?i*angsz;z0MwS2vveGTYxCGhHBuLilSx?~)L +Zqg%y72CsFB`Zlgj8AXYa86KwK-}K%I??W^fR(aQB1474N#oh`Vx1Bj(!F9??s5laOOEKy@8@{!(ZyA +%ePZRQ?C3Z!OFxy9pihLK<(MBveL8)Y!yzqsE}M6>5DO4?zt@m;%r}Icvi`6wI!=jbIHmYX<8s8Yi27 +eh~f^oalqtz))as;uK&ht!==r{8Gw-@8nzkG}&p-Cqw-7@bAO_P)h>@6aWAK2mm&gW=T+gF&{(%000> +U001Na003}la4%nWWo~3|axZsfVr6b)Z)9n1XLB!YYiwa+Wo&aUaCyB`O^@0z5WVMDOsSBaie}qAB5~ +;Ma#)G>PyNZ}TZ^lz|!@{nn(>PLWjA~$Sgy3sv0sc>Elo=i?)D9lw>eLuzu0jffzxHU| +>(DH#aRba+G_DltfQDLUeARiPNIQ_$U@~cEMS|uLW6tsZZ2WX=a>-2`mXAPpQx=x8C+ +D1$<>1x(H~kaVogR4M^7f4~O2vVzGb+1yVV{n!9&?>Bo*+*l>a1zijVR!yK=e5T{;_I;8HdWT8)4Hv4 +inoz1;0zca7PDxRe+%1af0!=MJWp%*?yRGt?i2(KyGlYG?UA>uokmL%vxRu|yB2ZsVHf4Z$QC*U$(Jn +t~8Ep6{fw9(%oR@1zw(X%2Y%vPMg=INdBJRRqf^bWTbcIa3`fSym9iYKcCY}m0BD7_YbM*XZU`y4%ro +(GN;nV&CPfk%h3rhQ5hUPC(`TK^tBNdiNlEer9_2cTWTk8nP^!Vnc6RfZrtKzU@?yxPC+1{L+DcBh7c>z#M0|XQR000O +8HkM{d7MngDx&;6Lq8R`HApigXaA|NaUv_0~WN&gWcV%K_Zewp`X>Mn8FLY&dbaO6nd9_zdZ`(!?zUx +;k5(K0INswG5kp%c)#S&mZbqdHiSq8DBR`xbDDR7sueCeV6BfS& +0|7u@Aw#fG`HxaKR7}DBU;e=I6@1&p^=gfX+R=I#%QuQ?;u79nqPdJUM{ARdqp^=Ap>e@^g4;}k>{;b +o+iZe5WU~T2}fx}!35%kU{ZoZrUiTEy&J~ymvqxX^RvlxzUTn0knbSrJzNFOGmG*;zmYatpNl9+$UTW +T4$q}{(y`ZMD8$<5tJ$#KYPD8mjWA;*;a-9%Bg`e+fNVI8qYhf9QK0VL;^daW2~%=?X--e*1>?9P}nvW! +w~5;f2@-Ev|Mzd5%={T?dk{J9OH;2;UQQdW!Tyo#^KSM6YK1ii+(2KP1t9qG*{cBO$-!dvb#fh%$5;M +?~z~50Cr~PLB+7uQ9^kel4Ql+C5u*ytqIQcjC;l4GxGttmRlPl%#Fm1C3Vk1M3b>-ksE1Nm<+-4&RNs +gM(lp<}^ACGC#YzxI99Ou*^iHf%l(3F9*f2$v|}DD11Z#hP`&rW(AhNZ+8rAw{=N*A5 +{L~7-#+_=8ubd+pcc;w1QWtUoQmw~D@xkVh%_Zp +~f&|A%5bQGW_e3Wrl(MTJvZyKenn(AKH@s|mdF$vgKExB&Vq(VTGULIIUY6YfI5Na`vaCmx^q@)Z|R+ +lW%g}%WO4e4b&RoS8@!HOXU1o;?-$aHHY4gfymprm@mfPuUxt&bl3)kSgkZqtMwvVWF)J(HUH9w^>>*x5K^&mZ`L=zWn?1?|F&I-nE}%s0bg!lyACfu8Ko$XR+(U%uHK`dt%AeHIr9YfKX7SI#Nuf$}>v`Sg9OLBVVaUm)-Ims_%%ygPXB6HCG1eRnd=l{D +y>DLrH)^z5S}Ea{l<)}j4q(6LO(sNb*mWrx)bk!fI*mNx}Er&4}Rrn}7S}O*!4~Y!)X@Ii;-0%UQ#^s(b|_?0O9q45Z{967#CW%HR0*li +Fekr$77H21f~m@MshM-!(i*<;EQL*4r^@4rpIg~DNd1%6r~@gFlqIEjA>-%NZZYN<76kcx7cy^0EwaY +IGhY+1q-3y3w=kzFs{PY@}3Nin4q3d6NZxLc{EwhS0f@C>7E=lZS=?pXX#X=bvpWd>YM*Z0nXJ_*zq! +*&1UBZs&LG(EN}9EcDSDHQpuB}&xPWsvEq+!f9=arns=VzQE94q{&wp)&#HT&)aZwo({-1zn!~>Bra; +hzN=+lOGN%%(*;k8HWZ*LFwW)Y!tWaNFp@Pt7M$#WH#T4nk6ctTg8)t=TU>`F&X?)1;qjxref;iT +UODe4Eeo_nmxMhDkb|IEK9`$+Q}ojpZcUdP3IIvL?@zx)lkonhE}BK$jl_S!Bp&1vu!(!kXPbnpI?PgWKGmRxgXd~|KB874S2Lt#pju9? +vGpHNO9KQH0000805+CpNl0%+zN7>I0MZZu04e|g0B~t=FJE?LZe(wAFLz~PWo~0{WNB_^b1!&bb#rB +MUu0!wX>Mg?E^v9Jmu-97G!%xv=U0f7l7yupPS-XL3()li3S*RYFkml1mW~>O;{@5EEie1+DE3kGq+L +JkB46%vEK54~vD~ZP5^Ao~{Bk6gr5QGw&1Rz^-0zAK%Il$`cRg7aWG9+Tnv<@^-`@YL7dXsCI$LBkqr +8-5I?u)2h;mBedS|uR4lgGBF1>o%NX-{FHocsdBXQ(IG3ZAFk=%%jbmkVikc%|0@6J+1c|jxb_~N)L3 +L^33?C9j_#fdO;D>Rid%?h`4#;q-@tGFe%;4D|Re!|&FRjc*=xI4mI-`5*=8e}#;b^WLJ?8|DI-aXBE*?; +}6Vvp&*VtE9LeOFiCr`XMoZWMc~tyt_uX-Upr*wvYASBI{_l(%j6&Sm0?tbC=rH8o8X&xV8CWx4P9({iw$EyVB{^X_uS3F;u7ZP#PXcJ;RRg9;iFF) ++=n>%8#?YwW#cEWk1GN;P6$|*D*G^+vsqIj`@L!=c@VW>Cq^$O ++(%qDY-`5|+g`BBYgt6Ar5zTRPe%zVJ?GIy9g<|j_4^IPUq=6B3<=J(8J%nRmo<`2vtnJ<_>F@I+M!hGo;^(ziuG +v6>L%wL)Q9Qi}!Pmn)8{_OaJbIF`CQ|52X-&iP0xUpBQ~ +&^oh|YMxPjcV)Tj8Cq|zbeI)uw^pWTz(MO_>L?4Mh5`854Nc55DBhg2qk3=7dJ`#Nr^hwYsL7xPD67) +&XCqbVCeG>FZ&?iBk1bq_pNzf-jp9Fmr`Y7~K=%dg_p^rizg+2;>6#6LiQRt)4N1=~GAB8>&eKh)L^w +H>}(MO|?Mjwqn8hteSX!OzOqtQpBk47JjJ{o-peF%LBeF%LBeF%LBeF%LBeF%LBeF%LBeF%LBeF%LF` +WW;v=wr~wppQWxgFXg*4Eh-KG3aB^$DofvAA>%|`E=@kuTS^`L{$IxHa5TI!q +O9KQH0000805+CpNstYPL#F}&0K^CY02lxO0B~t=FJo_QZDDR?b1z?CX>MtBUtcb8d3}{li`y^|hVT9 +rBE7_rhV6ABr*xMVdMNaZ5*DMi#)*h51xY4JOaFUEU;g&ykd?(o!zDJQ6 +Adx$p~y>Y7SsvK4ZbRy8S#sMxUq@+g6n0nJVAMG<#3y2)&SLId)9A$_Xd4Z*OtZgG +RdW}&guw%4%=nEk)wO}liAoxTEpWszVZ0L=7>LLLdiXEw8Fo0u?BRUQTc=U`!b`%Y0Z#*N`iv*-UmdS)(C_sHrBh(LVvVVQ +2m1dyP>cfl(vn|YvFk}6stBDoUre;i?HZ_@_&HR{7hG>($VCxJjas*qL27{V|S$hqD?Y`><@<*SA_v> +#Cf*E4)IRQr2Q8D5a-K2|{gd+Ex*am;xY~8)=3-F4>vZ0{+lr`fPYJ+kYu56K9Shse#2d}Lj-N}6c5C +&#T4RW_Wy3WHPDy4_#ElNR+AzZcvx{`O-FIms<+tg)WJzjG`b=QK+>%`ml)FQO8>V2uS20Wls$e+#KO +pI5R;IHXAa)nEw3=}oBcp;n6hA*=7f3`whL8tx#n~s3Uq`hjC{f-TH7wI9q5P)h>@6aWAK2mm&gW=S1kJ74Vq003qM000 +#L003}la4%zTZEaz0WOFZLXk}w-E^v9RQ(udtFc5$DQw&0>f(ZM1;M2lA9s77M%OYtUZLTr#GI5uF`< +q0q^(=dEY$&wGncu&es(!G}gSK6#OqV3Bvpo!IC{Kb=+P)X20W}ppPmgPj9ncA{tf5k#QC^n9_)t6iJ +t~Ji8c%D_=#{3WutQ%fLtbc&P2DK+PMyYxm?TLMg$}AkUCHG?;$2qPM)X+MIhRQ-h~PPJ&I+^nJO7pd +pEON>qEqb^Zd@=3c@Z5FoW(l=8y(olNh35kplQ%Zg;a89LNG--RYDfG%pNvOK@R^ooch4?` +sGmcC%wtHAZ1srKW}qKZ7Z!L`;!WehSYTm^@7!I;m1s_H;TI6wp_InZAyeVla>`^tB8#2)UT7x+8=z_ +K$CwkKnv0$$(pEqyrCvX#oTHru_7TXZ1c&rB137w~ab@(hZ=Sig?7OpAvI|L|1YTiDcn?v__T`cdfM` +tgju$og5(CgqR-uM}MEI4y82`wI7u5hj~|Va%8Ny-@9b2Y{1%9MLuvhkkSho^F@O|B`LVeQ4>6g_E-v +H1{Tm2Q?brhCKNLP)h>@6aWAK2mm&gW=Sx?%(G_$005N<000^Q003}la4%zTZEaz0WOFZLZ*6dFWprt +8ZZ2?ntybS}(>xS?_g`^UI>jDML|-fQVT>Y8A0Mr{A%xfzWr@=n@=LbEXs7+}T-#}rG-VQqyd<{oJwE +sN*iI_T9KtZIbuD=qg2<~#NnxHBR$H03Q#zJ$N%aX +^2Q+n@<^WF(!SzSbg|1r!c0r8Gc@_-(Al~ms&;$HAt|tc;@!9!r^^hUSHRl1B;n7qRO;bi_p +`qRO@>WU&b-$WV{25|lb1AB$sy$dfWS;OSjQjaX;k|M!9dsW>4)XnObY+$7uC6-POc+Jc#RgQB2@SVkarqBivJM#P!iaHwYmzjA5j +{~X8{s488!|X%&~S-_g2+dk(eY38ZD)-7ZBiY7{G?oa4^(+9A)?R +%43XnxO&uOSm4f>9`GWJw+jO7*fTvbOPs*+$emVe}8P4yLk|q4r-i$Nn*hPqnk|**>RqPWu+C;H1WZ{ +J&XvV#D17Vq~~eR_w9Luru6TNb|RKTv`zx!MMyMIT2_s8t*Szzd=e@ovX{2Trjt79?it16O;%K*<0E_G8!xRGUD(KnMrk*xK;tc% +9>E*PzA4BRn3Zom~DALw2Ezz0mq)OK&g502NXsbarjEhp1qOh3FugYSH+DC>tdj7`Q@6x@T?uHP2yz6 +4H#KLI>(x3*$;2MCewiwN3S8#L<)>#qOPtTtTJ9tf^?$0p{fj2iU#-{TCPJO_-|h5Nu%x3053ujdwzX +Nn(@+hUYXxRk-86q@&4Xq~uNub1l?d?{L>02lxO0B~t=FJo_QZDDR?b1!6XcW!KNVPr0Fd9@i`v!k~4-M>P0Cu7Liq-pc +yx!jp{w`ntzNp`wvU+&ytWRPv`0wR*Qcge5MIg$VYvK?m|9iYEF-*Xgw%u{lqg +%xGW)z*x%Z_wop^ofAB9@2j!2>5O~O9qtkGQ5s;BZsR28j@e@ZFj2*>M!ed*aT9>9B$yefnha-`I1UJf#|TA?KhF1Msc;Y$7s%NnZBGlb;O@^WDP4 +}5qF%yTVdHwQiPlBrHF>?ED9dVEfqP;A%S);hc?(#jpoP;j +TB;uJR|Ky0dToAt1k%v_BRw%iP{#erEbhp=?%j7JLR$)b1}Th_n2JfOKolZJ@D&RoN)_wgi^(8uCpvstUPYXmsFk<{CxTG)y2Cd)e?Y%zEGtP4H!Ud#k3@0&Td`QdH9eH<4iw+_cc7WFh4t+YoLXcBYwqE4D#d}8Zs8t8V0GX +%gu)#-qAt7pv6Rg3fNtbHz5y-rlF|BpcV=g*&dgZsD(0|=*Jf92ws7ASOzH6-SOj5r;OyW_+pIR*2`z ++4hq{&-+zCL%G<~5GU=~Y|p|mY^Dj*G7i9K|(d}d{nM(brOf@Bfo0pK5#bv)wSXM$Z*QhkJ$9aQMT;- +Jh$WUJ8+qGmy5euUT?x&*Wl#$c9!xdciahkPclT%XB9PyI0=>j@Qmt>0QU3cC*UU(&-9aWv1et!r#{c +8K^aBX#-=-hYAi4a;Fu8IUXtG8*g})c?n9?+lBu#UNyugrtN!aWX&;vwy(K-yLCk8yhTCe=uWhY#Ag6 +;VMl>c2k;1z2Yzj4m`MmCJ)m9`8%oT2UrM_>!Bl-oD#D6>n0{S%pNdM3=*NMVf2Log_dQQisdZXi?VS +*wd3i?Cj_OKh!>>er1;x6P7E_l`LcXYK*2y;nkHn*N-&_Vf(!w5gU}xyP!sm#Vfy^ICDw>dgQfIChxZ +)+2Z`ZKyW!2|Y9RJ8cQd|cq75NP{;L>B)NL@9pj_k^f_sX;qo-OxAIP1RKF9g=z=IxNz8~BiLiwY83p +`-}J@C_3^sL;*j<=NCt8pi^1f!a67)Nfc|Ki;ud&%}32xfvbsddVy +S-bGfIfq))~T2LZ}t!UEbI*`75&IuJY**++GZLRlPRdixe?|Js#%d)f(B*kW;19vR4OKel6dP0ui>tz +{Qt7`gpKb(>tj3~cNoxW-R8on0Tzahg15cs)#H#yFt7n>4W0%+rsOBtGS7m?0e0Fg_Y?J}YiRAKFxvB +g1_{7!5y5mCWhuDQnS|t&JU2E_Oal>;7pKDNm{s0S%NjEezs=6uYnRo?#86^ME92-TcP#W8h%i#={$u97LHm +&4w!3-=V@RM;foIRJ!-!ry2H5id~vJqh4XPv@c#l*fNO*SiI2x{0YBncXWZrqC=sUQDPW?%gz0j#!0c +e{$fk-6kiqi_6$?RMWoNEC3v<)cr02ddH;K)6#%Wt3*0`ULt^_(~J3x*VO;%trWLW;Xk?a2v$OLg6Sg +6ifHU0b{~zgwm86ur-Zy}o74Pkd~FgBDbCMZqXlTZU+88}WRq7aar3ow9bW67U{DzL(q!|6+Muu;vI| +-d4hrKUv|N-01t@}T8MD8e%!V*dSS3(SOjbAjoFN7ejD_bNAOjT;kCR{&F`C;=C6g6bwmq0)h=v$;78 +eOQ>CGt1KC!&DC5JaIQ`$mo2@W(B#e>xg11*q3$c-Yqf0JWLPsw^2On5CEvjmGTC6VX&dH=)9$U8l$j +}}oCmdd|utfqe8nwl_>*sm5eyu&)zd8gks!of9AOmB$iYGyjCpc!NZ +*6U1Ze(*WW^!d^dSxzfd8Jm{j@vd6eb-kI1_H?&S?TivdfH@*q6Jd4P4kcj1TBqZ))dK-)OxpH-ytbk +7YishF|aFft~_UkLp4Tqgwm#Wy#Y!I@3buSM|RG(W +rnH-q~H0zkGN4tl(oNSZ^!yH%A7L5V;7e>ptnhY-|05K{*`^5vRPLL$Y`wxH8Uw{7bcT$opMbk7VsRh +?-rGhz&|}V(1 +CQ8G|F_$6-jWrS}_Ae;4aV;9T=&Qngd1yX}RN1KrF&Sr7|^`Vv$<14iH)z2}y&jw-^!`3jqA@St|J4v;Dxq46>;dbnCwK?X?*837Y>NVG4#w-L;eYAD_{tv+Gn{F@FsZ@1GM)3VGGLXDTc%8 +FkoAps!+PP$FJG7P4jg-8rc4_yVC8cHq08MT3&fouR^FGwFIsGgbx|+?2`32`yG5Yz+xe3gEU~{OX+e +gAC0n9G;S2J|iCYrc!Tyuv2%B+wi@nhy7_Kp+;~m%n3;J5Zn@D)WWqlA_p4W6nzP*}mslSiyPrv=LMY +fmw?j}C1r)E3?Ig-Y!6S;69JTC|fNpLC@BfTXl9XL&2&x?q>2vsq$Ny(OGWWzdzL))2t-Af}Qk4#wDL +jF?|2hS5Xu4e+|6Jo>pePWihLLHgFBo$bsqEi>ll_x(QB#h$tLeTj2pKEcBb383z`N=DvT{3E{kioX??*?4R2*TYm +ZgYXM~IT<%#q^(iC&VI<3EX>Bd>E$rthbt&2eqPUJe7sd?rKB@T;9cTxbv%dgTs#KVL)2gxm+gHfd`$ +F*Tbow?&PU(r10Wmn6+uO7Zt_*CSqVLLWr#fcV43v1iJh03u{gM$FP;EQSM +$m(n`AcF%Q4w}*e|O;&B&|qBwCt=*+CUH_|-IsmR7#KmquQa-(aK$T6n%14WenAQNQ%#_!)`3)K{-jK +s!~hj^nJP(6aWAKaA|NaV{dJ3VQyq|FKA(NXfAMheN@|S)G!cz&sSKLR!OR?#q)|FRj5! +TM5S%T3n0szOcK+?Hoj2$_l%v}W-G|UZahA7GIQqA7&Q>a8t=RT#)ufSGLG<*RlRq>#&eQP_Kw@G7pM +8ytF{%gosag#CP@<*wb1m$EmUe4xU6T|_v3NJSjU~WtWq`D8FYI*-XB+pccNeJ4Dgy&otIDc0zpG)E6 +InOulL7KkGJgZ=Had&50A(DFCXLK_901<5I7i8&Kb}a+~;V^7?XTJDRP8WJ-3$JA@dY@HvQ*^gy3^^b +rt{7s!=V%qd-J8_|~h6_eAsRiMM!Ts!sd{nne5~Mhc|jlAM5e3pIHbt|R+>bQcoc4gB)LzyQ)&(uf|2 +Q>0dC*T5Y=^$?kaLEP?X*!X`KGiJO4=XfZ6JR~D5WFNdd$$g1n8XBBrT? +Ok&Z>5=u|_4T_mJ%jAa)3rXbhcv=;xapPnbRMs|%FpD9|90MF^-eeSoqA%<2%%`j|Bc^zLc{%k>nC*A +Y3z~4RZTV+tuAuTol>@ruT|GKR@B`UDxrdhTSUWKogsddW0EAoc>-j&{4hECQwf=ELd-98(%e`u6k7v~n}lMmQC??nimjCST0Z0DRJo}&3KA-DRy)xUsa&)kH +o={LRU084i`|ytKEMgD!I*r5H-OtlPJ_POtZI~V2z0S6s74v=LN`vyt4PMV#?%{?r8|50F2|WF@f}4i +UTZo%fwEXbC1QY-O00;m!mS#yF7SN +rl0RRBj0{{RN0001RX>c!NZ*6U1Ze(*WXk~10E^v8mQcH{5Fc7}$R}3ye4y0z!rRgOsY|o*mun5H-+v +-{mB$=%L{mQcCL}7I?@_aANOl!3S#@f-378wH}jkX^6)#+jM$d)@H?Tj)>3lSB=Bju9^m}%b +b39X?_m6_(RiVid&0h2t1Tg<9=LPxhJ#rP<@(+KA`nhd6z5*wpbrRWwT0E%g+c@deL(p=cY1Oh}Yr|%R%gg($?|V!c;fA +0v2&P_a^ktIpS2g$%QxHwMEhQpu+)!lXx#$d%tTBlRhV<-%dM-X(>fK&$^+s4}ST9|$SrG4IA@3;Qs*6 +|v0JR>lhD**u@}LGY>nUrc!NZ*6U1Ze(*WX>N0L +VQg$JaCzk%YmcKi@_T-TFRKyBY{Kk)ZEaSXm+o3xty&$N?wuHo+{0bmzXr6A3Ev +KYC7PmqF$~lm(A`9aU@Z+tIDciQAGGL7ez_vR*JMLS)}i0GxIzZ`#sP0_EzMqprt74due}_?3nL(%Iv +*7R3%UC-4iV`AR}jGalV-mxa`1zv2@0sW0sfXRz3Sz6r#{TYLslqFCt^J*$!FHc^($*H;ey?{Z{dU9a +&c1v$6r%QpsX*Jkl)jfWFrw4R|VIT5^#|3w+{5S<#ebrzjKAJ{4P=%(uebvzG?$^@z5jWS%P!aVjNif80EA)MB*u9MT4P@ZNR? +b&3g*aEB#yX2jH_Ax+E*WD~xZ3AnecT*&>QEdIYat0$7|eQgQo`_-k=oP3mM+m2V5Yzf2b#}Hf?naVg(Bn?ynIg{jCX${KYI1}6L~O3Su3@# +Yxpn>2PmzJ7BMaKO9(xz8Sr(ArE9^TE+V8Y)1uRl;rwVUinQOi$QSL&u_B1E3~K@|>a0eEI1~ZP68J#)(BAhULYk-_Al;&gUSSOXlm+ +ErkHvC%Ef!07Nw+DRfZ|$y0-6eo7)B9i6saD>D_EDo3jSS}pf(1-TcZh+cq^r$%uYWBS3o_Kj68G9loX`yf1!D;45v^f$;GpV4RyR}ku_lZt^Uej5yKh$`O +`3FPRXFe5I8H|aY8_OZ{99LxC*Bu7dXsS#8YR)7p-FB6<)p +i$7qb?Hh~0tu&6AmE`av^FUH-_|81ghR0)a%WuZ60s|eVLrx-%KerMb*B%cA}0O3&S8ng(d4}&z3#gL +KB4QMx0lzoJZKx>R~CEK4N;epCu>cs0VxiKY1gFxB~0|sj8x@de5JZ5t95Qr>2ula7BF_thjUo`wTpX +xubk`+gufl?0QsnHV1tC&IU$%Ck%!rU5#f*QOUo2%E%q0(vTnikB^0-Lry+Z#9zOx0v)m$)hli2AAH^ +fsOl3017z;R}W=*s2)dZ3tI0Vw`IsmjlAIwTM!+CBboA*eDNzP%KpJ^^ww?p4I!W<>|$Kwi8fOt_x<1 +HJ_U)m}m&*$~pTLMX!BiMQU=SmBrWz!1zup2^HwmkPU5BzAnW&0pAaUX>#A{2*vjqFukt5#VfuBiiUu +$l>b&yQ3hQaNGTaA_PyM)|os0L1n653F}#9?FZc-hHQL*^Epnw)D!{MVuBLWiO +tYh$vZvgOTLr%aY677FH&U+$lX`G%u{->c!fbz|_Z$|GZI6hxE+~S9 +Y)7-raq8`}yswf1B69e?CfIVZ|bzWJnhGjJa$jBCaqv=p{OGgMx=&?mvEt-o3s5=%t2Wy9(ui3I>&_uo0bAm!N*yBn>1Waw5@rCU|K +#wGG=^`g*AYVq~$r(bS=`Ns`;$6^X@psQy?RzP|wU;!cjkD)og7!h}{LarEZB}@9V_$EaF&=Lfw!-q$bFK-)MGLg;Ryi3%29WUUB +u%pChoIbovdL+9ABBe7hoBSm`v)qEh7R6jYNA%tgJ*!c?agPRS(U=j(MWjybr`+&k&!&7_-q)HC-ZTl +qf&nos`s8jIv-nvDT7G>Y8u$|}&J%F3)|`$7j +y#R8IAwH7g<(QobfEIU+DTt^< +D~G$~6f~=jWz(fAs?0R#4Bsn)-8QF1*V301>B+cEWcb5#q#I!{8@g38@)7(i`{5m5D*woG-fPwi2rj%UwtT1m +_&s!x<+KMe|nLNAIS^{&+GJoF%dXcD?r&oTL*Xv%TXV3Ri8@|2gV>3yUbwyBXx4>8`3`vTU_GVH`0yu +5oPZLk3gq^Wp{*t5!&=~PQ7?6t+7Vib?8uAM$qDv`&qoHva;y*AASRGU}^gDy%Di*$tw&V-L%Dl*)@L +8fR17TxV2+5ZX3Lzn-33WR^BE79vM+Ad#9F7Pg;6XzrgO7mj~)qThq?NmZoh^yjW@OU8i}`G)6WAYfrC&>wTIVFR6MMXb323pzsgrR^s1 +955_T})9${2Z6F#+I&Ba{^*2ax$^Y=pCseC%(H6{sauzc;J>?ga!{XFEWzhFAWzY9Cvjs5}6Rhs1D6e +W(Q@H+AT{wQs{mX2k7Hu$vu<1%#$+13I(MMZ$rSqM+SS*JG?47K*AZ5-9?7@J;*K!(8)#jCMn5^rj!+ +@B$JVRlC3c+^20*(M<0ca7yZO}hi@#H`MM4p}vts=w9R$1E%))WEpTvnvY>8|K-~ti|pQmr;d +1KVZ?4dKw2aU?g-C +ne*~7HH*gN{ve~HKO^l7Ki)C@yT2kbY!=-`zMPMWt?yp(6B#mbd6Iglt2Q-0omjvAEJF3ZRbBepn@9h5dKcI(?$qASr}|m +EQWFYHjJOUGVB#|H2IPBGm^MT`0wG`>CZlEZ_%V{*jWG#Wa_TfptZ`A}h7q~Ok +(56!z`GMWyxW;fF`q9jeXN_U*M}g~2@h(<9;78X@kQzzf`a!$dax;`hN73EQ?=A&*Y?Mf6+pkNfGwdh +T+2-9ifzN$Dpmn!^ZB*_)^&>XPY12to1OBEH!^Zse1LbGa?X5X6_XA3lBE@x8qc-y(I*K7Tb5h90`Rx +a8cRuUav>*F|P4AIzJBqwQ{-Vy@_D|&wknT7-4M?4O>y)d{1BQ5t^P=R}a16OopE7H45rWJv`?4RnH1 +Du<&H6;^^W>hlEqs9m6C<*rPaEr-(P(>3lD5}(xNo~oAiQNkiAOuo+fw#S)Ml8}o0ck$;#uioDmuaHU +Z$o6a;n3&>d3aqzv>W)IW;XusG+!>Bf7q;YZzEyVD%8GO_GInj(*m|3z%VJN@;PuWjj3oVAo!QXir;P +k(s04ey1MbemsL3PalQR>CRYx^YCpPx?L=fg8Oxd*LTD@90F0gO3NEqGVCbFC78Cf>Gq7!Xclei)Hl+ +S_~F7EJid%)0&#nGOz*l5SqXIpl43wW#;wezL$G-oy{;kZsX26XNpC}VR0+E3C4C~d>qHDzdb +FPG1CtYa(aR +0)0*b}+}b2zI|VGOpWuKCWbYS;kfa6XPP0VO7=~@A^z%mQ!J(^1k1YV2!Pn{&!YmxaL#0kM?`9%Wur7 +92ZylhHd)b&4?R04ZVN_;je;c3Pq0KIC>iA*7PcPwiAos-kBcGdtb?5)!e?Mp0Ej~EyTm6xqI2q+Y@M +bt~U$}lKVEQ&W6DC`n>2SZG}5ZQX0R4XT17s8-MkFrs(Is*N5};j_sw|s=W~?&v2{WPyRddUQw;`YpM +~;#PyYk0pK569_>I2&hSw}C`!7&S0|XQR000O8HkM{d4@<{5z +Y72WX)FK$6aWAKaA|NaV{dJ3VQyq|FKlUZbS`jt+qe<`-=BhTu#lA6+T^YmpbNM_oA%lOLGRE8 +EsDiLM@y8KSy@y`Y1h8C-@P+@NTeitAD1f%)CjURH8Y$i=SNbd6nm0oW!H9+Wf|f7M#z@XtrAt&vdsK +mEbRDaC2IG*61yF*ckbr{l{NfSi&h@576d*e%H}PTtq_%RqJQK~R*8DYRJ&k@oHZ@^pr8C+N+Hj2a*v +fz6-ZiWmWDTJcF*cUNXMl3!F#x+isfRzr*+{7-kYBTjZun=T8&7wf&(3|3wCfM-_!h#?%20D=+Sg7AM +}s4Z9CRxyjCr(Dpq6#SFPmRPS3X@_%q`wV+C*NwqnUhR9dh`vYaBh6Z>bj7x%3AP=C*xw{QMt!Z7gV` +$B}~?CBlL%viRQqH9(}+hTq!78qD2$;L%E1(iSQu{g_Wx`#YT7K=q*QKiU7(AfGXwto{7#N~3S{~`tH +Ehdfel)_2#sw-du;>=a)LbF(JDncbA74QQeuL&hN#BU9AxA;TMI*(ITwDL#xCg2OJLD0$Pbi;8M$v+mP(8fnZI;D~RppAjrg8_yy?%Z7U>#vZHsC(bSu29%N!o +M!e2bnBqKBbUpbOHc?)Q`;rA1+*8ut(J6RkzGg8$c|YYPhAidMmMnj_C9Qmud`pp_jP5rC1jtJ=-Cv{ +Ed5bjzw{W1Qrq_dbe}=jhlO9lNF#DCXzU(Mf-yj?C!jvi0ZD(Mczeo1a+@3O!HB$|zZhoK|02!#Mg-n +nJwivh8Ta>U+}O(w5x9dc3Q|mR2xJ&J?a?g4Ckb*6gZV)TobkcBQ%p{5Q|%_2 +dGOQY_FY{aG5?#c?Je*Y4R9DvyM`r;VKAQ)%{46dUp$J-4|?Ur6k}`2Dh8`6!IoICdsc~N&+3-kGpTS +@Ov!JLPUMO#X9Br|HbVsZpoBi6h%))x3s?rRe3td4kbBymbHHqrG3T;b-uzZ@NKeS*itT8A#A3+->g; +QUUrWi@kGjke>G(<5dvEy{a9G|#+A|k(GZUeE03%n#2qv-hS+XK_f?4k^&6Lo=G`LEaFZLA_8wB$o9h +Waz;?Zp&Av+<#n64M7KErk4V~55v2VerYi`6-YC!(A+b*9ee%{6eu_Pq&Qi9NJp+GyHP2^Ho^@J3U_3 +$hJGyjgjZB+p@Up-4Ogua4IdJbW-<5<=cfhCPZpFA*b<&<0vUBRM{7 +1-PFpv$|SDo6bs;44{1-0@N^fP<&SL`c7@Ew&^ewromvu#S7m{K`@Mk4H>`(*k7_f;f^ESPZ5M-YzQ{??<5T|uClAgQACjDg^ic)QEKdF2iUdLw7Lo=b9TuSgz +Nad+oS&JKZu?6NmSqW^jRi;8g_=AgCJiV{4ff+7g#0v!hGN?>e0<`7NzYSJDfYWQ~A!Bmm@syIKJ&6l +7=%l{_a;Z?dFTiq=QM$`TepzjWPab}JH+`Bgr49wyCCb0GZxd?(IWY~A!SC(g(Nzy7zJ*wxT@dC6JvG +8Yc~|91}bU;}}*^-rQ^&-39YFv_-l2MV;W)B|txTkQb@1<1%hGZz0{bgs7=`Ljb@Fk@L&te0Y2<@;Im&oAsIfu@n8Yei^n6U_L_5kk(Q``sc=U1UKK0odG>3uiJ!Zq4hr~R|hj1Y9j= +=>}@ya{dU!}7mv( +`NG=qk?RB+%V{H*&REYglgkKA>S@1Ak0O_3WcD(XlKPubPD5If;WbOv>kR##Yr;uFRIYo?KCU?_2x$J +z>t=Vs}-+%1-w)}1JJIQp=wg~XF!O$i< +*7kWRwiqg-5*YPkzGRl=e*PDeO&;b3L$4`%{OG1Df*`Bo&LQCUlEH!NpZIpzZbF-tPU|`yoG%?PDIqT +*@9>|LmvrT)fx3&S$xHa`>H>Gxe6T2|u#fcpY)wY|=O~5_c(w^PS&Pdb86=N&n@qnlP(_(|4_SoS0d{ +^Jq;-Q|NFXCPT8hXL8CNcU}BfYZ?AI3TWP(jH=3SM))_z=hk=v1@UM<=%W0 +4)1E0KF$Xf%BjC_sRXghIW*R*$wqrcYGJo6za?c14zCX*Lmi+QfG8I9!ov9g)}MU^Pn;PZ!Lods +^v~8bqGXWuV0uVlZ;Oc`)WyyI15}{W4Cu7ea!wYw`!){;}J-r?+j}sH@A%9borvo91GF*&G{s+3@C)E +7dV|`SrVR-oDb`@vaAUk?XJCzWdeJUw!lLms$u_I^^gZJu&*m*yH?u{pJSDML32;heR8BKod2?!r3h$ +FYKWA_KFjN{18kO0bYr7aGU0Wu^idFSF&Qwv_gT2MVkO$@MN^#iJhDe>Y=G9zJSvQ@7m0lR-ZeRonR{ +Dh?5Yr;z_NpJ`&BnX)t`AqN~3fM}1S;;C>~xN+r$~-IWcAO(L5EbDiOCH)(?IlJ3306L(Xu?#2%j9CU +<2RRVT}x41R#^nt5p*&ZKRBEnapWLM*mle +IxJSAvsQ};HAtR9>+oTCh&%B*vWzkQSfF*cCrLLMOM~SZRG;4hr^R;yS6t0x%6Sxli#*W&GtfOkzeh6 +&G(@bC^(0U#en?w(Xft$H96+jp=ihT^bv|^c)^!vHEV@BFJ)P)WSOYmOm|D=>E?_n?C?fGAqu*sIx_z +T;qyG<3O9KQH0000805+CpNv=YK+$IJ90G1H|02TlM0B~t=FJo_QZDDR?b1!pcVRB<=E^v9RS8Z?GHW +2>qUqQ4mB&D*@VcVBrF3_bJRv=A-Il%^ahQLU)%|;Scl8WsW{qMV@Nb1ci`e6gsy6>V!eCrrODUlsS_uf5$W3iR9u?6@q%OJ6``)7P8LnC9Rb4)6143XNB^Tr@QyvUZZ)pwPQNfOqRT +&MXLBeY$TW1kexiQa#raSRy#p<%vi0tsMILVYbk~74&%XSHEAc(%(Kl+`j9i(`Q +!YLMAoMo+!GIJTs}lic_trRE$v7KBRVc0^r4;cBy1aG%{mqYDV!Ru=d<}b~N0kS-~OT*=&YHFiDoK2o +j*~#;k>DTG0~9Cjzmoph}SyqcYoD8bbRWUCs!6Uc7kGZj&u|hq)nbj9~k)7Z4Mo5!h1==*bhwM5QSQd +Vl%cFnM~D0EB@uf=d!8gBO^!MgbBmIvGOdwG=zD7Hy6;4#f#LD}ZDDGCrYm&aWhx8PS|=;k59I>og4& +E4DGYpmL|+>*DEP<7+W%;AOxnl}f#rA%;=v|VmtF? +vc1ot{GnLEW;g6e%(v~)bUSjA;eX4od$YLn6XGOgXeuYy_K%a;$@TB)pk9RFggB+7NjZ4kKb2wdfh&avTe8m$hh~FnO$ +oJ5!nT}(`skWGy+gH|P_PI2EEl@d#u&{2BHA@j;B}XE0tW-}FbzlNRVRZi#G@ +KBBXibu2q9R|wDUCT7h`95}>oQjssy2dy+&F$ul +;PKx8H58zD=A#AlEk}Iq)0rtJ%(oquF4(3+A!jh0dbS?)72VEN39TlLdJ>Q|t_x+xcf-6nhX@S9T1xU +0gPK35w&<5<}Q3?5zkpqPj+JW{oiP8d(Ag>Buu>=f*9q9V757C2$!5Om!j>0o?+`MekYT~vnF5RJmgh~ctGh{Ib{*}VfSb@(!2S$+=L=gD8o)jUru~39sZdyhJ86rkR@r +17W*83@%4u3}sdqG-IB0yhf@F%4C4Uw;kzA2jcER;eUHKqWWAYKE2r2+vhe0dz7#oy@lkN77c?GM)q` +_Yoz9ul)=rqtZXmEhCXSqxM=;e6KzACQroM&-!t%6tKG$^um$XkT)8;DKUcSr$>EBwDgOE=!v!Q?M&HsLi@x~bh=g +;yt80a7E(YS>~VD^T|z>kIt1Po%Ai;>#mOu`oA=W*Q+K;DoaUQbKj=gaq5`7ZDY#Le6L>(% +`wt{VvJX*cc6dp&umIKHx9SLQ#yJd8)6a#yM`-;QdVCp$Q>^}3yyz~o;J-r%Fzzfem91QY-O00;m!mS +#x|Qy(P!1^@s97XSbh0001RX>c!NZ*6U1Ze(*Wb7*gOE^v9xSl@5kHV}UIUqQGiBp0^OXJhUbPp1T +^Jug}IkDq1i%PDvP*(Cni1db5MrI`|)@zxs?PH-0x|C(~$hAm{-Hzv}RdCuob~3u+RjuQsNQJgScYmI +qp5NU~+4=45^=&5`KZ!goT4T!XI#xm#wMvBUNrC0bmZNP^UCFFfp76ZLWx_N0kBD==6Qj`xod72n)|+ +T8sw-LxW0HyE35X>b*P7jJif7|SXuc=&5rfZoJjRzy=Bq;OcqNM*Vq4S@mRv9}d{-y|Z^7p*6Deyf6g +mPRDZs73ia>*wfL3Y^0vo6vWnwSi +)=Mz@3>lP_=n6s|SE?30=!(}_wYcD!7XGV^$jU_%uWBRMs?IW&Ne!pBa>7NsG6*LVJlWXjMZsj`d)Op +S1VEuG<6^v4MO}vPr+yG7UEo!no0yveo-&M~6Lq;_c~Q~o+%vx+arDep4ipXpN}f5p$poY!1J*prR4{ +HWZpa31;I~HmU1dr@iO5X?+Qo0RAWq@lowtyJ5Ks;4T5y$YVoRtPSr-y$vTuH=WM0Jv>Yu!$b4u}#Dd +Y`AD{LW_3UJWuAY`(YMMnSsQ{$R9Dj&2IYs$blUSPOIWrR;ccD^hm*AB_Hd?D0YK>dW#hAh +InAIh86I#NGLbqu(4G7T#MM{9{H5`R!ayG?P9$SlCC|-d`(88P4iK@S=0CWGhjyA<6 +1*Hij&P(Ju+}X2W|9+<>q<@J@y&4=n7itUKi?yg6!dm!4uk?mx1ibtTo6_TC2|JVxvncYkip&~-5`YX +LB7-diS&mu*(OF!7=qvzpmyPk;bqg`O05i>ME5Gc#uvr5k@aq(UgE?*HIpf!sz?`*}v`6m?SsqxamKV +O5J%12;NQEE6#&bc3LprQ*I9YaTzPG=SBQaIE1^W!wRQqBF{7!kr_tzmzQd5NTM1;7-bdLpRuyzTgI& +;XjmzHnX?fL2T?U`n9)zw+b9-%^UMWr@Eoy5x42JL~t0`hFbb!;WVpivm?ZG@jp=0qX_!Oh-+VtUg-d +&m+}o#>ZEy3Ax12Gd~j@V=o?h9M>m%frAzNBBGXTF5-~&y1>a#g^;yza_XA=3 +bbfzwc5;6*6gYe!jT=`6KL*qtWp_L|#FmEFlEdVBp>N$70{tddh>W@>IAiZ5kl0h@(s)NvP#S2D046Le|y%nL;HzUhly +KXy{cx?nv!JSqKO^b3RVGUD%>4n0w&_<%UUm6DP+1^nOE=Y}ghQVp8d(MVv>g*lyvV?&+L>&* +A$a~mJ(6_=ETpDgZrjS0P?OHl^bLzN;$-w +Olm?r>DRcqN7-I>-WKS4mgIsHI2PNqpZ`Tke+r>m_q%TOuQ-F>B^5Ge*>^?OzOt;KOwWtD_T#R3z$;G`Dbd^%NsAuKY8{_?dU&HO9KQH000 +0805+CpNvnw&KhOgJ07MG_02u%P0B~t=FJo_QZDDR?b1!vnX>N0LVQg$JaCwzhZHwbJ5dQ98F$5OJhu +8G;a=tIy7D}O%UP~#*p(yq^7As3WN#0!keMjI8QlP5Rp&Z`jDcucZ5;5U)v|NQ` +gIfy^j5S{M0B!bh +>O?-{E4u%Dmvl#rY^jX2eM{e+`SM~^h68caI>pCZ-oun3u&cfAjIJ6g6YXufv*JkZyWH=mBIM<@6gFX +O>{1xGdwIIBdh6Wukx#Ql~5*?aGC?pB)pc0Y{osk@vtYw2+p9>>e2WP|E7R}O~1kCBCB6?ctEEKv +cXz$RVCUiUYZ`6e7__Hh_oL=o5U=JwRXK5ojxgenIxN3EQM!T;>n7pWaPcgco{w@jQzynNBn5wl>Q$VVa4f+ +r9|uUcp3H;124SZJoe|N%8hizJL&Q-U)OY>B(L1$v4`+VrbgN33;g`g)i`IWq~xW%5Gs&Q;uRIF&Lv* +y>m&7sGJwBpx=KA1P;fh5R6Ukk`Us(Qnku6+-Azb#KWi0Jy|g +b-X#<5;l`u^xIH0RVT_{mvNZD+cL~HLu-7^_+qH%-!>|}J;?te{nobRgI^2a6e9kRWHI$4X&W +@dsC9`O)hh`8+$ZZ&CPpi-<6pDdSG|p&AH^-M(DkbUFd8v@DC-C;DIg +)LSJlU|uy>sjOw`R_>Ax^3(?Y1PL{it|6T!gRB5P4UKVNmW{E{+0qky^&M0=VK@%fi=3kWw3`hALcE? +0;_!Sy=F|VPpGe}bm9E5KW&s=0T-^ug0{uYk8PXIe0yb*+Qn@NKfEL955w|K^f&pF4Rs5PFDfH6qbti +ww1vt`g|~{j@dmjc_GsvSXoL9?k^7AArpP$%fR${6^5eZ6pzk$)qN3M=+sM`2vbP~LTv*(`w{C+M|ED +`D?(|UdeFEqaLhlt?(QR9r_K%f^y+=5)K&1w6^$@Ra=U-#K98c`KB!&liP!%o^@=yiC);kGw9r;wi_q +=nO4fTCWacUb$^gmEb0|XQR000O8HkM{dmp60f{09I4F&+Q_6#xJLaA|NaV{dJ3VQyq|FL!8VWo#~Rd +F5GMui`cnzUNn1R28s=ob6q8wCqK@U1_DNs@_)W#cCCqWB~V=IJF%({QGytb`mET&S5L{rd&Xc8{#F+tm*=GTCZ%V0pf6Y@;F1nK;x+TgEp=$;LwN|4$}iT∓CA5E)X`fD9S2$r +NUScikY{Lx{>Tuvy*^2!i{M`r*2dL~%ex@gf=K^XgRApM~K=QNJN-x=O8jeCW=Ep|J@`KQBxM$b!cVd +;_!S*DL6|xiVe{!XB&4qyxRkop3TH1C=D6G=wF=+`k&Tvw_*WjRzP=2a@6ZQ9R|Mb4;`A&NP+0y<=e} +3Y{9+v*utp>emEn#sem3Po&GNC|#X6rU0*$(V4Zfu_C6+d7s7f4n}ZcJFhdvksngT>>7;b%IXx?i`x= +V4qIdvOHAwo0?JYBbY5yI~YsG#{!GszQLtCQgFq6*$kxk9Jk_;)(Boq#U?iIzF}Cf;P8V<0Q`p=CMI8Y#^Q*g|#*m107h1-?t+m>*&jCnZ*t;m6%+yebtpNR=Wm +$HGW2Fa72n`|O7Q^Qi;5x^`Fr4@cbBHxszRVz1fu^=BHMjd)JnsThN%liW-1){dh;&2?y2r!YyU;uS0 +@vBhbCs~g+9)bv^L%bVZkOy0*E@vPn>SCVkTza?jfoeh8KF;Z7g@(1Gfp~2%;_9$FsK;OXYKz>ij0@; +0nMFvlMZpK(`<>~D`(QG6neHC5R?e!wMRvMIeWltIdZ+8r5Lxok#?<2Rx}#thtqqI^?E)X_)}Df*LO( +zen~^xC15LvDgynT4#fD+6j#uM!IRQYl-*@pZnNp4Uw3iSFMWl~F!y}I%@?ocsZ{=zY#UJ_y6)gnl{~ ++aYZUC2s|G7SnT)g}2;AmcwA0hPpwab=*HqJIiFi+cezuz9zOZY2_EUWVN`P7lDCzIamAI@v$8~RpVS +KG~3jD%F5KHC`mqIBl-$=NFCC>Rf*o-djpccCdccnb6W%BxL_egOUzHpDdM?sGO%pl^q3tT&?HeB99m +#4S_ubcRJ0edmL{30w6CNM^2q=VV8o=kDukVwB(q58~X7_!ij5*+XH4EA_ej5U_xYjrawXzS-kE)67W +=clTWO$oTm!AgS!?3hDObp)wuw<%+nV_a0(kLOn8GF?Nd_n^vxTXIzzW?Vk>0)~b34)_(Q**%C2SkL# +|?7<8`h>F2;yX8eJ2mS;>QohrwsfPiG^T|nYG((@d4YcOkfKJ*O&7%jZdfr{c5pkTv?6cPao%?f!Xtm9xBiz`TQcmvfS^DeuL@R;&`@vNUcse9ny5g(6~ckvF8=KiWq2CL#>RUewmI;RuxKOIkO1Plsu +^_x;-GJcy(rgNAUtPWO+fEyvSIlqMmdfIsBhF5WnwtV#4C!rmu5iLLU0{-*RG8;SNs6^789k*z^BK9O +yRjMoZdl_T!ZRR~gDhOC;9Kq1}{{Ag1Vbkp9vrp9H)2Y=_f_Y@$8ak9OXW3s$RP%m?s +ENAN^-B^3T{l0};9?pj;7OhCJ~F;B^gF+xiQE*OW?tY96cO)9*uAgdp`IEr)MIu9m2ujg+}KcS>P+3e +Wy~Gwe(opd-Ifs~3|$s%!EV{o)z+N0-}$&%Ww;Ms8b1`|_mP5bUQtee4ciHGQ^eTqVwu0d%<+V3wUQ% +ww4_|Ob+20#QCnHriWPLsYVH$HIBHtB8O`@*=UFQ2+)QoPnUv$}PG!EVRNQ(?jj@37p8Rm7zt +*^QiYV|qI@J+b6_jjXd{Wopt32%MUZu83zU3Zl*`0(od;C^sDtWfQZ3zpB%U#^Q7UIKM8hQqgnEYg|f +!*kkrZRU%#U!6BzacGJ^(~n$8e|O}Af|ZH2Z;X6^QdcV1wDm75)9)nHN?+_yYev;7jWqX0ay*K0#VU6 +NYr%EnRc<(Nlmm{usdIXpLkF<`15ir?1QY-O00;m!mS#zrC#iAl1^@s+5&!@e0001RX>c!NZ*6d4bT4 +0DX>MtBUtcb8d9_&WPun;c|DM0X3YwB^A%(I5$BC16$9Cd`D1uGgX+oJBJFP_;N4C>a>9oK7p2tqwq% +CawaD0H+eqMjiiy!0r{++4woR}#!go!-oN)u5wpS(2WW@)CfBy%_rvebl@j8p|Rxl}Wc32l@Z*9MOg- +}k*-$r(x0yf(GsX-dSblFAS|*0QJ#Pu)5O1#^J{J+GmVy8Y5i?KwG>sFHNfOD0vK#ZxQH@F$a+WyL+u +sO6bQ;K$MzaxxL+B*|o%i%Cn)L}vbQJ5;wc>3Y}WPZ_TaxwPaTl#;3=6K%-ktfD4CmY)>8VPGbUf@c= +3R>Vj#0GeF@&-V>!!H|v#744F<*4iA3iZZ6S*3YU~aqQB!Ee5Hc6SbumvFWo~l6EH%RoZ-#^Un6=&HI +;FN^TZXJ#MgEyIpS^14yf^2@38qo|6eTsWz+-<1kv=4xyf+C0|xM__Jb9kPB%--|_lU{9Q_{m~HBZ)t +BN>FD233gt;gTSK(O7B6hY!(aV{ERR|?m=>Nx6+W=DJ)CQ`bDu#>mPpalGd;S7rY>>t(;D2!qx-WEONvuX_{&(%3PA)&PjL_lebNHx+a2e2+%s>F3zAn!ML|!x3nn|q*~T +0;~pB;3wM+VxYHExM;W#G2mYg7RGV&hZI*qm%uqbEHH@6J3ePd8yYWNp$k;U(-s=0q!|rtChK0_iU-*G8w?B{!%|o}L0~D=XKj6zUl0A^S6a{*eL{9f +QGPxD-pQmW(6ecxiaoqvw?Ep9T=OMr?p`nr{m>3GkNAOb~6AmDfp;@1VJ6`8lWd$ZcbbfCe=wC6of$- +zT*Ll^97rfBLw83Yky_hU8Qf&jYf$`kw>E#&8A7E{8od-AF@=R0Dz~)1hIFIMCOYf?-g}Ju-hA48xMX +q-aNm&uIZU4Wu)XDcMkxHw089>lG{*U25{04Bx`9qvL~v2>u=(kk_xt@up&wIanP!pSley#E-^a9Lw< +Utz*TLKocNJTqrLj*QAsHJxnKZ0W~)(MER)K9!!m?^x0rA5oTJCaU2>{%Zd(QL>N?cQ4D@LdbbC+P*! +VOsp{R)!O6kFk&}Oe!DldHLj3c(wBrxXm~N^fthPDOPMjGS1LyBA|He_%3i!)jB(WP(^;FgcBOE3ZQ$ +y!pl8GdAL6?m;XNn4FQe<@J3YFYXxpNxxkG9?sm}*?YjX8iy0gNtIokWn3cEKpU9(^2LU5)O8P8Q@00 +xNYQD_&Z}V_c2W+l$fl)j#B4w`w`p$%vN&M#*vKklt{+u_)07cUNR^mKBgNc(%?ftf&T^2ANK&-M_!R +zP$ePj2JQFL_$GNdG<)=by0Ff$D$Bs32miDx3wV)jvx>w$zmW$YiPIpFfYIkbS@DZk?W?`TCptPj$6M +HK(n(AWFyE^I_KnT>+IJaa~};0hE=f%N586^S{v*(){wvoBCWtjvVc_W!w+u|Ip_VZ(d7<%M>ZK=>0Z +wKO72BbSV)>OM5|G0TQWX*WmByu%EhkXXq|0pmOoVxN4Qnhu8RF&PsukM>u*S98?;fidqXrSe_3Wl%{ +W?$voBS$E}dOixKOv_dIBM|@qnkpWFWMz`Qh7> +0r<;n~t9L^ULAcLl>rYA7I)8W!WR0aQiSdFt51D%e8|UUApA5w?qL$C3cq?HAL(ozY>k7bP3XC^pQL3!9eJv8D7jW(GsvxY~PJFUT0 +zj=)=He1WpbMJrRoMa9=(*a}8s1(uA-p<_*fBY64ZKc@Rf7UJC(_#)YM;&~ +lyMks%}c!NZ*6d4bT4FSV{~J0Zf0p +`E^vA6JZp2?$dTXmD<)E01Z^6zeINFsiY~>KD4Qvn(vh^iTQb7}fgy<%2yg*V67MSi{knS|7ytv3vb} +q|Nl-3}1ZH}A`rSPZp0M#U%ozOhn4he-ESa->$=S^|UnVh&lEos77p|Yg^Kjt?p`VM7Y?TC?hRRd);wK>Sr#U-%lbKjhUfQT0MC~^ZU){P=I#4#Bg@{FhVJP?y_G=d0o +lkpC1y@PuS=kV8y0~Ul?o`$nc&Ve4Vhb)=rfH9|sVUCCgiN9I#I0xhb6e8}$TejY$>m(E7kRHhKrcA!{aw5DpOYS-0BlZ_3dFaFK^_qJr3uETNw%~EdGg<;C0-#v}lqVqdsWb}NQ0% +)36(D4r^*Tv&;C6Xq9lZ?U7kev?LSm2_CIdV+<4DVZa14NVd6*$EAj^6)i$Wi{3n=7X7~_2)y{0iN13 +;wcX-X^VWozz-^U&|GhcwJ{9!r5R1Px|?><_v>vQhVM{Tp`CADv%y`|n4rdv(P=b%(?5VBGJG*r)#Z9 +UJ!Ec83>ie9gx1`Xe^Fz8u4lUWfGu=T{#t`h&Ls4kz~C-(2;37bbw~OZL7uJbwpYyWjV(`r{v2cW}Wj +`{O}xGy;Jiu)#I!ee4a!Z1fI*R51I#$FBO_@2`67@_GnU;r>nUyx+aT)i3(P-ualpgY)absQ2F=017- +}7v1;Wx48Ha5raAE#;14P@#q>>8^WeWAFjrLJG&fSzh_t1BSQAW2=;Z+9d{Ax&F~r!9d%${Z~U%@&;Z +{q{5v1_uLn3D79J1bYljVbZ?F1qdxP^HPQAwQK(ZkW{4kOeI;=bFk8sWF4`ToZ^I<4}1So@^fJqdG$% +qNz&>OjJCP68(Bmz~Oitk59^1d=pOAyfrtcALta`h?O>YMp?& +9fu1#2O65^q$87h>;o@J|4jy=8<>D|ML_i`e*OxsDFVhxa`B;&j6~6wknLc)B5|Z_ws+H6a4?x%Rf&i +&;Qu!;DCPn=;$cmb9V1VVK4>Vj&mn#pB^!|Rsf`c=&ronU&2Fr7S2hDR$?SxsTYD7`RGL(-b>RYby@= +$;0egeM$!VH96UW`&(aoq#w5Iy0|{d`PB;9BtRC6<`6l+sTES<)GK_`3N;SPv +lO=~m!Kgj6#n5vTr=`*&CTo<~Rg(dX-&_2~)iK+Hqx7~`A>|8E!j21=mi$Z{|Cxp>+Eq;g{jZSWqbNl +*1{9>H8NDH0?*lLN{VVGP|RdKa5_r*wA!_AM(1DVv0OnCUo33Fv%bbHeViD`XS}jQT5}9yE +0?^|XnQeIgfDoC_SIvp8p7t)5+Z}fHeNKKD&-};KO$M-;9_Gk;_>2#AAVqdqXSH(n&RT8tF|3I!JhPA=FOVu-<{3!sC8#E +@!oe0O+2+v`8QL +4J4{_C>!&i+KILnedI(GY320ukuZX3CUZ%mm;-ivfRa`sNup)qe8`j^dJSc7!3Ka&AXD?qjF|su7Ur^ +unsS^QpaszZ#q3GFHX%s>D_A2!|&;)*DZqRDFU-FuFWRSn`V-#FHgmk`K5zfA)fTWmT +@NoB0e#M%JD(q3wBc_{@b}`ndD+iyeSCj#(fgr!#;q~q^Tb%D|F*wlq2PtapCoOnj5p+5XY7A9$68>l +TkMqnsxhrXkXrtHL66~YHKzny8Ye|^2O+d8<5D(Hy#*Q?1YEZbwC +am92B@$XG`2RRwt5u{Fr-KZhrV|RNV_&cmVLU4UPk4odhOfQlh>CfjGh;Tm4-T$e%@jE3~9X0To?<2J +5QYU?d#J?X&9Dq%=*u{7fb6;!t@Laa2Xa>oD3AET}JF4+>r0V4yV%&eaTbL=XeS-odR4!!BYFVFGSl= +aVg%yEtN$4LKsvX?4=|a82-U@Fp_xQkSBf;xu&p6su4Go21%c%mp4qvmn;v{cPyWwvm$u<=1K{@X~1R +06epD2@d{lrra`v)nZdK;4>8r6j2hIl^cYxH@$i;XoWK$P+^$?62Tr>p9zi*TfKiJy*{m~=q*s&jP(1 +bt!L$Y)0$6$m&JqyB+jW)EG%>uCl_Vxkbz5JpXINX6Hj+UM)u-`L1rL)GBXr`Fj9>x2s6|(6+Zf- +N^=&;RNbK>A)IZ~#Mv}W6$+g94d2N(Yr&gCr+A5)7#WL%W);Lg&pmU&o_+ir3gr8C8X~vH#Lcbh-BFR +GpKi9>-J~6lCgms)n+WqB7*VoO$M^^;WQ#xR6pQ4h%9rFF_?SI^r*3q7$lH^IdZNbcLdV<1LpfEXgqb +V{(GHEUGxmCAIMWiCps^(i%78lby6k=GttRCMG=TcrOP!XRks8rEW!LClA#1p%BP@LAo9I;OAd{0DKr +gbBR!L?PIYx#xrUY)dhoFL1*I4pW|%({8n^#$@Sbv|+!) +S{N-y(RA7p8mbrk}8LG_oYz;#9R +bfzR|P>}^_PvIy@ucZ#C7cat_vy~9LJroUmiS>Ud1DNgy$^XCF+iEM;(HDgRE1MH|GRV+riSOSBnsxG +0K6g06|$DCb19O2tTAbp4{{2-pzk{fg@Ugk-*Ik#E2vf#_A7W$S_RjXR&s? +@g%;a3e0qEg@)=c+F;d{df%-Az36AqB?%G2z(@>q=+13VvM~iJFzvDp6H@1B9MkKrd$@CM8?a>9sOZ8)Iu@yytJT3{P6m`Ac1l98O{?tr1py3IHn28BBW@j~k#&WTra%xqJDynNd0VTfl +AOJ0<_1@o%f1F$(^xsOVdIVaoz<;jMMM&vsv@_iZzkAOMaHe +IT{YX7bcyj^fYq8qH<8Mb>#ndXjU$(G~*)9XEK!D~2EFFFEsQ@G~mQaNlb*P`v&X6x)#9<5&7(9jkhtWMvlDtB6ywxb^AlUf)>*j%B%Qi(+K*}OjJa~dC7n8m~+KS0SX{%@3e5yw{Pq%417W$P1`6)82QDq +02h7&g6kD#6bNJkhER}T;hfCbS8PwT9eFe;KE?mk5<#EdVI2{E%#An37E8ueS|CgEvk3dM +md+GW;TTNJEf}#Un_DYA2{V;v^k(t(V#p&x8^ie3TT;@H-25Q{etN5u;|1PTNNNyrB=&;DYF(p4_ulp +)#DN2`)T4-So&wVM7;^=gk_L~aw*^WGUZ;7v6UxJ6V?g7hLEau`;}_}pclcn=y)#ahwc6JF54kE&;dn +;8(H8wX|h=?#oK87p{yt{#xft0Xnd;9UME0mSTfo=JRrI)udNNeVlrJ5U}7uH}?ps* +5u>wH}E0bhQU?>DSdejg^Atb+V(lQ&LBlx3Q1-Fcn#GQd^Q5Pq$VF(Nc9tWj9%uDsZTt+--GbdX~~3w +yq(>ow*)APJapX-(jdcw-Pa24>R6(fcF}WSof0`^zv2w4^84@35wK2BWQIHmZ#t?Xpjz3@z6toI-l>l +zUldu?S>-=b?BprMz^Vii$!mg0}>m*hAFccXF1HNO_DCOS_|&MqRg#7tNR!$>VK3 +$;bCHA4ohmYb`X8+hjI)ze*aa>OF=Q?I;dmXN;mgaEm`WyQ?wcoJMz7u@~&vJ#HR7k9bV)kj0Lg*$g} +0tju%ohjA|>%4=v-==u+J1tw-l2(yFlRrxg+l3}MZiVU9GmnLu#YxY4?2NA +DcQ8`=-Pp(Y{@4q<@JhM{ksZ4Fb7fIDoPY*>~jYq3s{&}j+atGtl~(!1n=-}AI1qZL^tXf}-MjMrX-WkScBiZg^%{)YdBXcl=Q4w>cjw76>1e72iN0K +Z@h1okuF&LL}f6Z7kUfqSUD5#58K94J3zINvln|gAyANQDHa8@F@%O&ihhwx6v+q>zrixz@3w#^$y`Q +A7td0#9bTr+z-UalWuPb{9n>{YWZB}?ar5l7dhCl00!?R>vcEv{{1yjKP;^jjv45S^7O9UhwJj~Qvf2 +J7i0+K2Hl^cL?Xe?+WMMGu=vdaETE{Ai#~0Oe+iM(z42ps+DU?6IvG!8+1 +Me+z=KZ3(6Un#x;3^JKMJGbcs~g!lGi`-p&;nIrRDf7~G4W0M(?fE{czUeQQ#w6-%l$Pa@`@D +XI8cuGZ_>NK#u#*J@yb`se@*DQ?U*TqCEH?oz81Oz9A~y*(JUGTwpOD2ixbrHWroTv_Nb>4mp|SgqDR +Qi;u$qsFE-l^~GB$s~2eHw-r9{W77tfv%`fsZNhq^ioM4E?;h1p;s{)tF>0kqky}B=Vie|SL=nW6i;s +F6RQC_#L4V(E}q`5SyY`H0ccs!R9){dNz*6tJ4LPV4mJY-_iGvi!l@q~LSYb?gu+M<))d#> +mGvQCi1IeON)~&N24?`0pB;p=8rzJr9?_(ZgsXn`tvY9G(yikMxw569_K;|vB6*11xwkqXlCMYcqHGT +9(huy3_@@-X1FRKEJFQWfyEl6Oc9Hw;s9lim7AdhJ=8GG`MoRKD#Ba^?Z}#W%oprDPMu4n7l>i85DBs +Mtyb`DZ?e8{2bZjAc3Mw +n+a|I1%48dVnFu-wa9IJ#OTu`Ha)hQ$gw#m$b{M|&n(f$gtw-S8B}s(PeIK0M6iiijfBU@%09llY}ko +yzR5OI1R&9bJ|CMOd=uP!Sd;s-Z_2Es8!F)u$W!*A&g6T9PUi#oNz@zLKJ4Sy=XWFx2zqqTkt4 +DAjtYb*rXTmjR^?jS{7nAnMzX@J{w$Yf%v}U6EB-$QM*UD*oLDfSjD!M_f^gIgmyDH~0JE^|CB7btU7^o +^Q`X!b_-d`zxW2d~J0#?*_U`zi8P)h>@6aWAK2mm&gW=X0VXS_iG002h-000&M003}la4&6dWMyn~FJ +E72ZfSI1UoLQYODoFHRVc_T(96wFNzEzN%gjqjtx(9!Eyyn_QSbzDbQA(A13bC7xZ>jzb8_P26>Jrvm +B2DeItof4Ii*-G08mQ<1QY-O00;m!mS#z4PBLxb0002z0RR9K0001RX>c!XZ)9a`b1!LbWMz0RaCv=D +L5{*O47~Rhxiv_u=`pIDnT;t>f?af5ZugyS5M}WLx8h +_C1GZjx=dbmq-xv!{hOxgLr0{Jaqu^d=h^qX+c&Dz;78>gL}2GM`7r*7bOoiPCnoA3z_uMd2ka~IauY +J80IX%u%Gv6uY#Y3*Q=bNou?*lzw-s)8TT!|v_$m?bLjcLmgz;aIEi5anqJ9PP&Z?Qn^DUI@`I6(u*) +u}aPoGs(!av?y-E^v7R08mQ<1QY-O00;m!mS#!MWn!qV0RR9t1^@sT0001RX>c!Z +aAk5~bZKvHb1!3PWn*hDaCxm%TW-QI5d6<6R!9h2igExXF4139B_Y{>OX5)5P@$@KuOA_?^JuA5f9~w +gj(5k7q7o}8PFS2%f$vu)utBaQVO*-buCYu@CY7Yy2=r-~l#Cxus?p&RKukh%5$zimD&={Dv1LhaC?sn+jrv+&oF=Jt7CE9y{kWxz$NeeoNm +v!|49aG&zt?(SbuS+n1WiWbtD1l$X!V572}3A$ejyLV6V%BTsIGzoncOs9;M4QB7J72fPU32{dU1_32 +5klEgy7rH#4=NnX((5a3*;LG7lBg4n$^-|Blawb9`v0hAF%O_nZ86t%D_!Y-F~1T)Y)^!n{;gaL8RlO +gS|b}Fj=2=F-hpwU!IpbuZOpzmtya*=*M1Fl9wg%0yL<&GptL$xwpQlBmaAczb-I_!&Sj4zhPiE=pMU +VT(B)q4|hAI;Zrh836p;OeHQrkVLaHEdrLn2cRO@bar(w|y^2Kdh%DL0`v$eS0>Ye^VW4xCN41^th~F +v>2x#;TP)h>@6aWAK2mm&gW=Z)XGc$k%002r9000;O003}la4&CgWpZJ3X>V?GFJ^LOWqM^UaCya8OK +;ma5Wf3Y5D5xNK&-Ypr%H% +ht86HDnnRyGm)x_{ylVwvhSv*{s#`AJ#R7%M%6lpb5vUK{F&3a`jT= +kl@vKI#T#Uj?_hv3WZcpPXZ_B#fqSi$p3P=tJkV^}S~10=d~thm=J;n>g0KSCY^?#_AfB;i>5k>{o04 +#M{IV9Z$VwrfjsJkmQR7U>^0nEh4e0RQJc|mI-oW966$<8cX|tEyoO}@&4ctPp{KQKW?C-Y#WtQ`N3n +vsLWEm&PV%Ap@PanLXhaR71Ek4_En{N?8tY&UotOIoyJ?=-ehBQ~Z3S%hlut{ow>wN3k6i}hRK<2MUE +l{pk4RxR(VnX)AB;70hj9$tN*iJGkMCf$OO|}Ee3vPKFo$^oZ!A40(HKaod2a6kV59ENvpQ60wPk1n6 +QhM~s@l1rEGj-PP9U{7g&1M-9f<9hQl~=S8)5~=dUIml|i{@+g!9?tX!+MAM%;hd$(GCCnd*+3S1doH +@?jG;XOgOcg$b27BmqW*=z`a(#_6xwmO<4TfmjwPUUyhCM +O8w;Ezs34>TU+hu3~#&5|AtE^9)d7++gEjYK?Ui6~~f-qES*KJk(D4vmpb2Jc2O%!#7+w)r5@5Aq$y2F3xfsv!j#VDHp<;i%t=dWg7%QsP7MYr +~JRHf&xeq2Q*JQWhbVP5OM +%(M@#uo*$7?bTfYQ&X?v2uqR6iq?Dow^_!Ls_k4^JHkxZ$&X+{uGO?HZvMcQRNcU28;c}!mzVGE)(+ojAhXI1XMa +9?p-29rL~+3qh{y4*nSqmW@K_c!74PWlwgL2p*^2=%I)nFgeHe5(6?q)>47%%%;RVT$h!>9Sf9e1lUA +@B1J?niA|Md+0m7?Ms9)Fp)J##w3 +q>W-4g!>K|c0yqE{{T=+0|XQR000O8HkM{dTxrr7fB*mh6afGL6951JaA|Naa%FKZUtei%X>?y-E^v8 +ejzJ2Z);5XvABzZ8z0{)25AOpXu}4a?zK2zdq#Vhd|MU+^{1#@_#0ciYINpAD_+-e*9&Y~ +~M8O9KQH0000805+CpNgUve3TX`h0G2KQ022TJ0B~t=FLGsZFLGsZUuJ1+WiD`ex8z&#qxmMGe#PUR)v8CGTxHGmxLnKbeibpU2sna#dfA8+%L4Xg%_H_ECH;GIFyNlh$zOdlQ$;slC +__-^U*o(T=Y+F`>HC*YkzFnNa>|(3ro@Lp#Yda;fjFtOFs+RE^Evv2-nR#Cdr=osrMi4b_wruov{O}8-Z(Z0pK;C1aAxSuqdPp1vlVK~D}Z*(1455k$U| +L8UO0qX(PpTeESGf)s_G$?_!#Qdc1cRhRKUUV{bKR@hab;hoM*4j0Y-^5m +-`0zTB+qvt6keRzv3VLE9xZKEY}Efkt}|=eDUJ^<@E&C>Zf1d>Ex>?>6d?4CP4ikS67#>uFs!kmsi&p +moHxIKX0|YuRb_oQ!NUV^m(8Psisc~ +#D4}XTH;wx+3j+Lp6p^mhd^^^KN1vJRVBZfrAto1|pXAknA2ksDciBu~-jp?0$I*-w2}AF*&-$s +0aDjhtD&+MQs_Lg;qM!1BR~**&j1F~dvt?ELjLG9*_?idbwb6_c#2*(5wHu_(lrjU9f4eq8gtSTnSDq +0U~)8eYJEh0ZXL*a6G4c_Tq4ej0WSpgaxd#b?hk;I0{2RhIL7CkQ6l5GBYrS0Gt>>gi7E;H%%fyYO +V5g7*lgR2WCP^yuAf>|Y?_m->n>}fK_M42)J*N;!YmAAE2Xxn?^N{<5TyRre#yA=-sTwtok_(*yEyx* +Kpv&5OSG&ZUzPYn{%F#SxR4|7(Kp$x}h2N+ta!NwxXe`eP^h+a8I3)NkP>51h^K*e6){*lZRt8?pl=jK@q5glOl-FzZ;2XLKpu|=lXZeIcp!EpK%L9Rl +t-pg=Dq-EP08Vk@*pMf&WK2r +VaBqK;yRZ1U;xJU_`96OQUx$aSBT*Vw1SH6u{qk +E>P|?|O?$k)9%$R);%b_4^X_ggb-ews^sc7Ua!o82N2kaOSqu?Q;$D2F)rD!vze2CWQ-Em-F>*)eBt^ +wQ@pSg$r;2SU=R}#VV@Z{hP4|1?=TaBzwRK`~N&X)eKS)mWBxeh3VqeFZjUVmTrj@?-Qu_SN5ejgQW! +##<8V{(5&A_{R{eNv*&kVfhhpHh;-y%eQFVS4>di*~h +22?2g212d4ZX@Hohh5cF+M{pGi0`GG;zPFE)fQB{BSgnZF9(NURX+cyawZvxD@_{iQqCaSuppc!EJo^ +1sf9W_Gb6eAe+Tu&+WVgYElg|hI#RWa@7wtw6&Fx_7sc(5IH>ub?kZAFIxT5MRwy7lA!e=MN8F-!3w- +X8p&oSqW)sl!IGq5c)vk2IG^<{04%V`VOqP@yMda&*F=i@=mU>jc&s`Ht7Oc&}F5E=MDE*-CZ9qkStu ++Yq2zFv%%;l>}TxO!4|?&uZz(_&h#&zZHYoFh15?c)#*_+JnEJuE7a$t&ToVgA?>Xss9rVb~VKJa$Ab +x^Yqu_|9@%EpI2kG*)yb{)pUasA-o^a@|SU#ZzV7Aug%(YYwY6OvX?r1SN#48r(a-(fDs)MI-|PhN-NTn +DaGVZVW3DyUN;d6%#YN!?_Nhaf?pc8Qte#$I*HKcInMY9<2)@Pg0%(o+BRKTu)QfBF7JJOwsE7V5G#=$(JWI%--y$(cZ#QO~T39$jnTDpKQjLaEx_Qyqh+8dBmk +D!7@dV7oTTQ$0$nlM|VNIRr#jfYSmypfs>*&4(gfyOu6yV(8-}`$+V+K)!b`vS@mAm({Cj-=k>mCQe% +QU_tOn;Pco1KPTN`&E9wA|glY2oc#~HSfD44r$eE+O|TG +YXf7I==%rXA6<{a3ryWz2#44qsJ+$%-d}@xgP%ATIVj#(GStgMUOSNBP&5Crn6YX9{f5er@JfqnyJmZ +R8`zY&Dxd$PY=z*#77>fS+e>s8p&6NRYb(=th~8%Y2GiQLSixXXV320{ZfP3S=-m)??@QU4>oT@765_ +G1hJC}>?3(fJ0y2SEa1DsKHh4Lqwfs(yT9KkDNPKEm+Sp?p1{zgD{Gf>JI>X^jLM;w7)dz!5x?i_V0$ +LX2w$A?Uoe2Z|hjA$sSNSdsvjK&V0dr;o)g6RXnv8aFo4r)FqZuu6!`v4bAtq(tPzaIzx*C;}0Uv*(Wl3-%rv`6C!v73F8*VtVS>|S> +_tL4&QB}2GCuTi---orVQFbepcZx#kh0O0USnmmg^9!DytVF7 +9v^<4;5W15ir?1QY-O00;m!mS#zTZB@hfEdT(QwEzGX0001RX>c!cWpOWZWpQ6=ZgX^DY-}!YdF6d;l +iS9%;CKBB?C5F%MkMs8#9K8ElXxxZMs@vAN%r;bN)s3)n=`lq0R#YNMEm-`-}C5qH%N}-)Na+H5}5;Z +pMIS_?>@cl+g(x=+x@ujMNuTxu50@-DOW>V??+Ma-wz(h_jP-HT{YM0&vsD1dZB&|H~X=w^}q5yUMvBde&UF^iV+E$_;jug&!W&aV1s7 +hbcpT{cn;_v&a7dz36y4LIFwydkoTk~n2SbrP?=gjK5Y}%$;1FWA!(Ud!JtmZ9ryJ{O%_uu)?c|y~hl +mq`LWU&wu%woQ4Z-r@{7POOVp{5>c+}#LKTdT8fcU?KEYE3y-x1t!vex6*55q@myYBf)Oc>T?bZ-01a +s%_f4rf$oPs#p!hzOUyA{8Nl=0U&R%_u~!zMPHyq*{^R9JRze7B|fc1H^Q)V=d%Y1Jg=K!EbF?&PcQq +vg)V&$XzjmzFf*X)c3nmwt*WNz4)dhnH@Gi~eX|jLaa;A{zN|%aJ5S!cep9@7`PIwsUKU?}@%GQgbV?Z@RiX$g%gku@_YjQ~cy!M_T|8{9qO`nssAhMVBJfN^y(>{ngi!Ulsfy(l-uC_are@AKqU`BA*0U&Ri77OQ<#Z@53A8 +IXGEejp0S4vLM!zIoEL{f_aP$I6`>3Y`8Lr^%bA{H7dk3~v6F{_@LgMAr*mK2`9oK%CyZZr)Vgv!_2W +RrBjfN~#eN*0vd;D?!0QjQehE+j`(3s~YcKe)s*G@4o%^t9Qk_zrOz3uePsL!L}2y0A1BIHdO%{g8v7 +kk~5`>Yh--`lk`qll;d`-=K_A3_p~?F7aV#)Z)n|MA%Ebl`v6A_GwHumecF04h7KZ?Zo9Tb4hbWgp(Z|J#SFtH +&R%X8)4%mY-2+t`AkdX&XUrs%^4kNchmEXxc)T+vV4NyYI4RGhHV5_FTfQ2XO=vzIZ^Ndsy?n@k-1kT +s_`$E7WlLKXSmbHXu&saIM_b;0m*33k;5a0s>0#IG^jf90oy%VN@^ST<`QQV2C=C|Bpb_DB}~U$PltYxFvzmyPynfrC6j%(DMzvVuHVP1bqC}LfO1? +Qkz7?msz9EB${Pi%Wzx-GLtu=+>vDY~Bmm${fM8|Sj0|FC77|CE>s8DQ9suT41MQ|}Ei#%K^`La1=t!kXGkpI$qdv>x%OPE`RmC&GdUFa74b!hj=P +LxfuT*f#XI_qo}E>Bs3uoJNTEDHTXE>U91aFLYqLq=tNFt(q_Ca}sXyF8W{V@u)_-{WLvDL0qJDb)EUZljrL4c)a!4PrA^hF;6|j= +BF62x6k6W5a2z=rn_TJQTH{%iR^UH9$RjH*aZ^(RrLtX`i@whhp)*CU(K~=M5!PDkB_&iL$yMeCVwDo +34Mwk9j`Zg@=?=>Jb+rZ+=B +|R#gWds9LEln>8_8!1-5A?s0J0)z(ARalDr@K(2 +z~JKfM_Z|`Ot=&c3*ESXgB4pNLE5L$r@Gxm{Fd52@G`I_6SVYR6PaaHQuzF-0N|*5rFMSx{S<^Ctm1{ +Cc6S{OCGxMrjy?SF#chI0|5{xfS{J!5!PqeuTenX?(4+XYFvQwOF@Oj24*pwTTjkR+HInRQE&B=3|U0 +i4nu{*>D#(Sx;*nnVbu(7rJWJCJ+kY$B`Qpd!~^qiM~Z66QcG=I;x8nY^1jgWC-SU9A$qp12P0t?o-isUIjB|c>#+bGW +=i~{=cvdSN{ACsj>wH#fkNf)lTx6*LKddWpk74g2_^j(pkMVpkO5K{(7K`r?@ENuBv@m1#8Uta;%M2A +1JcnfMV0L`^@J~nzgw1)41QZmPsk1JdW53-Gw=-*DC!~O0ZwQP=4WhrwI(s45wIqK^GQ98m9SRF{EQX +U$e@123MmYk-g2>8HYQoWEin$@_=`U&v%t(wNQfSYnY|jMFhbQ+8x3aE!!z1({vzI6>AIJ`b#Za=B{5 +KtXPStX${VYcy}G-p);Gzny1p5a0hZRNEmNss=+N*8&7y54CEE*7#&n+G&R~GRiN1gPRc?3ZUR#>9LN +qQC?t6QU#l!+Nvt^Qgo}@?imsd8mTd=-?T7?a{b$KX8RK>sZp{uJgGgarwvst7?OBN7 +74X11I6K6@j<#3*fuV^I2Dquv!dh_mvXsMn9+hrlux}VR|EY`D`_A}ZNvfP8kWw(1__5q +7=1o6;BKB+`#!LR`75M{Pz`|lSvNyXCCbAx&s;!L2%A98p0pM(P}ME&~$8V=p-}=XjoWx+wPl9j`}$HKw{-WOMtyxmJOwF +YmZF;g&n^wYfIfflW=Rou(Eh3!;goQzX7Chf%1xlv`q2#xkNn4{G(*dPhRC~$tpfs(Mm_-IIBXXwJYO}ip$l`?*+vQ +A5k7mnniK0C&}X`?513>ZCk%k~dv0UYhSo(0Vr47~K`#qx@HMNfK2@NrDn9)L55$g%1w57wMF8&Dl8Di!Oq6vSj+lM}st{UIJXB^FHeTgl)LHfo+5Zsc%J*E4S)gW9e+}TH|M?BVF6= +al4Z#U3&AjsK)f@dAsh*jhHK{R)yZCx7ak~WIZ7iNq9gJPP`gN;B1aEW;<+q^LZKA3%+CC#9VHZ +l)VuNkV_;%UIGZf6jqkZ%2!)hH;>n}sFtDkxW&YN7LaW)=TW@q&fnAB4wn@iiKd_ybIi#d+z&lF(Kz| +zfnaaR0%lfW73}l2JSxl)9b2bETs_hn76Ld^A2SaYC0rHz`P%30aY?xSJ3DzzL(F5z0W8NcxzP(GfG! +Y0Bl-_~7-nJ$3)xJlTxNDIsa<64?6PWQ1=plCrdWi8RBNPQ?80LOWnlXhOZT4n{fd`Y^v}<8Nm9$-t) +y{6y){q@q1v5P1b&--1BVdmIDXg`W=qb@MBt4ER$)a@H|LCr?+kT5yc+1D+_>}w(2F>L>r~E3@MdiM8 +l{ndD-Qa&)9^)8Nyx)k`{yIy)AJ9T!FCfdfNVVq%jNIUV>3VdJjt9NnwM;TWcoa{|jqox731mqMF4_2 +yVA4e8xStCYQ(8D#b>$lM7m){Yqtl3mvrSq5kA@NU}rQKGgjK!esWUQE%#3tBMvvoKk1Cskih +fpYYaB=|kYG{)?A$^np6uWC6dw{+Le8B)k?aF4Aiueb-1{F`F%(cnm?^Y(>@d?EM9LR(t)T{FjRWo(!7k$LQnulb)A4U%eAM&yeNjB`EDAaEDyY4W{lkb3&Vy|UTAqyg`aF#WPXt{v +M(}k-mEN3mDU);s4w0ML^I33`v3Y5-wA2;|rOBVzH2}oCUi`3l(kr0uHn>fTbeC~snN@ffV$!g1zMX+ +w~fD#_FRQgpcz4_Ja|Mm6D%jEUIdONJ?N{r}hB()9^MxrIIi0C(7-h$Q$y- +ZeoWA4U#qlO5PK=naokp4oho^h^?+eS;DEcSJD~MM#kCTgx1f1EMo>0+~p0z=v5JL +`Czz%YcLBTz9tRzAwyw8rZJ6H9J==qjexdPFX@?A*Eg+u*Ymz$g7YDfhJTndl8z(J$s4ML(4 +y8(-j9s3R@RRjOr7p{L-X=?E*L*%0#p$ApLW|!^G#o&4XEA4|(7-P2l|2#76h +;>wffbFVn^0MhI{hXRw|r;LpTr`rb!(cw&ZgBebWj!DfjCB7Gjq5_$or>aCXCifbWs}+hy6;EEN#n14 +@#Pz?4{pBo3dE_NG`rv+3$t@bpD$C0zWQ&yZ&_Q~k#xCP4^op85y<9~ +x%kg@Gs8L(3vsE+5>aTXY08B-WbQOklG@ROp7&6%vs$A)!Zbr=%w9l}yx9KFhRr +4^8mV!gw-#`lOb;*(hKNuvTJU#!t;M_{jf3g$#bhNMNqeGGsv7K^4`VC?8(y}iD0VQCi0y)YG%_o@1p +UU{VG2Q+S@{kxO#04NeKc=8eD6Qv)w?P%=bBRXM2yMrVdxNns26|K}GXi5#OW!YE(;Ls4-sP|~<^bHt +&3lp~sT=hpZRW$=NZ1!a0Qg~AorQUktTorzjWTBR>W+@G$8_apd%!V8(7i_&34n?;R)P!KTe(TTDQ9$kl|t@hV?S-h?JXcu2IqT5+h}g`(a({rE}((mj{J1qO +Y^}7xIwu#TCfI@^{3X*>-fsXn78AS7p7z*5Mo5Lmjf!3r3{(!50n1?*BJHVlS@ZQ8sNCe?L75Vfm}m) +};wM#L;j(F_xQhEDLG;367bE3&jHsExz%ZTC_$liqqPpC*^3M)UV)?6OmFWY{1Qa4fITPi|h3*9g?95 +c{E^z+9y1<)=zd;Oh}3*u-SoV*{Td(gOA#qEaQkmrR%)V1e*vrK?pb +HP^g|{k!I8rQ{k-lAz)MV$rv9f-4|F +RK|S7!fjzsBPA0NJEfFUSJofD#gLWt2WbcGXZpN`2E}uNP21$LtLT}-d?$DJ_V7;Go`?`Me +`_G=|@$pzQiXFm%Pn|dB247J82M2m$t+F}LNiKE{IpMP=JI4`t@U`mOCK_C*9t_bwx^(y`?5`!MI9b8 +2L|aB>9ms4yXN>y@vfy*pro!i8@*dek1kWC(2q{3F#wnqyC7NTb%QRY$Zhq-OYLOA=D7gY +5OA9wx>12oZJcan(x>z1~eDrq9{y^+}>Ta{>c8VwyVXhsPTKwJ~9s)5^PZpReeA;9_y^hLb{dCTMW1( +>maNn#^V~lJRY#}p_MWL$r_J-j%B|hOCtsh0ydLNWZ!q~V8@loWyU}qJ%6+0Psy_*3>u`2KB9!-^HCg +@b-7z@%H-2!@(Fm#9#fu}(=W5+akQd|%&$j0B!d=4zdCHDenPQPdEb_SWg(THEL)W2SToUfv_}*eKCBffbx#~Y#T1AI(2qw0pI?$wgXBXsHfbQ9 +FdK)7#3sOj_C$W7uB&CeS@vv85K&(Xoer@}%a&JSUZoU@kLu8^S9F>F^+)Y^I +&(RzGtF1{=qtSl2#^a3b<#X%h-dF8D)+93}7CgQZ(Hy@k!uDO`<3QV|5U5b1p5<_RRiG4icw22-n^8^ +0gp+dE$IGaJriLm2U7LPN!m_APR)>7w1=E=pX+~5hh%j8jiF?saFUO;Z~Xn4x)njB}8t-wE`B99hBZ= +5s5=mrH@4oahHi?mF>$s{m`bI5OQC!k_sz^Lj@<6*!x;cF-)Sg>*~6Kte2EE6^q@d| +z3=gi1Bi%B$_}hHyXir!P^>o~&4S_v0_7G3R8mmLNYL{M1FFyFlYImK8Y%L}AMO7B_@g?$VF7+3v>y(<_j11D$kTFSgYufVR+3=&XgFD<(atjG$pa>HoHhPjWJbmT3sGNwOY9D$Em*yBn +3n$5<2+O9ID5WIw&kNQ9YU7AEmbbe-%C4TNX?v8c8(!Kd%xWZfu|xbz6E)>z>3s=0j_TWl^gB9ak$%G +*GC!!lwW#(+eQ54Tf5J#Z>2k=f1onc=7Sfi)6J?R212HXaR1l1@xVv!(#C^wGe~YOb-$Mv6y6gdG)UeT7k$`EM~@zu}Y+ +OU7Cqs& +La>-Myn?|ACGw3-53?vX;P>3&Uwh6H1MZ-|9kOpO$*mWmNVGcCNud|eSCCjO%@%TnS>Sqn@&CJG%?{u)MG7x#3TB~!$$DwIL=`5dldKm$#jr=8Wb +!R5wcDhbIe$-&e{?N(M_1SGuD3uqfeDi9w#YBnEr}d>t9#R32)Mv?J_@i=G6TdWC4pvSKr%`RT<~EGU +y}&31UVzC(1_}F`KBo_DBI>T~)9ikA>{6Wx}_H=+nFU98C<|UZ`{}#2-la*-v#?b(30+K%;{?UD=NnQ +WTF3%gXtM5{!&BG!zu0x%!U@jZ^%}UAWlNYQ*;VyH9Ye)0ukRK<^Rda8RaRuRMona?Z7JeFMs-;pY^8 +qM|aTmwl))8y-yDZ5bTsta6cCvEhrS`Dg2A&lcU`dHxv!Ol}A7bMJgVkGY3R7)_NmM47c&dtb}tAt7g87XhYX?cpiSqkiajYdwvdhG&{%pBO|VOu-$#&Q^Cy(3#v8kjLHCjx@q-i_UEJb;HCE#E)eX +68%ph%Kh$+BROUeY-!+1~f^Ko2$PkfXi@d2-_2xL!~svgDQA=%!_b2L24zOzWaM6=oDqz7i4?#e?-W@0fpj`kmx>W6P_@uXE*iWNaFpo1?t +hodPHZhCoQL5Y02rV4tSs%!PfzS(DrI^csB56Lst%Sf8b3Y)kVxHrdSlZN)~4&g`1vit2oGdb+yBQyy4;!QSF%mp(0gNR7vcBdD=F!t7lBtVn2UR-i-YJ(9 +Mey29T^u>YsK67bgR#F1;C=gb0)=#-R7}W6E?WuAjZ%ETM%@|kaKHdM85n^=J%sqj#Ma5vTAnSP(HrwZdP +FgMYfvJb&K$;oUQP*HcUZG-ZT+EP6wf0T4C_>9saYze@dTcR$Hs*FxyomU^rMW_aYK}2w5FKcM(8d=v +Mjy-S6xGOy@@i64KCCM=d)APxNUO>C*I@1s*a?;0JPgn!ew2DEXUsjSB!lFSob^#()qXg2>R5J +?sO!1FLj%1#$heGSpLr|RwJ4hc7Os#+w_cesCXNk2QC=1cL0+qnWa0oQ^N`WZ{BaCauAEN=x{(3!(@) +P{zDWM~$K=^(sHi<{|HmKxFjYUl>nn7C^%(=3J8{7F-0IVQ_IZU#{lJ_JTpqc`cUrhsDTty4tb>Q~<( +od8fX}h@Gxq}=TR@&Qt8jenW0IBF&oU;LXbxE%D^J`3R60 +WbIi>jX?kmZo! +u4-w*>yy;Qpk!ubi8?qtfs`J^;DYc$naxZ>~(**BsUDMTL+KlWBu`azzVa^~JM+WC%c1}S|#qOF)90|!6%2%tZuEs;A?+ +o`(Qn*Or-F5A^DA$0G$sHNDGqv`Wi6^7b9wsm8U>@xyI$hgtRYWM|Ig)-+W$o*b!fnt&IJOoL3b<2w4 +lr*BlP!D=C^DGD<4zVxV$K$nZ)GFu_{K)w@9Wk`^c`lf#|J0SO4n;;bQY%xLEny0XN+l}B@UERqFe*f +Z|tG8W+c_1h9L9J517Q=O4I7%CMM9KrI3H4DKbmlGQf7;TUw@v?QsZRAqgUa=CKSvUKf{qWZ8X-tRc+ +&qrp%{J}dWPB)=?2;zSb6@`qwdpm0FXb$pbB=LNuo`Q7Bil>N2N$88;GqW2+%@d=98#d%`yH+Q3P2DU +J@hfZupiRsc~5z5*>SqzkcywC8OX7ozRzeADjL^3J$oXpn~owmmT#hn%z&&%JVo-^|J=%PIIrTlNaph +rRD$u7LbjNPH+9Cs*`4BAKLX<2Pd=bQA-=OX*N!J~PZ +4gaHvK5Q%U`UD%a$@d%LrHTD($p_v3=G;pLitS5)8fWhGI|N8dMr~mM+qDutpWVUOIziQ+X~dsbGj@0h$ +G7+zMsf@Z$A#|>n_io9db_OGvXu*=TT394Q@UW-aWCL9%M35POho6hom2xlpEI5Mh?6WcDfbVVi?sJc +>eFrDUGT8C@buDV=sg&%GsH`I9VaN(zRwI)lj^~yBR$nkarbSnYgLWLHO`fuTz+(bKiuOSe-M5Z2heA +(Hr_IGQ7}vU%bh}YUdKKC*N5ezD&>+LkXzqOo#a*L*0edZ#U({zY36XDDZUX*SdyMi8(aScGSa&V^~z1k@?KF2)R-1Vd-7)B%2D#PM>i%i`rW`hpC^w{q;3OBM4L#S7ij@&q`Xc}z6NQpyc +aC4ldAQ;3KiV$AX8wR00x?@ENG!YD8nmfR6y4(G*W@Qqsjy)E0Y_yd5 +N-y3uMJHh%kd{i>BTpqg!Yd~KJ>V$Tg>@R){!o+KTx2Vezv5GyG(b(Y*9 +dg&LPh%_Wr93&Ec**@X+r>dTVYMQg^D-)nqWGu*c**WpSN`;Q>=2&mlXd+Jsbo%Y(|7WidF +;69hxFojeRi`(CTj)oGem`hmUt&dzm`vv`$U*9;OXhbzAHQWFHzjxB1?Va%H2p)^<7*lk3Dlp?ql$t@ +Bwz4B%9=9Hq=@=O>dP}&7;D&jy)IDt-t@!Jno4xD)ZylD#N5+B<&tlr5xaNKEqVNK~b?f439;%DrOC@ +h&Q{!2N3E*LfPLMCiEvAXf0>wD+yFY%=ZK1oVgLG1n +%-tEEIOV3EbCPl0XI+E1i|Ad)=3?iGOOqpaY^iEi=uIqiV9pmgo5%r*-k1=80|+7EwL-68hgr~_qKE{ +`aBsPVZrYvTLL;b!w5vTZCe$G!>@H&oinKjo>6!=JQc5~sIkg}F}jRS`Z##pFU?s{>;Sq_K;;3A75&XHTc7@wRI90s*)^n7 +w~`<)iiVoViFhIV>L~%#L5`Zn|aE_?PO(WTsR!Oyf1~O3Xfe3poapk&Sq9-L{*A?|>)sgNZ;X2Ng5p7 +^?-4$Z|bawz&w+)x3Q%G+@oV3|{R(v}x~V)W*vh$IwXM8H-iayUMnDny`4>Cd +kzY$F +0_XC@5SGgBCYToIE-?O^|`E6ki=DK6rZeydPpGo$RYyuJouKSsn`;3h!`$33;dhuIjgYvkuVMEkKUk+}DB>Xb_ASCRYjjN`k|_pFa2Kvi=q_wcyRzKZW2Q?>LFfI|O!+GGr@$k_`zEtM!n8b~ux4T~MF)r +ud^JPujJsh^);m%XQ8Sk1k}O$l#O*wJnm-2=7}rvUQkAs*2Sq_Cl=4A8y*1h7!>J7@tu^0UkoD=`D5- +V!=SytjKNlZ1`R```LQavtb1RjMI5zY3P>8=+pc?W*kGugagU{=0pb>r#3r3Vx|!D8wnv^6m>mT9WI +DD*4b0Q8*```Xh=uX%`$E%;&bdW#8yFf5Dnjo1v4XfoHDOG^e~09jb*Eie9#5sX%z@$2y{`|$q#-#%P +jJ^pY-$feW!B667tgV#mV7P@CU7jv9mt8dTwo2y6ofG|I@YR`?Ua7u;&^PW}SaYZ;)of}Vo?XA`qFU% +G7`hszl*+Cfr+M+{fiP#ku_3K>bJ?Mrh}At>b +0-E$<-_1yv~tx_LSU3pWL9V+Lw07m7;1=GDhU~pp!VSE?Kjek-tZ+DB%j&?Suwhcg2Ixwgv8jj&|J84 +H_4iD99P?ERVrB<8*=3Kd(R5Mn(sUA|xu+G~Yz!U^u4uj!plg;S!^1JqR9FGg*PMk7ewwSKQj=>fuN? +g$9`9T&A7Fq~>AY;^xV3AoKxclB +Gf$T_@6aWAK2mm&gW=Rs=l6JEp005qb000sI003}la4&LYaW8UZabI&~bS`jt%{^U<0P&f05--p${L?C01ViuE&gnGGY#AJ_8WA#VD)LKEeg`Z0i|iCUc~^I`D9^f)EXPI^;X-PQ$Oy{jO~^ava3M{^P%^iV?PzO +wCFPnbo0$3WTb4n8^D|M)gGw&^a>jB^jiADiE&xM4E!0`aGn2Vih@P6CP1JUd>ZS{(>OLsy_%(;WUBo}YG7T0DJ+U*5dInaEB&nDe>Z% +Kne^Y`R)C#U41r?9H1u>$*@%I7n5~_UZ4i-?RHSj7PZvW>Pg(zgkU|tT*t3*-ZSpTs_OPf^j}R2G5a! +!1I6pYXF2zLm-_5KGis|hUPCt4V)m;;o~sMN9gt_Ho!vQ4?wyD?9pAtx@~&kTuQHGj+|{DL&m2*6c>n ++JvOi~;P*Mt)PYpdT7j^7AJDybIELrT;&1>aIEBAw2{iHoA9xsdGTV4EIn-J>ZvRdmx_Dn1@3^OvJ9R +Ja)I{8gDYl(H&*p;uz%C!3A7?YhyIm%2@$502!^9)8f8MEo%@F8hE+)&rw^cLcF$a=F{`c+)cwj-&X` +o63dUJDQep8}7_M+cO!KdIw0oI!Ze>uQZ3pnK{2^5}$YQ5y;e}E31GbLI@(ZGSDGpQN*Q!NGb7X|)a* +X_w{;6j|F*dJ9dp5Rw(*0+FC5S06>ku)6#y1?^hFfxUKp!2$DCUEN84w-9x7CR7WHTT5%9}nBED6yH6 +v*pO3TiM92=;48=0cE1yi0;@d`f4v>LP%7ySy#ZR^zf$&c*?OiOT^W}vPDsr72>%7q!DWZeCe5<+GAa +s?z`fJhLr#Y*vk{{Esgbb7G;ajfE7eTTX{PXRac_VOTYwWnnovMN0H{!HgVdPZ;@Jq9tf4OviK|x#K2)eswTkv`XV+0YwXoBB*%xKe7 +fW;OGC~2F!VjoQ>1BmN!v7UGi~nGNiULqW+@SRA97r(yH_S~6-WFC$KO?fIl`L_Fmh%*qk^*$6_xnRl +*q0?~KLme?Bh7|^kyWe!+bcT*f8@_eUjPh&9?HiTj$W@3DtMbJ;)%Tn2v-=gBD&UD32fknbv@;tW{+Ky&zikf=TumS&tt-o01fewM%*HIsD=2YacdjHv9O?$1Bgtt@z^o_g{W~zw7&hx +_|q23%h@OLi6qI;e06G0)KxC>N5!Xx1W6S$**j`1FYY{1LNr@;(_S?A-O0xusrQqG-IK5DCSV`0N32s +?Gtn$u_#MVt;7Ck5v&YroK7qcKCh5u)UyAvpUiw!kEgi=c&o6vzZqr;G+8qSHUvdDGm_VT77_#kyK?( +dI0H$ulG`nO-?Y=&Xj9lc+4U<;I{Tsrn+A++Ht?nnp&JYMXOeo7ZXG^#<*Gg6bJWytWq-*Qnu7uahB$ +Lc)vfstOswrU^J8Ayh6*_JXD~I!ItqTF{r~CeKw$WKYZwpI1Q}}n(o9?S1zVgCdd_br+^xCGQb-S+VPfVwDX0u8XUXDJV;=ds)_y7dn9Z?b(naKNUy$udM +hcIiSd-NLjBcNgo85-l99Wd-&{IVWk1k4jlfvLN<*5cjY`A^|;Eo)5m8&((pxEDppMz)CLassQ5vIAXnW-4+qR6}2Qc(Letc;Gw~ +u|S*~7B`(1r%~?*RG6r}JP%y2}R>0@4?JF^ +_l%-0#!4O`vurfy563KdK`NY;*dSq;RcVu&2U#;2#>rIM>vHlqVLy_Ixs{cC&JR4t={m={u3PY3;iwR +>(nOPc70O5*&_|Ee>l)EXBcwuPhVO@u=wfZzweZGzx8T8Vi~`Huv +@BcV+3(exXF+`Mp7Q8^bKprGwe9dWL_Y6bc>a>frc-jAu93V4ZvL$WrGO9DtH~R7q4-vajD2$;iZ)4 +qnKK>#vkU$mH1NMSs=y+9^r8bhSU!$V=!6IV3CG6N;6)fG`LP4LvN(F?Ldb4%=*GhZ-jUj1=mSD(~aTMHKD9(5vA?J$t1VTcJv^f<~wz{R;eb_sLB`P}IJ!u8+Gqxp{p{r$zz6lMW#IimYGFo|2(SU +@vH#Rhrz~j;3sz4NR6b$`2LJ=2Yrnh^cS$HbD>Lz^iDO5)tF`*AqwOXehPrO704KY7 +dT*c!Cp)-`tgqQ7n{#@Qq;!R8AeW3u?=GEpkffG}qFYQT668<-I&?Y4>1|7a7QoV`E4Gxq;`Yp%O(rq +GnQr>*xctjD@Z%8p>AQ1GX!1u;Hi1cy(9sw}^t$>)Ovs!7CH^4KM3xu9A{N7wki#~eLa#qQ0IVme)@= +w{Y=g!&3R>uMxxE%x4?a`YPp=*o|5XRMt~M2B-T1(~AAjyapM2IHb#%>=*S30*4eFF)YE%T!Oz+g3i1 +gvEo5i{&en8*!G(>kv+;^5_UT(X1Ikzaa-T6f=BF+6Hj`ipZ#spj)t2v>}FP<=rPMVmtAPINsH$r^A+ +%D&01scs#EPj(TdK}eX{M$p~H0LI393LND5IFZF%LHu_G*7f%k|z{D@hR0RXN +na!FxsYx{xcBg81@`RGD3mwvEZ4_W@-Ft{l1h>N6_xSm3`03y|KIc7RA8LcoJ^3=6MPOxeb0t$Mb|bx +XX`-v!u6VU?}b|F>|>UpB7EqV4MKYk2b(HUt5q>J)&8@fte=KMs8!uT=pV%Y#Q~r_Ds)BXsCmL?F*(SdF$z-CvDpbM@XSD`^SeTgaM;jitrBdn*0 +NV-C8FHC#2wsK9=7hYw_cMkGe8Lw_Fg4tn}qK+-{W{W*u}T*h*(vwyDhVQNvEIZ!TZn^A&R&VtBI8jT ++9Ef42Q0nH#TmdIQVJn+M{jA`_9q(!!hr0|lCo=S8`XvvA)!B1L!(u{K5RTOueP6p|U`6M>TCrWd@VG +~GDlZ(cCaYP-mZ8lZ6k8)40VgwP=FDce|&7o?Jk^gcz +%*~sX`z4et6cyT6{c7kNB+c6V`jNC<`}fz}0g;C%V<~j%4JM7-(*g2tNTNcP{}y#u%JJZ=nzU>6mUCe +J_<@Rk!=~0-gu3; +&mgOQ}nQ!vGDP}|aBSJs)93cdfwH37jc417*g@z5Ys$o~K)C`5+x5ZkX>eL>C*mzf#QJjEgy22DW6nV +8C_xq>TC77O&a8Mi22;6Rrs9_GbDkGRkyGTv3ytby$^c +T_2OS}U#^u|%CVtImG&OMa^ex)yLEr0R2qH$i00{J%=Nf*sgo#kxTd%iU$%;fa_9QThii<3X-L$F +*<3r&yeS@6p-9jHHK#W@Tie4C69FhC74#M~3dmoNfH-O5Ndg5(lQ&Ptw1o43=A;`@e<~D(ohW1``t!k +wKY>tOV>%Jjc92dt!xBm6L2b9BhtAwjynI<0 +5Y45-IR;`qqQEk#PP%-oyIioy_;bY|BNpS#Zeu#@sF#A`Kp_0r74!1m6f%&(&c_KT2MO75O52TMZkTwdt>?-{;*p8kSviZ*T9Z?fE^_f8AV3Rv +fEI+#UQ*87-cjIht-VR+vW>eknmFaTQo^8jWd-x2ob*l(mfO|2P%6W_^lHktb`8LsWWQdDcg^5sWd}4 +#Q=S0E=J^r=UbpE=eXmNak6p*949*Qh$sSw_&CFSaVQU8wL&zU_8r}&$c3R+Ir@DHU!v#ak$p;IBwwl +NF^C!9%gjXZ^(wM^ZfwQRa(sH#q+sjVI%>#U%_lnnmO3}b}dd#vwInW^ouP9269VFXYIF4?anyrsZfTnDX{;Qm&M@gi+n^39m9OgL8vA|Ln>zR1>lLK +H_LKAIxp?@QA0@y2z@7|OEE+)4zb{}%!+P7V`~#Is$S^}wZNu|Gl5Gu0Xdd2O=i}zx)5Fm%LEOQDuVg +wt3PxL%eBi#U9=&G4^W@>&1#W7Qgb3d%ZLObKT9x5sz5~^{4E?r;od=mGfNdMR7;%aha*}^DT){%kO} +~t3QxJ_w4@-En(a`Y*J%s_sQa*0x;fpIAab%fYWbeu?an%524+i{K3X>c6)=u3nh#$s3ZH7a^D&-A-K +`$fTHk2gZ)&WpfaehM(IO~_$;>jzy(M0+G +L~7=Zk>nVT9o3ZNCjDAC`oL$?DmRMZf4jiUx_;TKy%QV?4WtjT5X5UJpd%IpAJH@<*Zo{p+>Hz +j`j}dz|AvAMNd-JHez>xRyGkAxsQxGGY!|+TWNGN5<`zL +$$ArURh;Omotr%9b;IiYn*G98XoX$?S9rPVD8;@hO9CO8drZBe@*eTWbdKCQz+C@wbo#SWNyc#Q=g-t +SsG|c61#!JH%W}C5il5Q0iI$8M5weRKcdgE8Xy!|j=)+{Z4wyoN#dM3sSZen=7u3<*W8&L#Q11qL^-BDkkc5m>%70d@t04(6@UKbkI<3BsW=Gs)djPcN&Wd6?UN53Wf*W;0>D>Dc^#-$zY;@ +DOHGp*AVU>*PA@|gqBhu9Chuy1#4;X3+8JP`E-pf#D)?Z8FW`V~jI>mKj;!X`1^0$JS%G$&SnJaBCytBFuP2S_~7$SW{F=qwPSj +=-z9q#6}u=oDQI?+#t1jGF)}jd2YC$_yC`p7IMNMuMbceSt3S-@bi|41y3uY8>E=3oxiw$2kq*kAUKP +pD@+Ej-ujHcnk7#W72Zpd61wbx8#pY2mCy(n~*UJEwP%l>>o50IV|l8u4nbTaVGeOrad)_ZQGV+rbuX +}Qd}w!lgy4_U}{(GIgn2Ec{jxx6$X8|iiH+c^#hL5K1)Ao)Q5yycI;Wx)j3E;coZ)GA2Lm|Q)*8pS!# +$j;Wy5pHhF95UACL&y`Nz^iv@EwStGd55_xCx!l|fF#aS5z+uC9Zjen&}R-kqdI!JoCNR_Ww;3vOIEbx03I +(Q}DF-o`tg){*h6dKb`kpUrFIi56e8`N6QeO^f^_{sbGgOzx+ytZ{Djxr^4`kfR+@2f2C)WXT8?- +;v91$M2?Ie_?!Z`Ov32^#w0igY$jblHl5r>Ox=FyIc|&hQ$@YurYL0#7~s+c +(Dh5eqvr^qU$SjBQFeo?Ey>WNT#}tD#dMsb6NH6*vC@$3Kf50nYw^PKZKFK=s}mj$ +MW_7N`COgm5H!<*!sq(L>`iu(+d63tfI6;Qiiy4%J_%w8=;fgoSy6QzbTh{Unc9<3&kbrMI@3<%I +$xE8r>hYCoQ#y4_k%@C;Jn4(V{$cF+yfg}w}SXQ$~}Mw_Zf6bt&1_<62GQ~U%~ +RpTTCWjdP9Rjf9Tq&qBcB3awg@dsVk3(@^o`2DYw5#fr9nVU&vFd7>)<~4t>LaK{5@$Vyez7na-X%VL +c*+{TyVs;rKz9bwTQlLWCWL`Va?+^H@4)52oLU!47PW%j2;ZsSH)?xiBQ$fEsWU*-4h2fwuC9D;&<4d +xAVh@_GH)T;3c(6UH)abg +r|#Oba-Xby_lYAz<0F|Exp*asDVFvvaRTx^jQl^3+>^4wN6FEtS}Jsa1x7Wu|BWy?M+x_6y$UFRQ2>m +Q>x!SFf)FW%`;};>3iTd&mdc)=7Vz;yfW{Cq&1nUFZlM(0>gVnvz0srJ+cF)GWVlxw8U1J;l(H&(9@W +r3bAuH2gCv9SsipKgGz17qN^)bRY0GsBwgJdu&wvVfZ=hxvK;hiDA<7<*Et(V9q7_2k2PHpOcy!|UOZ +`N)CHZZ1(gCfRyQfp%N+()Aev`%ZUBG7Yo5I_e$f0eq2ZfVL)%$Ap2JoA`X#Pa@QRXAb~vYhR78wM9* +(VhWQTI^x+=q5zaY_kf0)kZ;umO)!T)~oe8Rsn1)#J-hP=76FI(1mRG@`U*~_*oUQB@j{eB)wYYO8JN +ZuyuK1&Ygy>piL$KgkQ6_VkH{1vKbD<_VIsjsa$sQ?+zg7a39P8ZO3`R_21$3V-x{?dg8H@vc-$*xZ? +-)SAVlP=#C$*YH)v1KzYT^@eH?UJ9*Yk~(C(3Bf6Qz;F@Z1FhRfU*nGz{`6fgEN+G=%2lOJ3f&4pY=h +#5}7PHa*=@HMGBw{>l((WGGW?(2gd@-v<}&^7P~oj@-)BsSGi;ph+paXjArw={mitz%6G|5kyD89mGw +YfUf=)u+7dPWMo}@Y=HX}jm1)kKzW)bMO9KQH0000805+CpNd-p4a8L*U0Pz|C02lxO0B~t=FLGsZFL +GsZUv+M2ZgX^DY-}!Yd97L7ZsfQTeebUzJTN3-WjU9Zg##l9_5v&r%r0g&nFr56W=m8z*Al6al-r#k| +DGyRlqiWko>@dMZi!^ESas@D72PP=k+N(CGbmP;gm=AEhS0s1?O<5x-gmq4dn*qIE)M=xYX8fyu5WnD +cDn{8_Pj4D+4a0d?^AAc +%HBTQ5Z>O26Gm61JR6pf}>#~&&wi^}11{x)o3czbYnzD+|!HbNni9?yW2f;0Hj;`5FHdaI66B~8*R0q@cU5jz53kfJI3Ix47c@UITIa-2-olZkwvH%t-*OX +*z~>DrJz>?J3l}3q6oUwTM$7=H4cJ`)u%tQ@eePN=o&e84OIYkJ;}4iolo$a$FN@T%7!D+aUpT}MRMmk;DZMJ#1&f#bVOJvau_X +3^bjO+&)xH>X@41r)lV8_xk889YBt_B_xL?7je3_YQZ0ftCMQ?mNTPASZbNf3*bViXk319>&z7R>MXM +u(?cz=OSv2zmJ9CvtyJlA=E+go=8>u93swAvR3wL@fbZLU4P~nq!HI=LGPj&Vfn&2>5>GZaxO_Fy4Kt>e*A3J5O9PYt=HxA^@Qfij8kAB}`xcmjl{<;T +55%A7>xq-DV1jwj&T%-=`ADrjfn8PcL1DC60sk!s{*@Gh=*!38w)#Lo9E6I)Oq7N|I<4;v8Rle*{tYB +Ku75xls&MfT#niwB1vV6%C0p)}y7Pp5EWeU{l63%^9A;gKde_FVJ%KV=c<&chKl8goi8DaeR$Onr>!l +yTjHi?`7Axj0|)O06JSPRvrY5nIe!xKuf6K?fsCKw!gFcW<-i66^2mX?9n$6$@c1I(WNz@co%74K|)u1u4xsVy<)36>g_sb|Gs;hCJtt9wz +kBE1~nYp#U{Z59K{3lH{B$hPT{{Pe>mTKgZ0t46n$}&?2PCFG^MnO2YJfE3&_mBqu3ol#@gxS++h@m< +6^9gqtUC0hKmj&~2c+D=_gTm4nf|W|rMS7Jtd^lC7c(!rYjBR3gGMubY84ffcL+E~MF@fcITq(LL4pJ +Jmx2n%^fkQ(Pq5uz2-x=f6*&1G{;}2A}b|V5f2{Nu6;VUB&?r*r#Uu;gBZpyqjzV0$a`{H4wr`xKTNq +PNtxJ&%~PA!)I(n?TmcV{KC-#@5ArnnYIHgz2J15F;eta+-HdppXB{eVQtY2Eu{O&sSp{Kb1pdd>#4^ +-VP27KyQkHYMfNI-j6=32sg6_}fR_O@&s+`~^z10a(f;gH(1YY*+p@NZG^F1)%YtTYOY~khZqteCfNK10*u4I}Jx +i8sVHO;BS`pU$ZSgq8WMZ)Cg7;p@Z&v(CEsg(MXo39E`*A; +$JmB$rrJTjN&JcnZC#fTM|OracjW43-TT`2;L>Bd(OC74Z^+Mre1M8dp7i$q18ZKOM58UEIhj~o1_A% +ZMz;pv9+@r(`Sl3k!rKF>FfG{#@dq?VYCvyYDGpHecejBkhnJw@(A=;as3V@}fsHps$RMbVz4g+l3+{ +2EstyEseL}p9ce(Z+BE(M6S~%l8{Nd9QKi-)3FJvtw4VES!KVs!|n`BXUhMjt>DG8i)A;BZDEC6VW=^ +0S-zP2ouJ$8zI5HwT!1e!}&ySkWo1M{uJ?R5-EKB|u*aWeYzpP!tW$Dw)PPsPiUNk>FBn8#^tU(*Ozt +N?8PhHk;0c|Ym^G>YREH1@~%L1$}+*!{2`w+laW6%tMjCVE(&C+Z$8y~-=>|)7lt5{Eijx>&m(*;a`7f%X;&AHLp{Pmh=YBE9}|Bkv +P@vJ))F1~sKwz;;KyY^xnI$W%w!XWsa1&Vi`^qs2P7Pj;C8i8D4*w@6{m)Uk>u+60k-W%-x2T)4`1QY +-O00;m!mS#!dTC~0sApig~Y5)Kg0001RX>c!fbZKmJFJE72ZfSI1UoLQY?LBLA+cvh}^((OU%_Wt{^r +P)|$F15;6Q@^m(vP{NxTI7{(n8@E6IZ{93BCq9bouzaAM3!Y<=pU*1mKAZ7$T182*74<3w3>MhEsi1MaLSUs_Hd#~>fb(` +J0wbbIRCN-npZaZSa4#zTZBta~?Ix;M`a!j7>NGRI>Zmr~oB5_JVp*Ba)y{maqjHgEW`N(*4gF+NZqi +L4Z)3S}s5#34dX`1_@S-e>vTYm}Yrsjgl!gV8VO@k(T~34qg!2Sw0pDSouma)cdRevIk>bu!{z$;5N@ +0yRQG6XOWi>%!mLWcyh_cCZAXM1o2|T+=%esLj%Wo#4{T}8;xXg-qluZcQwnT7=%q09-N98s2#5qq!; +}(f=S +#HNJ<|DT-3(?V>2xQ4K5fJ3&pWFjX8g2WIF)g9g=24x=uqJ+4JaLYmiArzwpXW->}})d`gFR#D|Xa=P +S*O$NBAX*n-TiDFnGl%=f0T9)fHk1~ThJ_OlWcDgk=$O$nGHfnMZBI_4&s`(isp<4;;0E(jxsx_It9cRJ!E)C#~zH?pii#JrEA(Fpa7E +P)Fwr4vB&m-O5ZL!?d^jz^>Kem=7XfF8aVz^sG$?`McbP|tt&#-ks99&B{`JGaq)GxZl5TM5bSC*kbVhn2oC%IcL&OL0J-{xU5ePNQr;2sYPSI!@i;1%U^N~;zTV=uF^ +_KMjUUjnO__s-p#}&CA&;s3zUdGg#L6At?+&k~(u%o{dP!k*aBxsm0X_)U(Y1uPmDr}R8ci)OE`FR{U +IoykKLO~Z+cP*D)z_DVCfW$ub^)Uz1M+;tU#9E=1w6#Ltvz^73Tdql{UIU(K#lu6sz|Z=;AjLe>zfZJ +AID%6K~h67xoIAT!Dfe2dK7!(&Um~Q2ahUoMAq>@JVJ*B91$5eHS&W!Isa)5i!%o=kR~}1NObje242A +}eYeKgMBoQm19>on2lG1=Z_(Nc2?}xt{$92al>{@CkVrHeQ5WJf^{5*ColLV|)x`!Tbc^mpw3~i*a&j +^e+X!sbBE6N#^ox^|F;R|JF=7A9Jr2t0|{ONiH-sDP_=<1oC3XmF6M4AB*U?NtY(x!QBjTn6hoFY82wfobQOnurQnPTuSJVtr{3rR@!DTpmd-3#n%VUQ)HtB$n_tR~!VYh@4n-U@=Uqp=2qT0yxp#Ic}d#B?goY+)z31S0{_O;{y?9wQ#!Rkd8p9G(Nd{&<28A#5uc*oDJ +Nn~Pu^%jOSy#x0I3wr^v;fI?VkTV4&A5lP7kJPFe|&&A#_l;j|7fc)3IlolT9=*G2YBaG5A^Z1*DmCX +bP1+MphVzmqM{bX0@e_EK;T?}`h(>{NTl|l2`?_Z)?(~O2~JrcM{eABZd3RtZFTz}UneI|k8$!XpgYI&Nj74~X`WYbUV}aiIRw>YA2JwS +b`^sKEhlBx+~mL2F61Ai}uS2H?m_FCZ_`Y1h2>DDmobID7Tx-Br(wyRMMmvsK=!g2QC6mldW4fc0b|{ +Qt0_g1xQBUy0uuSs|2j@u>2|qaG|ZS?9T}_;_x>E;OK~-e3#;H9((lw#(iR5WD^!GBbai2w)+j5i7*E{~yyS(tO-^??yNgs&R`BVy$9YmtJwP@FN|LlxHsFcpaRG%&?(Ry6O +=G25UP8t6bj#W&&<+#d0m{`7om?@@5N_~AQ3liMFt!{9`HQLbv{z}pWkz3#&r1hEg7f&PJk;Fv`-B(= +p}^hL)ay|hNhUcTl2S0&g;!0Z#g{e*6gt!U9l0e_fsf5`031{`B@NsMiTzQi0#Tc%ZKC<|BeCE1fiP$ +7V7jVf^k8)#3D)Y_>QJPz*b{{1mzvvIoP$$&Ma52>^d0P +A#=%<8o(5XlL~tP*+O8Jw?AxZj`83b#+uLk)X|#R6;Y}^uV7Lx`+x4(+jzmJ;5}P!GxpcdPQzOg@$O$ +s%GA5I(Qaguo$nv^Dus5T&&mNy>Chh0W+-SE9hr@Fd9iw#j>v47$vW&F?Tu4B3_OYR3^==7d8(m6C3!$iT4ihojHWKXSlg-r{rp` +uyl~C*m{67*jy|7=Dq#3g&X#pQ>&#=4o=`r{a#}eZ(ci0wMuh33kECkj&Pb41?sF5)5KqlqF0oVT)k{ +4yeNlMW?IVRS&{}96;kb};xeU<|55C=pcN<=wBZYO$P1w35q9( +(N2(JgYUsmTICn*g?w+(gIk9?j4;hx@6n)6LW>D7n8!n#Wm_NV5pl14lCL89kcO{k@3&+YZ +AV9*GR7fB{*{%>$aNYIXakPc5ZBQD%Xp#8-J~u=KP)qIHf{wZj`=)Eiwwbn*MDj?B!kI{WkqNe*L1<+ +4HFfYKT;2Id-(Q(+e5{v4r4CKPi~&|r3gcq{8Gp|GXk-!2MjXK9GelVqZc1Y+=-QUX}PrJDpp{kjw~g +xTNMEZN>}4n2`hNJZ?%P6?2rP4fgjQ`)XvD?0qF=BUOobp!4(3Q^m^Pwo&wJ!X&TU1<98{Q!rtc~E~e +k$nv~HaNO#Haq~oyK|VKA@0Wd0YDvM8U|^b(j#a2TI;=MbkpVjG1Y?)ydO=*+^I?nwnd5CZeb;B2U6N +$lwRg539jW%J1;2My%yc2-P^#WVy~G!UFXF|T@|4WO6z(ID@&cDAX?xLW3PBS7r7lIo5BbXTWC>kQ`8 +z5#w%&O!hL10!cF}cVwf^5lt7%0hdeorZ_V3dm=+>>p)d9BlCo@97qmZ~y9JBX@odcS^5TeV5g!KG1@ +f5!vXj*xgJPlA;;cLRtWmR~xWF_fGN3jD|z0N`HCkZ7KV4y9%sTGaUi_r@Nu ++NPBA?;}v1T^hhf`^uX0}j#2uT52JzUR7wvf^EmMFH`L>%ifpDlBOHXmSw`2vwljP^GBfkwyX@V46Bl +I)0s%@ab--JfxRG!g$CogdUXElOE70`{CRL<33D{t4TIZu~g-_m_r^W7wGn!%dzWS-tAoO_bt^++oyK +Db60JAFL|#Ukvh^-GYrU^ZmH{e2hb@8cSZ+>T+PjGOri2b$NkFwle>dCb$KJRVsm6%IRep&Axnn?iVI +)>MN;Pi6aJzd1_f@*R%9FHR9AAH7u#0ML`MNu9iPJr1O}9>F~90nFP7IYY*XZ*Z~6636|LV-Hb@RFX+sp8%O2<6zpHOcfL1Oh@FFrMgfgR9x=XFQRK +@J`P@``p{Ry-R#KC_5&{t`;59oC^PBB2I>d&FP??#q8(O6deMe;5Lc-=(PXn%&;7743&4R$s%FZLOW+ +zIYq=sFp~+tUWad=zkc=dr*WV1-F0_bAfT+Mr1N5kXr^9p09P8u@0LZpoV~ih+U&D07)9shv)3=*{Xn +JLe>-s#DOfHLmmf|)LNE3G!^w6=f;Kro%USuMVT6`3>gcX&;AVtH5nxbc`VG2c89&C) +*iGp^ijo9z*Sko8S092VZ=kuxsn#t*y;gc`YDHs%1X3Kk*KGnxaDC(;g{#cAqq)Ph%aUCRhcMv$p)C! +G8)c8^_Yhg^8HX#Ckgzk`m=u$tSqhtBp2Mw=l6d^)Vhodo9;< +sY-PL@=kEADnqd$`+WFiSr*M^fgr5uY*dmtTDhje#n&Z=*5rZVk2@XUzj2>TEsMcqz3trVx9ORTwsSy*w>~c50BrOavi*J8K=k|Jhw6V7&tREh +i4G5zB8zXn5vPA0>_g?o)DgMW(IEK17G7IvEcTQgPb#6v?-P?d(Bysqy98i|>7W%95k1nNNz +-)6-#c@PN4gMrxR`CbgwerZV{sLU(}jwYD3xDncc#^cX26OCjxrV(O@oH~f?0%P+qaM_pSf{)gwKtZi +@6Ne7v=)&@-<=^8L-JrhPd#s88CBS2uq{v-=V;3Bmn^>1py{vAx1s{Y3%8rrU3{;ss*9c}QmnWZI_TJ +Xwqc&ZoO*={27>NxYjSmtYa5lAZE+(U?^%>n%2#rLhH>p08ItPp= ++MPN5g1E*CkClDBpMIQ<1yobayQi{n1hZVLdvc0hv4zGTAnLr`FeU5d;uIID@=V=668xq*3q1fj6}Co +9ssgI$kohi>j!u!9~?@sfRW2WQ|8~4H^8HdvQ`r4_w2OY^Di)cKuKk(LdL93qI_&S-#tbr!b11L8m8| +lV1PI*#S?cdjzlJt=JH%-FgVZUdIFJ9fDhcS&ERM`22@YS@n +GirI}5^Je}6NjfcS>ipye+vQ(DMhR*OS!=X8NQx-`ROG;Ypf#6pg8K;YsN*}<=fN!8`wuT*^yTsi7cr +#9gX{11|)qw;n$#Ge#J9R9Jep>y= +|j|L4$=n +f6<3ODyn7Xv{1fnAE`VNvoio>1}n+wk@=ojoU3Z0rv4Jhm>kA&U}YY{?F?V};CxHa8H0RpzXWxqrqyF ++JKxz6Urx!4t128$nZMW4&q8rG#y|559J(+L +#@zX!Y4WT9_g9rbKdOvuAK@yX-5Y<^IjrZ!Z5$NW`V@pZTi3CY_bQKp(1=f4_AX|+FBo(2z`Zm+P-r& +w+L6>YgnOHfAFq=M7{OwzF0kP;Iy~w<#Z9AOQ(ojDZz13w=hP$I_jn3;Y68|Z1Y;530g=42Q0=pDJBT +ULJeMW?Qp|kFB?kHsy;m{QP;OyiU6X}Jqw!!Ww8h#{&OV^D%@i1jU~kf*snEG93ovH1r&5BCr*1%q&= +}=W4sP0vYZ)jHiA8<|z`|+4aw=%@c9W?yfOLXJWiJj5&UhM&#^d*#G>H}qEC;l3rQKs|EmVKHcO>Yo5 +*X|#2j0!})_6O8#+8%28C8=MO{t(Ugg{(i9WGw0uw3En>B^QhTS=AZqBPY+y^OMT0roz}b3$|*ngW+n +)j8@6;ZuHcMYSZzrgL>|8icR8-13IFzR4jHbW6vwC^R6@OciK|uaNYxm}e)ae?2-mJ32d42vF&sh8Kw +iK%|rUl|})P{>QUR1#VknF+@qD24a@5-rGuzAOzE*OcN^CtOagfmvp{*F5?JqZAkUv#()?Wrr^qxgrW +PE$=kHv(Zv?(`h+sV{*2&4lA?0C;0Gk1!I%h!n|b!CQek8u-mfB7%e=xcdCmPtbg@POViBud!&Qpc)l +qj`<_O`+iN4H^@AU{w@9%c)vf`b1nrw;%@mvYwgC|*8_{7l>=+6v!O5fXY2>)5EhJ-L#M}g84B9R +8GM}-&!NJ7|nS1|L6$VVP0VE1qaV~q8c}D@j&?$^?Zf}8OR6EFTQ*C{a6)3DbNNnYcilCiabdX8ZLbx +{O=l7=7DNKA;wlwS7hvi73rH~&?{H9XN3;4zC59X(jfaw!ugomxR(qEO< ++7#&$xweIel)`qI?*6BOf#+vu-!Ub<;Z!R=YTTA!P%7KjlR|6cAwm1tvT)a+&wAiFmhp`ZzP$wes+QU ++KzvS-k1Lx;~cc6dvqYi2WzTv^6>Hy6f{tnbl9X;Q7mg&c>2KTbD)QkG6?3=P6>#87b3^n>v?V9l +TY?byR1twg(djlJao!8x96^>il52EsoeR;DgbNTzy2E6Rg`yC4q +({KJ>1JRv6j+Px@{RO!$L@ugPRG)@Y>PLcv!X8rAAM?A3gL$-{aREe@QLm3Hega((>{-}ll{#CT2b;6 +6hTCuwm9G&%rF0EtRDZo@iEWppJR{jC0_=7u(M>{>h)X0POTA_V|VI8IIUsF)bE_P4F`gg4LH~ppV#g +Y1h}mpPd~wR|DZ}|w*oR2Plj9mk{>mZ2zZY;)is>tIf}!#Ve5i(SN5Q8I{de+BPH*X?sJ +?tH|kgT1NeRmr +WZoW$IVEFM^w|uOt?)kg`Uop~_F_=EYadhzrU;c+ja$!AXq6-rA{bvNtm%%cCwc4DXeQ`!r3%Hq~ZVw +de2qKPLR%0$`M)uE7C+t;Y{-FeCgI(3auZE#fHG2*5Ksb^InOE81e&Y<5mjdKiLT$D3v=nJp#^+%lZ_GzgaxcgKC+{>gA`ZZ|Su%;4 +DJuFCeotxbI>4==DVBX(RcW{X$A)y8fLS@!29X2D%vNltVv1&hVUAnJ(1>Ye;w%SZ^>gYkzeSgT`9U5A{wRDDOahB|aVl! +DUkERGJoE-rG%8DuLcH?qCUFPW8?pZWO~E#IbNRBLK1f-u~+cf%*zI7t~#;^1JFjayB+T0|*B#OQioL +1)(5t_G-QpomP?CdDN_n(J=t2eKDu=m4+7PWDTL?T>X(Drty*6MVaXI^oFVp#P)ogIH;aCe +8-lwKc=R8vvTjL2{w?a%&OQktL31cNE-as)CHVH;7n!|4=E)NDads*0=<-iy%JA9^d9Wknlg5^J)VxcIGsxL(NsOr6{-x9 +Do}H7EGUuGSBgrC0VyQRU$WI6`0k!q;q8FVpZ3h>iqb43Bxof^y}k!QP-K=?9`Xzc~;DiPlD6a;0yH# +h{5%<|G+)L@1tuQHK`o|?SNAva4o_b;B9H>3MMK=ll*yG?)GCd3|!vuA!dvX(=4qwfMJC=A +M3zeOUD8|H<-mfEvnAV! +{Nw?*k}quviJ)aAaFy{%;(18T31&|9yCIvq(B2GLEC@*QsW$#G`-_Qt1Yv}J*t67shuE$Q+n=Ju`hvW +!m%^Vtg8IYD)S*G1MvkyYB6`wg$ja?Yo}ZJ`Albc@=l8H@Q|nq)fRYK|^((j8@!Zy1+kL+M)SBIhG^c +)D8Z{JS~~PkSUX!kfg?wKQ39i;#T=vd+=>=J1~1T}tiXxB=t?yIRAWnfF)Fxdw)B+iFUCVk|2u-8W#3 +%r_Ro3K-bWRx-Zk<6r8wBC*7OUm@Q&8muh{g}P@7Ug=G?ZM!`B&|2+P?M-nOW7FYKv;WUbNYvs@24$6 +C?V7dp>E4jqT+@$MiQhPviU0#X6V(RR-SVV=YufI3^Y|@9WYd%J=zjrFO9KQH0000805+CpNi_=IJE; +l)0Ba%u02BZK0B~t=FLiWjY;!MRaByU4a&s8XIF6?r}k+gHS<*<*o? +e5#VZxI|yN +jE2`&}oFuRzS{a{1>-&a>69+$Hd08EgD{_JM(mcp94Ka?_mzx6U-}>mCn2gIap<4z)uYP6x34j2k|

    i-_*;o-;w)}gy-#feTF0Q+s +3$Jr?bJqFP`Mz}3!ex}{_%9HVA(z@15=f+?gGBKu0AmbT047i%8;G4bfhCj$B4EP>`%a02>o9M=H(ds +%Y63GhWMEaCnmlF*sMS==CL$5+X&MD0c}kj(p{ODfhL2p<1pE!X +>!8ZsaJh(!z)*?1L}_Gvr!OIW3=2ZJj{PPb~FUiKoO}TAwzi&R0#1>@M{T8fxZb-;5?4mhrDFOR713cfVhS5pzs=HEmFW#C73;i +%TT*ZG;j(~5mBcE{j}kcFB+&*iJqE;!%B`JAK-V-D36q5g1QyvSYRNf+2;1&m5ef +dGNNkb8DNP(gkS@>z>Pz0z|bi>Iblw~6Hw3jp-30h-EdYZ%X!?aA2cD?T#Fw~MaVr7Jv1EPL$BNEemw +U+USFO&trg`hfv#lXzpu4zL`B|~`&Ldrjb)fJ5<7X%!O$#+eyoWtsqa71!^%0_8?h@Dfs((c+IrnqQ7 +J6}Dks@uuag<&u*OiSQ1Ga=q-1L+kZi<;0(%4dl%(Wku!>}4m0i)KMD@A3MVo+5GX)u0(?KtwgNP;gM +zlznnM&?adK%M)96!#uxn&(mJ)8v2fWkrH3XEPvemy`jp&HAGsHL*t9nNGhk{RJoK&CsDexkG*8Jf;S +bdc(Hm{pMPzkc=V#hbT{yT1GUS<~e@o}X6GP*1d6`>EE*S`a#^b&4a~`s7h@)1!k&`BPMMr$`D0JqYK +q9TQ0v$ED`q))SChno$^Wa{@y^ZNs+8=Z{#v*e9rZTgbwYL=rNsJln8eZ&)KzCJ$i~)qy$ZO!?^)1_w +Lw_OltJJosRb-KhkuDSLt@rFA#tdX#lw`|3f1*S^Xu0ru4DHQVT&y~n^cuni_|2fMY4OK^nu9ufdEr- +h9h282+}sPb`sMOq_QX`6H_X<(gH)O-s^yPR8`ZE5H19&&sIeI1y6$uyusHnim93g+#`Ip)#suyZsb$ +<5|k-`lHWZ<1Kaqf*POKVIGSW~;I@Z&Ax1H#Ov)@{4v{uLQEb){RS%gPy!om&e*HxO61Pn;R{*o1)L| +c}^s}|D7gFHkNxVbzQU#xgcw_6)o~{`llQ1MzsGo+HH+i)10rXQ{g^s)u!TxR*VGwbZ<#N$-~|2tM|P +R`!VsVrhAZZ#wI&P<-7&`1W#^6ew^3J>{T*6Q3$=nGIUKctpr96FW$;EOD}V!H?4ZPv`oDIYwiL0u*! +CM_+Z#)+EsT%NzMS%Bz1#j*`K`2-tQ2sBwD&06M%q=7m7&qf+&(CFfDY|^RW@YXvzA9fwm4PVTPuSN-%Ju003lReYLa5X|as&8uYr4& +YafLRvksEFTp>-^RHf*XFUI8;#P}c9fatqfYTQRvro%7YnxBS5po15r%8QbnS&}gWOeL=W|>`oPKbyoQm>}nqNO^cxZ>$l|1$E<%kE=4< +N~+;cFR$UX`4)CTwrYIUDgX9CH7j(Ih1Q3bX|Mc_=_p)~iox{L^V7FqHPHH6H|XDFt_rQ=ah12!XQ$( +X_7;bO#WWo(Ve&gFI%7>8ZV!2krDqqqi?}&@K>SJ)|e#%-l+1{}cB2qCZs6UB}GH4wO!7bSJ(gJYvJrHN$$lWyUztH+-r#XFJe)gb@B%ve>wln>wdnyJ-_u(oH*z|0^FU2@RTq1*rXK^W`p8z|qqhCQ2=jBI7cwP)DWMp?x_VP|R&}N|j*!9QqPck@p^YYo-x2LwqCR}@n>LDZ;PY1nP +PMtmy8E9EBAZVhJpy4;!DLZ`mvPzAsV0etIEEs}M@AK|kSzQ2uxWoOUkYQDWaWCMgi_w5s^wE_V3LF9 +M8UWzZxJBMSY%zkWnqkubA6MvjxwTeXogIMpN-nZ|WmPKbyIK=iZQHBFHtM-AV#9g_cb+7wpfPAwynoH#++}Zd`Gb;y#!CR01_59y=ZI%t?&0|R+2+e~;IR_2H^=w{U;nstfGxkWqrIh5lgrpez(^n_{%?c`_N}W+Vbrry%bO6SVquDGS$f))ka9?g&Y=aY19c7hb;uH +m(sYBkfj_ZP{I(69I7a!EaMuP3N{-k^IGfz#+o#yKi1w4RJaCxOv!EW0y488j+xb!dwaQy+pvcs^;E#l*s3v(8xDZ!yMf;dU +XXtt!Pp3obU*{r03MyDmLha>x{8mxcbyk-m#~}rFl|w)XmV?46@Vx}s%L69jGCo_S}xH&=e%*_Xu4xDA=NK(JgD&z +v|l`%`Rn|raIr6}iato!FKtxM-o(Q&uozP!zJZ#UcRRi6KDpewvp=)X15)B&IM%_qH+MyH-6N`Gs^Ic +QugN6(}4)95Wm%p<=H1~%Vc-{AF&fBUhimG!-h*|8QPkG2rJO4)>{E)2Fyc)n%)82=oz3OOzw13b1B9 +HbujHHgguA&0gar5RkgNI4%}C1hn6N~~oa->Y&_z+X^H0|XQR000O8HkM{daUN{QDhARuU&px2H9Q)S8($PxJAdrfG5ujVd~UU~6W9H?6=1r8Quc5?ogF3n*Dm9>~lNdZr~E8(_KWEEL +#k+%U_PG|MCk?(-Liu<&z&_4RJS?ZjR_cWa+CwX3L>H+<=oo6&6UO?D;#5i*1F{#qq(SoMiiIfqRzr;LMe;zT$cOPIk9tP>rZRYGfBE+oer_KMW +%rn*CC@Cq=^B$YpJ%@!H{loA~;kENT1G%lttqT(!2YY_5JVL*N5k)A8=(-y6Rv(tCsSG&B!&>jfxv!Uv!G0h7e7HY7~)E`If8BIC6a$^7E0sU$39n`}Pamq8K;f;&P3Y@_e?JasQ9 +HI3M|rm-r+awN`pM_B`(Y2u~1Tw@xGgF=ZC`&W1WrLBq#absCOlaIgN}Yd;Idf50iFb&F5%tP?i9pj- +>TP_kIP>JA4@sD#Rym@YsPHU6TEk0t!l*XO|Y2s;K%87XGO<1bK40|XQR000O8HkM{dy;?u8x&Z(H%L +4!a6#xJLaA|Nab#!TLb1!9XV{c?>Zf7oVd4-YDZ<{a>#^3oXPU!=9OHl(-R7K*YT{=z5+GyRL2#O3G! +78zl?I_BBzcVyst%Bw!uzz>oci)M9tF(nel~@>0^nZ;ic!TFZjh^Q{y!?EH1X2&^1U(+o<@V3-r~4`R +2V33yY_ePuqQ_)4sRAFSGv0;vQgx123H*~w(`SYz=99P*Pz1IB7<1C`QrMP| +S%+K<*)*yaQ!TKWK6BcSXRy{^v_Z&WzOG0PxHAop*4;If2&_8A)Fx~KyOewt&5AsH4V4d2@7SZ7y(mZBoH*+b|5h`zzksLsK9#b{^oN`MM@(+2Esq*O$sZ{m7Qi97wyLU@I@q4AbRdA<47cdE13SqxMd{LX}ZW!=4g$NTu8cCDdoL11%S*vxTS}dnJQ +(OnnOXXl+fNqt3Jj}uvE2A$crgY!ppED+{Z6V8LB)r&q +shS1{lL^7P-5wj+cHrSI;ribN=kXpvczFCO!t% +aidB1OF2($r|@6a +WAK2mm&gW=SA71$5v9004Un000sI003}la4&UqX>4;ZXKZO=V=i!ctybG^+eQ$5*H;Xv1|m_3vE&+c+ +}cIsI7I*<2$B|gXbWORj>wJ4U1oO~Sug$e&MZlZy7U6Hf+35`x$T)Vm$lIqB+0sQjlm=VS=HJ&5G$+8 +#$nPvk4D|O!Twk3wl&)RsV;?EYg6^l8)1}GxgCv08LlBOg3PNQdEVu%@7oD +L>s9NL*R&4DQf;Vee%Mz8S$iD?vp0bkin#RYC85Cr$^b!OCzuH-o3TmTsBdQ>Vp9_-Mh%Ic8f>KbT^L +9$99??Li{nJL9M{t@P=ado9jq9v!3Yiw*G184;yD3`BUPbB}e^n1o?B%=H3CC`0ks{ol!sI2L*|v$`P +p+CIN0$uqMVcqp;&X!D3O=P+JNVI2{#L}G2V=C^I~c=Ohg3({$5F50N;2y~|Nef|;+N%uMO%mq}gi#k +>yj*YxK6!Y5V>GHyb*Frq4rs6^*Zg3NJT*GA-No%YG54{bgwm=jBQOg!wOTuQbe!oDlQtEGn +u6MPmJInO96mLQ%CQiR!p#fE2_y4s>Mp)oeeAoQHJi~P6=W+~h!dDEyvcP8&X-t +u#`#|J+V8h{rk=mMQ)F}q}|bXaWPw5%)g1}^B{^TuLyZDyS%!-Zegm3BnIP(BMD6q{_yU5pNzX-FJ>= +(|2q0D_D6iF{wSCZ=@JboTJ3q*_xqTCgu%m8jVUMTu%~aND`4SCPsOSnA;sQf?{FIItQ~#=$hEtHXEu +OmaKNbdjdHTWkFE3QxFft4rNtrdLmCTV73W4bbr^WxK@`F5?GZPbcL%{7>T$HJcXxZl;cnWUt)1}S(E +q51oSm9|28OacoCwjIe?;Iv7OC$R{j86BD_m?%DGW`ZzOVA_X}%#HDdIRPD`^gQJRa}3AHxGvo~Ti6y +$%fwa@u?FbNFU7CJlf;zM_ul3au9Lw=hd#aoJ@9rp#Ll&!pCMzqF7wUU_WnOJ@&m%jNuN5&8R)IFvpqiZQ&V+9p2E+P2h(N2}hN7lxIfK| +_issXi{NGhAqQAF8&K8Vm#Pjr!<8c+u!jP)h>@6aWAK2mm&gW=W|u=>&ZQ001%z000vJ003}la4&UqX +>4;ZXkl|`WpgfYd8JlSZ{s!$e)q2+dN{-ZQUkl~hM_|rimqGxu)9Os-5!dWxH3Kntp&+nIA`6Ho;D~wsBluO^P+0a);~$)57Mly%e;E*Ot +sM`Xou-z-=W_Ut#MSkIOZ?077pp*b)MMtSx>C8Jt(bY$R?e54%bl`5+w&Am$)Z8kNzjK*I&g`XA94?5 +vp~Gc9hfM6ulow+1xVpqDG9RoG|A&u5=MUSHi_c(i*fO0%$2bhSwuPt(8YL$4+{ME*jpBz_R4# +_WI+8Ul{Mj4I;klAukyGw?BN>t=@n0Zg!7;6k2%C(Uv~7t3PBB<|hf@b98ic20JI3hWSJgt5)f?hq~2 +4HCi(K2+x{AvR_3di>)W(KIALGsj|F30<*{qBTd7gTy%SEUB^aC=`0U95m=cE +x%)Sci7oWWWZfdVoF0u0BfvC0HYWC#|Jyx^k{hiK47PbD8w2_{JJ2Q3n^EboJR3SYj0Dtj6*{Rk{b?R +#pH!8zt7?-=Q>NatvLnfiE6;=pwEB*&vMAt(?5_=eG~5i3o3-f5zY?^Ufu5Lq(3UJHfT#uuIN8$!)*B +hj(j8;g{Yx5G|p9RtgWU{Geb#_5EjkyG>px1VnG%I^kU_h_fPPnnUsboelz9E{Zq($ADjT#*)VyKmxh +{?dqJ$6u7OboQI!%#78A?3}<`KZCb0GCc8`IVO)I*;7+JEj=SK)l+iu04S2o+6H4JQ`Yv()Bs^YB=tJ +EZXQyJk;L5$b2z4OI;SI(c#L>Hz>&mWVxHwX6Bn&LC3CkM)Atz?_aeonDbXEx?Piop_ljxxZ*PTQ>0_ +<7coDdW{qLlYbVM2s-riBOOBw5{PGL)_I;Utka%zWF3fqD-DSg1o>{hcm)pJrf4bkg(m@`H&3Q>*@{w +1C5>gklo>!=I6B^GK2S6rU4e(%S1I#Qe+;ACa3esl|Yi{js;7g@Iz9Adg1@ +jJ90D>1cw*vT0-%{nTPLT`}=kW@G0SD|-e?;|nUQ{8BBUPvdgTyWIq+2D59+rL +cas}s1p|N3953>o4QbvMy>KQ4vyC6aWAKaA|Nab#!TLb1 +!UfXJ=_{XD)DgjaFN4+cp$_*RLR)hf1wS6y4h}5AzatGvGRa9UvHrK%gbc=0=eMNhNWA{SGgZC|g;p7 +t7?ieCK@UqDsjc<$2YbR?$31tZt+-h#a)!t)aR9pCsYDkiyVc!`Y!b;qrK7;&|~FpNJ?qRk}NuI!TN= +|B@hh!kIZKN=mCtUkln8w07q!rKB1OmTg_1^IjYg9qA^O4WVHTE@a&h(>gxEd8ifLu+z5p!aCj+iKT>k#kH+R)lXh9EOwD2f +$#@vqzulfuL4+@b~ANr;TaEC^4t=o&Lo0ytugf#^rj{e9pLhu4}2a-=FLX@$IkwU +COoUVO?thS_Z9ewQ8fC@7(q6Dv;Wg>eqCx0(VTYUxL^HBAfbN_3#XEG<#xB0oE0R;s32gB^`%&5RXbL +bDPS3?4atBc=}v1TdXMPoI6xjPlZx$pqm%x_ZOXPu^1EvT&p(k1o@Y1x2AfguNxksC2M2NADu>cXRYH +14{)bTBEhQ0DeA8Rf8T?Y1bY73D|cItnbPlrke6<4jv1s%4|U2<-Y)4O*_}<##43sHUw93_UoEuJ`DaVr-I)^2c*Hu_}Dwavr*$n?9nMl9(xAsYAXolWjvyq_>h%; +z~SlCvUJp|-~X{;O0j6K%rgKFvE{b_g&wDwA&2y)kW`HLb=`rf_kK!m-u#|<*HCLjtXg8jaXZmkykM$5f{ey{)XgS9WE(P>vsH|P$k(LgCMUZS=^1X)D33 +_K{rAP|a5Cv_svbeM5&?pFQ(A;jDJ&HZi>W4z2J? +zN^Q=!KinHotlv7w}rQGEjz&XzTrKa6gogq|0b7d0`Y#r|3U4}+)2CT;A??#dO75~uW39X6n{eGvZ3O +#vxiUJ6bb{rkWU!i1*t(iRsxRbqV^armqfa0AcLaJo6J5R|_zt7r8G($by1e +Z-sw+frLFuoN#pFLwO9KQH0000805+CpNk~-K>WKyb08bSF02KfL0B~t=FLiWjY;!Mfb#!E5bY)~NaC +y~OZExE)5dQ98!Knx$54QG#VFQBZLy)9v(DVgO)}qS-fsxKJ6Nyww%8pU=zweHErQ~!5+J2ZmBofIx9 +-q5=?&yV9Ig8^(X-f@p%tT%&Z5h8YDl09-)%RplkEh&%6*)BDcSgzPJyW;0Lf$r?%0vaX%jVN;%w)2l +-3n1e@d{+BG;2kZ`-RA0v;b8k_ng!=OIM(cP?B-O+PSzM>}`;!9CvSotg<|d4J1mYX2#y1y*hdQ{-Rr +*s}wTRtbVh3bJoqFZQP>rcKWZ2)3@>Q(ed-s_~h*EjOkKJGNP0z=y)ZxEqMlV)u|}0=(K}01a&I(jNO +8bg*0ef25EZ=UoIkG5IqZdqas;Cavu}Av06*elgZ@b^!yoGbo?SdIl4TJpS`?fhb-9pFyG7Pd+Fug^M +k#Y2YVNP2e_6T1sdmTk40$4xf=`PSn?d>V2aCGV#<^vsU7kKee2O^G6n;Jr(r8GZ6)9#fx@!z?DeVE3cdS|XC=7zsjt`5`RVhdh0yR +7I3s7Q*c76Ph#5;ttwGwDa<8ZC2|KbF7X?K)TWf&|Rf(xr>NZatip(X~PI#aL*1?xRaTug!UW6m8K8; +4`2{4Xq?Cb~*yp!P8dOzuqN%X6yxQzH=fuH&Ghp{2mxlGy;YdWQ{4cmJU3mY;>Q}n^sILm +{emv4jWIQ1o7!s5C=!mfE8Hwo%Twt8x!_dP}hyrw}c5p=Hc+o250cAG=O-aNS3i%)loJ=&J!D-ZasI6SP9dPn3c&cd)qH}zChA&(9^07p>GzPkWH#^9Db=13f+@(%9C^NGyaR!m +>jrWs=){LaT8PD#{u>(85uCUP46&JT?)}!nHq~{)9+lZRDnW%x>61QX-w;P0YKw$7Z*3pH%n5pvh@%E +_lx9{g#W@~L|%){=d!MgG#Vrl5B-a80_imDdaK6A;+f_ifIMJ;3HkaLj>>zHDp;bRFh*)X-Ja?DT;Dw +zN)unAlP+(*orKwM%FG$a#1N8+TAP8;dri4{mf9Ttqb_lg&Za`w%jFJ|Z|)T9;*x26hQr%u%)qF^S`0 +!hJTYIC~E3B#rsBYtbM98$YjS7G$rSPl>MO39HEDx7*?;|8Pq1X74L5RQ~q+x61|rD>N+t5;2%oPIp) +x*Y1~EQ&Ojt*Ct|Z6eh=oc4(I1T5%WNTB0mv64VFLg6vd^=9dy_KQ8P>r(}J(JiP8DOCuc0R}7ltnD; +ywHTSFaLluv>?(~{eS5CQnLTE$LD$v)!sB_@z0gB--ZOa0p0YpKkL=gq@Xzl*yFX(}8o1dr+k@%4U+> +=b;BQ0Ga}egwU1{)Q3`5tgxt4uzc@~V~xr%91kZl!H(0y)!A`{gO_$Sv`4tnb8$dE{LVIW3Ea#3EI&|fnE^lD_r%CXtXg&lG}q~pWTlVN2K-G*dWIK2uqWWW)G; +QEo<19H;gBUwHcn2tv3cJDEsSWP2gVr0774p092YW~Z$UoM}xHnrd5AtU3_a|{Dsk@dI@h+J#?g{F4W +W4c^f*n!~s+PtpKBNyt{hM}l3448hbhJ8wXIy3>fWt?A~Ky-tswTpi^9Ef|yd*;ruhcN7&42Nf43t+_U!1M&_aU;2|M>W)ga*$B +A_pJs15|60_P?Lg*ABTM$m9V`%;8ZuD`(B=&A4q-yc2{PF0*A3HPRHHNK-5$*FH-p+D0oq)&n9g+wn{ +L2<_GbxWl2@oo8bwhK1_japfGWt%hB7)CsHuLZI&WDJC*e#G25uztTlEwh3xXrfSz +8-O{kE+nf(>($fN*c0W=?2z;HxQ~KT+ycn<3SyF1=7+X*Bvj-8DzOaCaG+n)e{YvTWT&00=Ojia>q-N +KZQKpEz>l&dPkPAZ3GAf$ZT=VJ2M{I8eOHASY~o5t|2NahW4cR%+}A<)cEFOD#`HxAnN++^jMWP_NVLN+m(I +_tcfZm!je4n!II(bV=G65xb~~%U@|;_q&ogP?kF4~7zBJHfjA^zrik;qGgE7U>Z^7;cB0On6V0K!D|%D(4XeE +=1Pt$m`yEOeSXP{!ao$Yjz5|+F~G?MgKlLD;4%dda6|sIq-DJCh=njx?Fltr=QjPqd+L7o9O@9YzJ-K +jQ3V4{U%LQyZwqOdx!6B8zuucKhkq^$bht163#Wc_hNdi$#V@u7dXcIghYn=QLFhGJo-_t)d7uml&c-aFjon>tN3n&?3wO-G +Xx{R2=-0|XQR000O8HkM{d7NYV>y8r+H76AYN9RL6TaA|Nab#!TLb1!pcbailaZ*OdKUt)D>Y-BEQc} +;+_(f`Xzjy&IHLGc9gQ>EiFx+aeQl^FeaXml@O-*8>wgg7GjS-+bv`;D$R{! +;S`cIKF%jOw^58y*wQEhuv;d>w2}`LIpB|IJxUR1^z>e*n7pny>X#+>pIlBnukUH#oOwPY?y +@6aWAK2mm&gW=ZAZkd4;Zb!jeedCgi|ZyU!Ie&??kP%y-`sg>=tL10 +ut9mh$8x^`eW@IxFdhPy*@qUFqXXI2!0{`h`pE_)%DbZr-H^&pA6GiT2AJD1_I)*F^(%f>df$TB83m9 +8!03!}@%ip+nWEXS7>@=hA5)npPLNGocqb!p-Qvon6Pkt@Z^xY2)_vzzN5uV25LvqCI+Q`$@_o2|JjN +>N7&R>6KiA5Ndt1syd{XMwN~+bwA5zIG&Gn|@HXii;`t|p3-rsbu8!Jl_-!65%;Wjh!53#o*4TR&$ +l_2H{p)9u~aJxFY6ROa4C)oYLyR@qHsusqi3*IjLj@NT`t@2uIh-it=CpNA{S&6#kd-lGDrc3pAc`wy +`!v5`_pRT`unZ5Ys?aiCFQ2tME-iHs#iL*^5l@cxEH~!;fV(Z;Acl0q`tAm!iej1`-gw3NXsKba(Kx)}LyDa96F!k?$9}BqcFCCYut)N*f~=U^QR +!n&*~$6|!wPEN!(rcq{GNuZ{W%brVJ5*Na0o#Y*;Rm}h7W3{Tm)7ota859olvVY9pS0_7s@@uBDoFvL>k$Ma-f^i +H{c_vcGt*eCd|BXg=|&p8sqL#&+>08`YvmjGh$TsJ@wII%<3nO^)3Dk03L +)2aLWlfz+Bkx&My&}$n9E)ncXn)NIprz2cLj1){Ob}M!Z&1=U~2+GYvio{ab8;dW8_Abyl#yhbOmQ$5b1LROTq +6Q2+I}JC?H_h+o4HAddV}lbA#d2SLLd^UO2#BxTpuDa%l)km67aUv +lrBx_5;%Ike~LbUeAbfrV0mGDuYlWW=4{`jy*C3KNi)QqNYki=`sp&OwcWiZ7vQMzNy$O83@mkz~7;` +5Kl$jI2Qvi^Y8f_rS_RlzfN30+}txQPPJjLJ!)lC8ZgdSw%{Xszsae_W>;mLNWBjq-fro?qzks_`t)-{vXgWgf=R0 +9_6$L1l5_zu_V*(xA?Y3l+uVgvlD16kvoq;PP^`t{W37m&_Z8(V7L;z8e~a=Ci*1jFOTA%3641oB+&q +sN>Q3s$v|??cVS-Aj5OOZCsa)yN`+0{Lg%|{@9(!py3}-b!LfX`aA9+7tl!#nJbXho>YhG2NSHzvUz= +9WrWIiW?8_M^Q9C-;+0K&ikg>AY&!SO-=pV>k +D5y)KlZoa#Md3T#f1=I+*s1sS|<*e>zrrYW8VgyopM?qYn~RBhn=H1qXkWQJHZGmh+7g? +0{OOUSVGi83=N?gC<@b(Q`Byh9A&YE3!~4nibg0g-4n01#Bs;)q^fP`NP +7dke87O#=_1B8So;xg62^zMi8wg1)svoVZjN;2LgNig8WLPRFP|P%Ir$W}n~Fh%y^0p)C}?51{*VU}3 +LT_;h&n1|B8*aa0_Lu)#jQ5{Q}Elug+~Hrs1jVWUUvX+ppI8$8p0g;K$Z-L)db{343|0E-n`*FC!xDV +=qne2iXZDsf2jj6J{8vS5FRTDNnB&?TnnA*%2@^juf$ar$_OBZ0Rm_DoMP{DfV$gh(UPOEW#jIr4!;y +MY#9pX +wffB&v2ab*b7}6sZ*cxU==}UE{gs;6B^_E(-{tkarSX +j~X{SUjs9@S7=i5gQpsgaErnQl0 +~L_0T+g7uDbDsRi}ZGEZ#T8mAAxX5AXU8_X)+{8GEr7Xi>e~99F6urHF4}MRdDRgRNt&+RlSEx@gcr_ +iYyR7ux8WS4=mxAG$dGNPAQfk?e>9-2SW1W1pi+d#AzQS5If{f@HAIM^5W1&icN^h%F(fIuHNmz08Zs +UK$Q;n(b4g8nQ3^fQN+n7;lF~L08;+l?$#tdb}tG${5HRn4k$8-z*CLtoMqPTA{i*!slm7y)2tS4*y> +W?RYpTbL8?^@$enrkA#sz@5FTXNYxN$ArZoZJ5qmbY@r+Lo_6KJ^uY`R%aV4LBNo^6#O&1%QDbgN__Rl*l!}O)pZl5Mu +LG&W$wM1cy$an$u4vkaqG-6raWc9sa51{ezw4g;wm(YPdas!g(-f&^U-&aQV?PQwp3IR;+eY2BH`G7U +H2@1YDrQ2f-^T>*N*!D8!ZdjQ{v{0_&CqY6vJg3^>8`YB+|lzi)K`LjdbG=%)|7qmuZ&yrSbDPr +;o-2o`nxdW%Q`R1P(F3CR)-+@~^S2R5k4jK;`o(&g{I$EiOT)h#u3+!lUA_3>WvClwE<-+xGxh&OQ8^ +F9oSN?>9~P8D6SVgtA>ns%$QY)@A=Dz*QdSbsWu;7lw|RhdDphvA +t0uJSf&Wj^@S1KN=}Qaynx-0>WEcnP-=mE4*(=$D7M)SMkeAR+rM4MwrX5{`BOVFi;OzH7FwJP=8xSc +VsW!L=)ZgE9iwLW#6_pXxFcQcr&Jy;ha7sLj>5Yck$SP$>2U=NXTzj&X4JMngp4w$rIDfT_?aNEsq_hFlE1+RQVLBD!HT!_-r6(_B +@IHbLwG5qpxuRbnKpCj}X`y7o)(dTb)qvD4#G4FrW93eG08(;ZxEP-D}abvEg7au;9h|Y3n@R +$5{c!D@kOR%77YSagZ-Esu7l(UKXyWQ|`sC@K4?UqxrE!1~-^*otUwb&<9Irq+vf(}b*?UtHbEWrbtm +u3ADGxrN@1~K(NK5A4dred6F;&od(Q&HXdVL>YENq=0sVbde#)!f(Eqd+m~G5VUmP!QT+&K4zCx6IJpj7u`;Y^c-q3O#;iQ1}r +ul|mg^G1{aZdUNU_rdPd^qa7QvwZxvrp>&Gl+PXuAO15*0xNif|9rdjM^ZZVlix<~^CTBUGl +?Z|hy}Ssu7dJ#qf$IXP!QFbfwH&L>t-CfwUHpeoX~vfW!1-&QYJuV5wrc_Hkn?5klXjVQS>Zd*W{|zKM)sf$a;+(D>{tE~Z&u)Fh^#qBeD +zAoJwoNbr#kO{0I!LN_`K)@ggRUf{(3maV8oD`buEDc!fCy5fgH>Hgvr0lE;BB5OQuzZ7QIHI1!ZYK> +pT^zrY%cp@#qM8E>+MlMK4Xj2%qCb8F(sYrc`>~0gob)hKQ_RHUw$8FU9EQD>pzCcNI2!I30PVq>?dC +S}ve71aNB0mZXRPL=6w?NZNxoT>MP;KYgsjBPFxT|H4wr792I?|s-uCKj&(HtM^E4Bh@hoG%zq( +@KPADyloFzqGsUn*(U6*B{s`K;nvz02gERI)oRVxw4Om6WF<4av+btPi+`|Qj<7fR)Y`;isvwanM@B$|YA?Fs_+-9Mf-azPL?9S;2O+oAHvTuZry!c +HNG`^_u}`^G +o(5`e*cyIeQvCWoaRF9#m|@cY+bImEvney_qRj46x=^r9yvc0HZS=(0NO6)qX1njd8AYu&!jLUi^u6bWTkBYXvDEN|SB8VLb +}MF`ITO)3Vi3im0Y||C`XMfIT}UvYhMKF&2&>F|MSq1t7nb +xd13&pBI_}0xGOg)Tsd92g0#pbh{nkqcGh>$wC?gX7e^EH4h%Jp8z2=8k- +J-Uvm)#^|#u{hCX}cWi)LV>ILvNi<)E3V13;;T&*D(eDlrC9>4kV3~_*gKnecurwyH*4N`|bRgV#A>? +Q*pC<`sCLLDqq_+Y}9zy}B4Hkm&|bJt8)95QH1`3fE3vq+1wV@7+KKYhYrubt7U0vE%=Ox_5VJp1F1R +gtAajk^mPJ7*P_h()tbnaPS?g~WJYJMdvdD{5RZ^!S^htEH)DR@PSn>__Wbum_L7{nt~H@P2bJQr-&4 +DpR)S7&HLxv`$3&%+B0YRjHpX7LZYI>LvK5?V>!Cd;w*~f+*?*Qf%`7MHPjZ$bLjS0C&~U +EI1#seTV?>k>pywEE-;N?OP~Xqrkz^{j<@U__Pfl);xS~ux98CyXEF36fF|P!I&IANV?Wf0TQZ@O0?Z +p4ORKlKgy939pyE~qeNBa~WKNVClC3j{LYQ{1;t0kZz#jKVv-K!Hic1KmZ; +R?jL<~(f(=FNygTKcRSA#=%=ixQd;ah{$fm0zDYECFuiwF}=kxwF +3h+<>K18*KQQHG@zknx;pAY{j%Lkyem-MZj*jgUATu9bg@GxkC5v(%rZSSIaXOCw +e9=BG244_^y

    WgM@p9D~|&=DeKoq<(tAWdh>0{k$?%Dqycx#KovMT)7bTMf1k6H4?Rvk +2=ba<3#j8%1G>KRO5oFTt$gCD;*|0i{}?1_NKvPXK`LHhq}4&)rtM+@gUfN2Sl?--2d0(RKo&w{A2T6 +*$a%Mpqo`G4k`@;*U5zra)4O +8{>V2~Db}?@(HZDvLa$;XsG_whu7&5P~k;3&g#>}#SGy}g}UxVPTufLc>LP>NuyqmfAGzo#_nG!rbJf +dbMf=$fYpiVIkIP?g91*as8*p{aEWZ2fZ?-XQjvRmUq=rbA*`7ScP$D+^lX3>`04AZsz*L$y3cW}&h-}f>F@PEhfDj3pyhCXG8+E1ijPZs-m-L){ +&okIR#1EnNfW$aRZW6>qT)KGKP2hjCu{lK|ECXD2ioq+q(6b{g3}O;ZnCkKf!ayd%+4Ok-Sj2 +37dMxg8^yLsP{MdG=fvscu$Be%JvDi^UbhL33ym#RO5WLWLHhS)}bNqCXJwDd6^XY-(s5MJjzdpojbl +R{t>3>cK@#;pFC4%T0mo`3tt9(=ykC3G(7_u7u8XQ7;7ss>&++|Oi*f0r{lqhxpWD}fFjI7<9)Pe*-znL(_MO6L^G1g~8_k79AU;QJ?tEokN3 +SY0&1Eot%Sn>(a;m*j>R`}iJ172Z!k29C=RIoj+WEF54t4(dbk7J{}-W+@b3Xum@+s?JA%7-(4kEJ&B +&7_g_%JDU!J|6wu&%%sJ?nXSmo-adT$@h-*cK?*hc?5s0IuDrD`8R+4pmQA~!z$D6z<3?_exbIU;`BX +EWwA`cqd#G~e=+{&V6E#B59{b425#%0#(9pIJnxU3M&3*^X{j@Zi1FP2}6EI-wfI@pmV`8NfM{qEp&OsO5DxH?vx<{`v0sacGNoq(j^S1v(zP;0|#ZItZ7i(%8pUvrqjPn_&oRU4iyk-gde +!bo>$HRSHIai4FuF?^AQIIO_61>c%%DMJg@>T6 +iLu+SL&AQfIKa5Q;$%!5u`UBS?s_G4~ZNo-% +J6lw=27jY|++O&2hwdaOX!Vd%u5z*2ZC4C--;nJ8|dnL5Fm$QD<(r2HlxHN^S! +x=iVX6mw_cgkFjgewO;UT&jqWR$gXYHQhxc6Q-q>An8#Ual>38`oG3=)=52i_)cwPP<>6~y2A-}Q>P{ +?1Dk|_iUs#u(BVtUIJUSCQ@1=94L-Bu(Uo=d$oXAQa(351uVyO7Un_ihd`ZcZdHA43xG2b)?^G*vu$f +f6re*}k5C-^>l9)_;3@fI5PslLu*3FC)S4c*A5Wofu6dT+DTst}X|+sJgdpx`_>5nCTLDcBk*@O$cYv +B(ta1dei6+yhLkZ_bikXV~%NaPs_FPA=EYpJ@z!m=t(dn0y@*Wel%_h8}@8>tVP-=!r)C0#*r#~?D8d +LlM&Y)tj)kF1ioPBp>42S{r=WNA#iE`oc$mxW;^yj3kCj0^2|Iycl?t7&AGA{NqkhgXc)GS?(6?hO9K +QH0000805+CpN&CRe#WMu}0NV}#01*HH0B~t=FLq;dFJfVOVPSGEaCwzi+m72d5PkPo5Lpgbg^9E3ddugdf%%j>2P6<@7x$e$m6`EXBu<3KHiAwpV3j5wvWdgdl=bybPSv|-xtmDT6_6@jNf +JN&2K2FF2|>B!XI;HQi?mb`O3Z?#t13+OHZ@AAEs)6j?}ZLO$G&#!B%IZsF~OjEHlFxzruea;3(I40z +8u8mOgjgnTYYUIn+QC5oOqv^J!R#C8EwOV1&xF)+kdg+1N_l_1*Dp?J2-vC=yF=NQj>@#CJo@&~7ACV +WtM30|!v$FeLNr?F^(+3FZ?d{VMPo0y_(zb!%_)sJS?`_gS3<#Lt9j@MxKhCyPlKikE-=^QE- +zDUA`kLg58yQ(rvS&_O!woGoJJehPh&7Q)(o%5EbXJOtRe`jR{2+{l^i>UcY%K@^ZcF&7Q66Qiiz`8t +w~foc4@EkN5e0#qGi!Amf)e65F$DsPkqH8UPk1Ap@TdG_xy<8z1aW`ZT)%bc-{r+2SLl|uU8X9PF$*9 +J?0NCx#c+Om@|9om4zvz=Mp&iKg!vC(1;z!BIX6~FCvcFwC>L7^1!MzG`>vAKPdT3BXzMLR2twg)qtR +)!Ic;UbvZuHgu?aJvOp0|0zC%Jyyx?7*acor1=AH+AsM!;T1na@ujL9xuL|Bq3t$Ajv^F*3&FQcx}$- +ePT%-5}?nW}5%ax=KvUw=qQcFcFZcgaM+>@lS}Qe$(~+TE|LGJMotKq9K@!h+7$F?Itg%u(2^>`;Mub +XA-{zMrXT(6UMK&OPx0B6qEG0>uO>+9qd~PgH!h^ro#U1jP1J^g!;ydyA^nqh&${ssib~TYx>M2&xvF +I0aHX0TU1|qBm-V%ll}HZ54r~!r?0oZ{@YlF43HqjicsB=aP)XqPKL)sa>neuG@tD?GTxQG>a+q*EJ;IJ +o#7;vL#495*Al`X`{HH*JKzVAl?D{x|HY$O;890z{G>89!Z%a`z#<*+c=MeHrizpGFLVrneY7OSj`BQ +HOiPmykQxQoD5+)T!p!}2Ew{WH(6j|2E<`cj!j8qpC!sn42_FUfgBEMN>*LULFao!AsoEi6(@d$pRGp6Tz^=gnzGw7}-W+Ni-ybOt#0uO1e8`}(B9 +P>cBxf95XUp<{wv&Y3}>ZbR7Ug?^*!CME^blR{8%RG1%&LOc1f(LL?`~8l8c +`pIQNB2U+aZ$@-wtwu1@i(xjT^lG@HwfS*vZa~Kl+BVE1ho&SHn9M8-+NB>c&;I|*R} +6Gm{eG&B>UP^ukN~mbsM+#n!)-I?uebO4nFYL3I3d=x?9w{wz*mT3s6e~1QY-O00;m!mS#yPz +TPkZ4FCYWD*ylv0001RX>c!gV{=}dd6imikKDEq{(irLxWiSFy{ogEwm=uS!j9|21%f1q)1<}v +pl~Hh%bX<2qI7%PqW`@!e32-LyLY}1ww4+WhcnN-k;+?9ktE6cu5VeA5MDK+?FijTQT826^zVxcGhT| +K;B{etcC2c0UNZYz$he{1{^BA>wheFMR8%lx*-Bb5ML)b}k11<9E^29MzNXnbQB}0gMylk2)tP8x$sg +lNJTMveZCUc2ozu`(GD0QM!-@L+{OK+G+%wrZ49v)qMMKkjiYka7SSvy9g$U{)F>f7B^c^pUO=es+B| +Rpntrcmju4RtA59vS%k1O(vX7*0hT`S6qiwlqv=JSr+PIesIaU|&LQzYgM@IiC37D$X;@dwxX{ +yLTf@B&>^ckR0Y}fg+mIA8A0(jH#fBHcv`Z!01&fSw8f2nLSL}3S*KcssGpnHfBMUxU%iS3c05N3H^c +8yO)FBft`zBtXygD&+vAGlEiEb(Oc`5QH-v|1!U4EyCNV%+9(cD81EsBKx{{&=ZE;#A5-h)0#=-Trn{ +~^rN^9AI41JZ%y66Z#SH43;`IJqVl#0m>jbZz0WmMH( +TwPI@9I-JTJ5?>m-K*)wM<3?2Y6;s9v@a;YSb@iG2SY{p`+3#bG5aFcx?W=UuIcdVf4(S&Yt*zGYAm8R!jzNz+zyBl}ZA633g(Ombkjl@Hq_DS{Mu#kbc)rj8K^C +Ys~tgWih_(+T&&(Vr$V20yu&8#usHRol3yw@g)YVY2=^de!*uOfYYb<0R1&Uf<59!)>QqQtAE!`3w0N +c+jZ`i9>4IQ6-f`-?Q+`?y#O_{t?L@bQPN;(B^w0sheYT~&lnv>R?2Sb(Y~BQ;2q9Y1_lzYplIm8O>) +sPVt0-}zy!-`Njrvsh9O#vet<5rYiXTgzNzRDf+5R@XgL%IiTI7_9Tvn=Xcl-wM@Y%?ORn%%00DV3?LEXKMJ5b=qF}aLyeAN?*R6e30mm +D%hE>n24b~x3X1$=@-t?Kictk;@C`bLgjqrHs2S`|xf99?zVUP0vzUAoI?429$1Cu%@(8I3{()!os?p +U7%4+BQ&(i~?2OLY{%w0?SbG +1V1mAEAR`3ZZ4T}mIJLj$O=QU3BeD+4PhI#O%)ZDP+Cu_OUE3uq&U8?;eVM87cp%Lc8|?Z1ul;U)Xua +n_q5HP2IruejR77Rk@KPd2=7HbFl5eQmz@3Y(XVv7T!oMf;!pWJ|C +H)jr-GH-VcciKYJXiv^^SSLH`jf6}-0^ICrmJJ}&!4`tb+K-5O~uLT6slry9hSw@q>rzquc4m^>Za!P +8U$Lmtbj&sOx2&__{ArcsAt{GiB4wNhDR3jq`TUZ*Ps%o;lc7gG5Z>5AvQY{t=+dOlNG_DH#8N7Q`an +u4&rMRy#g$#b}gg#ZiEF=ccyLGVTtYQJ4Xr1jzAylQ?eNjhN|o&7)%YCIPv_9S%GS;>I$?ZI;i*f=Cs +L_w9b-#sq?-pb%%8h!~f>2%piRB4LAY9IMf{i27x?MW*vG)b;bhqhzn*Ax9L0o;S_EOFq_ZO>HmAS0# +GIdC<09{Zxt{B?-WGNuJEt{NJcQM$m?k|IigZ*t7LeqsY^|Bi8?m;8v1(okZ)+D@)_=Pd1L$p4`t^Zw +bs9whHk&_0b(>9$Gs!v8N$2G~v{96vUiFgaD!zcfb*!hjTR43IYvX1!&MIA+8OCi;a~{4ATT6HcytRoI{{7(G1u8W4yNm;>@i_T8c+ +!V6B@jF?br*){g4U{U;^t^iZwhltO6GST2!@x~b?c*PZv*FKOQ?f*w+7nh<&-Cr$`H^Ut +)r&RJw6zf?qq1>o7r@f+ET0Q0n2-337pgooAymHgs{Ij4x+ivtdb{3q>1O~d>}aNdC4aGV2@mOGCUz@ +V3!D@c?Sl)-`S-U(fHmjU@pMJW%f2o9_QRn7g^%_iu}p~0A1HoY*Qed_04cxC~%Xu_=XbZ2)$}WFo%K +3J*-fpn0OXS9XE6SycPfEXRd=AV2B*N3K~-Ay;}|f)3PL&epco}-Ol1nMwfnQPt5MSubht<*Pq1OtMg +90^i2$J=A)I+;@2B0POWIhEHYqu)rpVjvs~xtu1(d&Hz)>gXzeKq#|G7#PeJnOS&9dJ#=Vg^F2#Yh;p +CJRuV6Rx{=;xqA6Epbd2Pgaic%Cw(~950cs97Bh%t^U4~T4?xmI$0jqzSw3GJkj#?NZG5_nEu|(f;6)+@fyXfn|yMdC{M%R2N!M +^2n~=VW%#k_P=K&=p}34?1k)byBqv9nqC~G`K6oG@i;Ea9eE0n>ipkf|ULBaetfQ6&0?oh)lOuk*L_R +RANDoZ4#}8PW>Wc{d1qMX4O!sg`pS;tTeyAG%^#m9(KouyM+H!C4VGfm`y^g3)X*LU5&)JLqy2CtNi+HM8`$EaOUsJFFF)J5PW9dY+>MHFJK4;T|}hthr_-$P=j>5o=g3vbUCI^ +yMecB?jS8Gg@F>bK%D>`UzaK2edt~;Z9-NWjnQ%(@$wNyis4#fj{g;Ht5BC1ty2Y7N(^;MDUg8boi*FaOECaR>u}>AC&#F27Iyn8eEK#2^N#G?l?kN=+yA60zid+;}x(4q+>x{Lk;x}eEQQ@e+OB*W-=Mdn5@{;aKcInvLw*#e>i;IhgRDur|9Iq +n~1<}R-0Z>Z=1QY-O00;m!mS#zLVrm^>1ONb#4FCWX0001RX>c!gV{>S&f*`@TqS8{I7WcJcqV8C%?>67$X(o{ybgwm>az +2TG+(RSK6!aiFqd&lYU9!2B6)O9UXJ-uo>tsHN=N=P0>6>986m-kLcJ1H!M?Ie4q9dk`aOzRBii|DDC +1!0+y-?_0ut2?cn(Q=V1^;t>H%1IctQKxBd0wH?hs?;X8;wf+SiO;GFttwG>%vf%sC_-PjA&1GSyyos +_zn4&|SPS7uL9CF>TJj4wMQ;R?$r@XF8xeR=95lsE9sBoEm}x7Y_6+YdopuYU6(9C((eM^f9!P@cGt} +~-ajpxNc3fNAOe@EnDE3|sV0xpxBK!$mO)QsH296aVq}2!#pPQSTk55C!8cu$yJt`}lHqV3&n-EOmv| +pCoI-$IdSs7@UwPDsN_zKu30_5#uiR&cZ4_FW{q-75%r(=jN?^VZ&$7E8me0An|!8?naUeQ9gEmLK(` +ijp(%uLaU6OR|Cj~TIzK2z&T-Mhn&Oj@3i;#?lKCM$4K$_ujtNdtg$knLHxq8WpXG0HG#Kx=-YxkV-dV6 +qSZD+XM`I#97cY8~j_)hn-Bucw6oy!#u?*v?goxO!$Jmwe-Wh-R?XkgeI%zcRau4E2*8t=cxNAe*g%| +K5iML@RUz=~|wd3MEE*GoB>3YGtt`1EJTfXWNL0Mc|TfW6)nR9LLl6t)7wiV9^eF5hAm4nM%_ar1rbD +OgTP0*Qh>fu$L;mBwU;@2}+M!osWS;}EO&1ZsBiNQ3&AT(1LJs4BfmQK2e*ji1mVfVrfp!JnNSm>6dp +LA1Ep42*6+hP~LsPG4d)K36z0G%uvcUg;HK#sHwwG`aJ53clP_8{RW^NpgKa)_v1*mQJrnP3a-*n%umB$|Bg-zBk&LM%$_Yw +9=3-7;jBC!x1`i6cBEx6Q-rhf2-s68ir{Y!3}iKg6|yx?9%=L!P)h>@6aWAK2mm&gW=U=|l|dj2004$ +0000#L003}la4&Xab1!psVs>S6b7^mGE^v9(T5WIKxDo!ozk;w~NILH-af_nOBEHKt$Q=Tt*CIu)1=d +@EUU64COQJ$jyLOBI_s$GOiF)xm{Zh0-5NOHaa5$WK=0)BsS+XSAH>Ob{NmyRiQW?hYwJaJV68n3xXv +YhAIONsA{gm3hDY01WkyoA9adH$@DpjoW$GDV7q2opsMSkzN*Ia4AxMp@Zq2J#6yh_ERBmR_E5B*eQ@ +3;qOrOg18oTZ!EgWL=pAMtj2JuHy)=OZKx+I+xXZSs5jZ#UjziDtRo61jJ30V7GAE +cqhv`FGLu?;O#}Y`TNE8I=ToVORdClN(nDzZj4A*Fb!+&Qg6i^Zx#II^QScnxgBo*B0Zyd|9MBU1H(cZ%Fw_*HE^!63L!K%dql`Rxdwpx!5!hE8!Fi9$2f`uX3uHag;KR5SBtLb +p4@o2qZ@E|>~3P6^C2GU%)vA7#lqLzsp-eqFM;|Any1;yv$;^MOaAF4D9K^;rxv>GkhDHEW+ducMp;YAw-s?o5bTMgHw13>{0XW}v9PkN#&r?*A*cqvw*6d0L?5bnfk%E5e#(-9cnQE#84U<=CIN-Jk@WerX ++U;^MuQPc{v`K;8?GL=rVmK`xjpB)@j=2KU`e*Rz`=5Rc)+~4*{HrI7y0?;>T?R6Fz7T7{)h-LIygg~ +YCq>bU^2?qYf+>YW!8cDCI&?c{lNyp6x3I{FDdl8tdw;a7oN2r%Iu0`-e8 +gHb7r)XqJ77hdk?1VQaOE5qpcU;jEw^}DS4D8u3zK)J|rSV9lbK0*{O~(iE%nQe1G&DCbM5$vmhFCo2 ++URgbyY9L4f(c8d&{Y6Pnm-5>g3JzYp25i!;}s)@n8r-`bnwYmtG!e^!S?wh#1NC^kQv+qlN01EvMS* +A(p02y0y_Fl{F@0ko1TQzqvLZPeDT=?*0_Q#yB=KWHQNkyx}7@H1e`sS#YnQtT9ZYCTXtsUw(wLuk#i +GR2G5FxEVtf%O`UQh2K#;WR(9>&R^wgdz2SM~?cy>1AMhG5XIQ)*0nagMQ4fE +f(+IIhV7j9MzVJS|DQWo{|E}65n_MEXX1N55`nOb&A6QY=j?506w@hEN{qEVt--`g&58J`6&eMAa~BI +MvPYms{my>zxa~<@bPbd_^<|0E(*drc9QA=GuMi72%@_Oeh@4J=vyH-3{{wdemCLtAjlF|LHvsZcl5W +7;WBd*!d$djuWq&x)Mh8B42HKjHS(VAISmoTE!|TL?^70iGJ&X>)C{)btnkLO_8z_o=jC!f9c$I +e7G*c7hd2>&=&g&=}4!D7Gr5~6rI6c;#5AQNNfPJdjS?grAd-&eiUT8O2VmOZseb>I@)z$Nc}G;Ke#f +sRCQa-Xy-pN3~Cn{tRX0aMytbw%XWVBLte9d2nL?TgZG8*XRpm@?C*|b=<`m;sCn-Ymn@S8l0p&(>qp +yWV0;gC4t`lS4Pe;kvDP@FXOb1Tgps}jyGJn6x4mR)Y6Nh}{&o8G4d +xl+(?1V(m+T{yb8x}BZEn!j$OiM}oN$D}VR8M09+HvaN!U<6K-TC2joTkE! +Q=%J?xAde9YCAK46DA;q4Gl)$Jy-^UQZdo-kfg_kisp))=;}e5RG#ruFcu4h^U`;8??~#OpO4S+^@ME +ZZd~Ce-#00P;oRNz)jF$TUU}Rw=P6j|D=s5sRo1eXoeN4n9O*r)c!E%+X47oyeIHO1=E#vmyO}4ue2a +%3=vCH3XB)?tN;WsVREYgd83PI#)!}0+NUJZWMmTcy}^0d?XC-xht6##WY79f*LoI@JJBYiZ3p^e1wL +IAwBmzOQuQLah=Z0h4rjfQz8KP`m9@`!WY|=tOUP%3MA*FF&j33&93;bnh^HP}QBp@f+L!6y-a^s*Td +LN{LNXV2I+4jz7c=~!(D6?b;_v_pe-}hx2D9P~=-zxK-OcNX$G4&spun)?b*PQ9c_pO$0x~Mg!zP+{) +!pOk-CYGthSrygf(XHk;2$aoOo*vGb-oHGnL%^6n5*Em~P%|BkO0BprNz~CvcHz#J**3 +7-WkKsjw*Wb6^Va6Airm?y)S!v1QO)?7tMa-Xb!Y&7@|!izGkKA#eGa7mXmx53!+L5L&NR{Vm{*6MjR#upm1{*6FplR0yTC9rw+405v!_X~ +Fb~rjE`Sf~9;t2{H5emsUGC=a&ZJ9hSR;HpEOsLF*p1w`P(GIsp(uj)un@%h!iNH`X@>vL~C1EBOlq; +8FFDRcAZnzQs`?j^mWyM1Ao;t+@w%xvtWlO5X}dx$KpGccm|Z|E>MX72>%_jmwENUT4Sl!`x@bms^rh +fPY_{_>;y@bWLdkRJ&Y5?7}`X0ghj(w{ntO*{$D!<(Yg}3P`uoPMBxAhJK>m_7XVMMUXg2O8ae84jL^ +e%CBn>?j%+EE@*kCvB$xYy+Sf9rg*98LnQtNP=yrH10$1x2OcuEFZe-wTrgbVA~XU>!Q`RJ|6$wT?I( +x1^2a|5uy!%%mC`q?TBJ!O3|Ijy8h+eIe{X#|!v^gd}xc}JN)bW?T5ZpE2cIj&qR7G48t+KRSzGHxvo``DXcr2-)WfX>Mk3FGNLCLsCglR7p=xE^>2pl~hZQ(=ZUe`&W#_0SRs6dqqL0Jk(o-mUHVmQ^ +(+VB72h3f6q8+Nf(u6>8Z+mkD1S7cfM1r)k>+y24TNFZ$CgnOKpp>##+5?n7h2xx-<5NaXz}LJ99&^q +U1D29Smb;ZTplkvVOPUDJBYVqy#=@HX#TJwj&8970i`VZ(zTf>W00PW+&f?M`tQe#Xum3fO^)d8g4`J +5rvOrd+C&)k+>k&jfoBexqlf&Jmp)9FP@wJ09$E$rn>QCB{}J$P^2#KP0l^SW0FD3+|MzzFW7t`e#@A +kHGYgM_{}IvvXNo8{T7oo|%WC-u(h`U!T-te^!HU$uWXumRZZ~kb3DVgE*v7C* +M6LWcv3|0mSct$E-)@JE@WwQbS-IaW^XTLZgg^aUvO_}Zgg`lba-@&PR` +FO&d*7WFHSDXEGQ|Cct$E-)@JE@WwQbS-IaW^XTTWprU=VRT_GYIARHwN%?~6EP6|6|+xmMV%W35vdi0A`z+3h +~y1bD|dIgG4EZ9xaN2qHw!rc-vt +PTAaKuYvzW0$fdEeBKyM +JhmCN+4zoe~`zTe-md2X8n|{DaPZ;kFeAO3t)(<#qtpX +BOP)qaOd|TY2GdyBbJz8lbo(h|McxBpF=sMdrPS~WlZln#8ERim4WbKKXLFU}`?$WP +Ka>drAgNj_1Rd%tdaNDK1aD{&Ax)!3TqA*tzr9<(C23Bjqx)D`+;M;GTKJ~@6~WVVh_y4y5KKH{dh?S +A}luP&Jb+MoPZl3eWGIM#_uOWG}_71aZ-s^`Q&jDHmJ|B^oF1Wo}T6}z8MO9KQH0000806LatNyi_T! +Ug~U00aO403iSX0B~t=EjcbQE-@}-X>)WfX>Mk3FLZBkUu@6aWAK2mm^k +W=X5tf)if=003?P000>P003}la4k75FfK7JWNCABEop9MZ!cF!MMX>t&qz(p(G5#2D$dN$vr;hBGvIP +h%}XsxEXgmjQbCrr3t3TmgXgG|#p%WOoqn_w|Mi$g~naAxx^+zPrIJ#-NcTSc* +KX>Ib3ONR7ccgsBLZDqTDGhGY_~`OScjRw-TlIzqGQ-2}T8P5h?4!h`RRkdncNrrD=KmI7@muKNQcuJ +DBnPfsBho@%(Vci-Q?24`j@1U7;V4@LLmXi=KVNFRe6aqkv4{GNqoLe3f3%xjY{J&&L0Ae#|INCv$?o +{>vGWfJ5sj=H%v@mOg=6WuJcp^cYA}I2vI`&vDwI-_*UJy|?Uxw3(6Gc`JN#nV#{BZ}(wMhcd9vPIuF +oSFbcp8S_H&@La3dt0(apl!-Vz2ntuGh_Q+3#FMW$YmK34#Fr2EY%hId$M7%@_AtU%yJU_6*g+8D$rm +qOUHLfV;aX+wv;{j|jL2C@dqk(Y_`g66uIy%r-=r(sM_Bk3e4-Y^ORt@=_uyTP@VT`u!kwW)eck`Xh^ +5Eck@(4?0WaB}R?!dx*HfSCb$Ap1L)q6&!R}B;T10e#1pbi7{NpTvue|}NvA-I`M&-!K?7dG`PuoT?# +yQB^-(1txCF_FQQeu@`-)&;bxElswyMh5g;)E&CZCrK)*<7`O;+J&~_q64mv{RpJVI7*Cp@2J{cAzwe~k}YVAP+Oxhcz%Mx{)@Gq6FCyApGi*^p%*+kyBf@&ehCSZh)Lk3 +T*o+1TY6&yd_-mL&+dsx$lkZ+NNGF;aDKf7e^bBtN_!!eUvXGIhM`6*Pz_8um{7In9P9Q6VV@9c(o<) +;yt*9k5$&)50!v_+{M^&lS5Fm)svm77p`Ov8QUB;>4)oQg_@LH@09;s!N1$az5`!`Ta0|XQR000O8I+ +kWh?nZi*UM&Cs#$5ma8UO$QaA|NYIW90RF)n0jb960fZf0*UQbj{gQbetMNt2_<((V44eg8zdk9kJK0_%O(om2SoOwQKn5zV>%5 +zj*L+Icy$RHkMu{*7kC9a=$T_1Y1r&g48s0GYLga$&@o6~p*pxoBIJsx{P38Lu8 +m!RP>i9L6B|sNaF8N4P!7)gC8|<@`}b`6LZ9lH{4JqU9^}wCU9Nq1Q4@^{kT5>i^lnguC&g!*wMeowP +ZRcEQYq@&)B!&ir#~lk-1J}hpc4dV5$>DwS@f+Lx +l7bq9-B;JdD68gI1n=Ml0w4mnp!&q!`}ddwvF@t^)vURbrQTg1_c?d+b+2eaka*L)JI&bY501^p-~}n +J}2EB1i={b5irh&v2R{o2w|FOA={{n-IXz0G~AyI0J^UBrM^1DexbpIBFH{7w#7=o2>B5&Z-Y4Qli_u +UOJ0Rt#Nz$3ux2?$H9>8LkNv$WU9{67Qdf}=daJqA>5c$E9Qz2_^l{QBahylv3n(HD+!SFpA*8%lo>G-lk0229#+1{VABd^mJM0} +$SY1zES~~ND$rZfSWfM2|JqBGK(qPa0S)bfjEubkt7a%1RV0$AV6VREPD1$fJZ+~lF%a$4{KhGUbr+s +d0ifQsX%fh-GgBV1Dn5n1dDGqgu6zKoa9gKgLIpEVNsHmc`0S#xx#YL3jB9|p-XGQ +m5B&~&i_b5>ine-JFNS1^dD#7cq8E6fz9;ucfx(xE=sZ@Jj)CC{M78Un6Mfk> +7`VnAc@HfSg2W9?vo!X0nCFPN1&T6tQ!HG_ln>Aj0o_A1{I$-8G6t3_J!RR{dFckjX1bnuQ)ZHf^HXR +>DF3c2X0kY>g2%PWii4qa7HZI(KFmt)OP&?$eUi#yg;VWmIoZ1@i%FMgIY{`M_BfemOoWE+Rgg*GIcs +J@phcNXPS740%Gskn9{dW)G24+g(aIq*IZi?IOdVH)U6CAG4b+OMim>(p?l(F;uxP=51{#{J?n`X-k` +S6M7a$mZ&IFm|22iMX(x&CtNSpcdNDZVcU(p}2aA=GepiFV|B)Qy_5>4Pfx%1q>XxcBBfkiS|b2c~+j%bii}XT0%iDL-|0n$UvwAWAqR+kQvN(rBK +5ZS8+@u2^6r@n_uW5hxiW{^AViLr^!G0gIf2P^Sl>8$FjTTsEVQ`nEAllEQSd +&CaYXY~4eC0^<`fl?j^n2JXv{$c13vS`fZ8?G+Qe&Fb=k1N19X}ggJx8bHa#mp3vYM`A+#LqJN8qPYD +)aEGWw8&eL{;f)E*yQ(?5-er;DJ?Er-O97fC65sStPqDXR*{)4S`?dehTW`Ln<{gRxO3!-+WM}?fRCk +n3P&!TN^j?<`!nbxQ12=o5I_>#=VIj+fO3OIEcM*5t}()#^`*8wpt#(V>FUGO%0*? +dMHK8^M*Kv6uPW$;NLQ}&@%1vtDZ9#Wa=pov3$v8QC}$bADFiZ#P(KVi2m}c9YuF!EM)N`BW{l5QaB! +AMrYK#KUhmNeZG{Gsdcdl3-0^_QxPrw4i0n`h0O7BZx5_iWCc~?d;f|fWj4zpRzPlcH@WM?JFjPLLN@ +^`m>j6NtrKP9_i5<9=Zr?15D(H*k!;o{Mx1FWE+smzx#PfwvS)GJ@#ZZ>kI7L_WDACNG&Olw+78~)6i +K}D`o)h?L3v0OIdInJmLeqr|!<|I5?Lrft`7rUM#rPX(NNs+TwjfFn@He*DGnqb+X+t +hqKOHB2MS~3n;PC)G(_lVI=9sxgRF?tz-gl4Eq{-h&I<6UxC*)$<(WGK5C}A>fQuE5@{@u9;&Mk=}1x +~+6+7B1<04J7K7en+)v~%H7lM6rfWtMJ(TDp;sh(hW1PKsdls- +RDG2|7M%gY<1MHjN0n}pMWv9li)Y9h;SrFY{>&BznQsd%wG#h7Fw*m;hi&0;Veb$$w +I4=%CzLXR*;T)G=r+;89hlXutOn|{KlE*ZINvS_^Z>UX?C*i<$7fBn5CdItjx}B#Vgl`w&Jv$IN)@J- +L*uv`VYpzZ-AGNrj>=UKZwb|b|a*l`gGXew?DX{lBAZwS9}$p*X(xasyf;cC<=TtVarF;*1ncE2O2NO +2R={*=*Xe`@Wk|t7*MdD?>@k5SHhzQHrBtUV|W>8av +0o+cW?q8&_v;5Tu{4}+*^n|}N%#E0G4kIfU0O%9nK(-@c@*H*hV*z6%|t9f{Fzj`7xtHH8^@NdlV4?~ +p?(W}IBl1NbFkW)|V`J{o@BZm~Fe!@Sp>pV5cxZS~m>IKq?LSvSYy@teKJ^g +OTRtS;lmMkk@&N}DM+!P|8kJ&Gat9~th$ro^s!`k&~U{$v>zPg*L9Ct4GmeP +;wG!v%5$)k1DU=-Ndve&}1n?bjo&{sFR6OEJ?G_?*(5}uqp0%ooTd55;pY;|4>Kl2V1e6sJFryx5R`Xt@|fghV9skh?kwZ +L(y;KUvntcy_L+>w`&RP!r%;?n3In&wrBm+nw_Sxa@u4#&{%?ebjpuW2VdVrms&XQ;vO^a?kFo0D-CciRQF$r^icaSvQnaZs#7Ru(I}pUd_ie&o@V|=HS9GiIhX9B +)P43jo-U>zM45d~!_yE?~TT1q3tM03#Ct=%KK|uVwvHN46Ctodd!ZyG#N*U}Hx{5|}ecEvQGiiGBP8w_isJ_2YP#d-2=T;y4-ul6;bYvdQX80&Iqs~g +*uZB{3rqdR0)EY?TKc$S^PWq+(Ok>)O=aOBRI1S|3>hKbFlYKp>p=9NGFq?7)6DuN-H|v5zfvNXYIaQ +EcqmB5FM&$;z$hd_B>)qLJL2*m{Wx8$a@(;lrCq6>gJwzP6!bw& +x{COE+eg9sH@3{e=G4AyrVmotv^*K_$ct+ohr6ve6cJqQ#?U}L-(>JMJ>e0bVw7yyNlKhO-pv +)ca{GjOdF`>evM1{UXlFCam8@Ek`@J+6=Op0f$-I*P)bxo@={3W9$!)RN`fifV)Cb>by$1TegI&92J{ +NjB;7ey?jJu^%c!`+J3IFRINO7yAM{&nLfg?k#yGfA8#m=_w^FN1d_>i6$dSG4m7Wc1%{j7G^1vsY|2 +nW#&N;OExLHPa^bdmNcn{>~&KIvxSLg)P`MWP;_QE(QcTH(#n2}?zwe#64d8oD7l4;yHz~zGUaQMA$Y +B};pU3Wb6~jwl}C76r%AYoHiTsD>5O|RnWkdkJ9?7dkuBq6-}&H^A)N9u{>E5Vc|e-JFjFt%1WAuC{g +^v78MV@Rn6mn$p9DT(0B%N#9gG0qdE*C~H-AUw_*VHIboGy>epsa1Df@>VMWY$+C3Lu|M0;TZ=fvdHZ +kzRQo$v!k+`Q_SvkNOje!JWsv8qKxAfbXjOzojj2ob~YD8{7fc$|ljOm|z&{JZJ+#gIIId*KK=;czyV~NR8V);HtG=y`!uO4AKB0&(S;?Dt8Y(JU60#>+nArKF&MK-#LR|h|*Q-J7baM>I+i7eT +{KXBI`H>Ky}*m_F*cbr={S3LGV89#Lbpj7vgTIiWuCKE*X^}NJ*X}+ijThsB?5(YRep4g&l$s|HevRP +Ws?t%heb%$1KYUs}aJ~oK_liLu>Z{t@kF7-Fzy3@Mmj>!N9+<)u*V1Fp$R59$Lem3U?EHQ%dsg;s*k} +)jHK4^s`-F17UJQY6pGdD4VEw)>2=sC9`WEB)}|^d(E`r`mj%8Ng$?7;BCyYXrifne4*9>F^e4uzn8e +bkhlC={QTv0rQ#wJ?kq?yb@0{1m0M?}(} +hHX+0_JhhXL=q(!aomuG})}7x)ciDurUWK)%%bTm~jpZBY)F@@?j6Irm)PcWH+OghBcpq%#UbU4suYw +Ri3<@!+BGUVp_-y!!&H|2d&B_HeMGlR#rc)Z1$)s4-T3Gr@`u*DHgJ>Gj4=eD+DO2Afhpmqoh;ordzZ +4%|z{Nvcqlwu_P;{;zNNGLdu4!mMoyg>HZW5=tf2h!F#GH12=EEoU?{SN(o0|BluXVxlARachSM9{IS +fgVQ>{?R)hQ#>z%>&g!Y6?C>yzn3}xz<%DfJuSz2b+0{?X6nOTQL=M{L(xm{xjta^-n+)&C6L>?R-Q^ +1Mc*f~Nc~?M_+O^(XqottK6o{GGK(tZ$cSr$SfG@w>}$`oCG*rEHq@fek^ufZpM8@)yLi6rV5&g?M`V +lfnmI-u*JjIew^}=-rwEHiKGZLG-})_48q~9~W>W_1=~@?&0*uEk1)+A?Z8;^@OI*tf=t(Puak`(>HsmL&o;34K9pa;S +yHwi7af;m*TpmEEo#u$A&iuAF0G=1R}YAcY)EG8Vz*Uda>$l*2=u)H=_l~e=5_sH#5rw`mL3M8#qs8? +20dBRWz9{31}SMWxKM%5uR>x;Sh2}r@D2Fsf5|X@y(;2l->oMn8p?o;v{|A=UE@NR@aKTgl+ePBVd(M +M&V?<#L)bUSKMRuA{QxmegOvoe`xzQAzwtCy4ky`BO9fhw>7-5=G<4C)%C|9-`1{fLKhW)~9MRG$uTL +#QWU?&D>HrvyEcGDYsu7~Ey^l>vO>|I1(!vhK-+R3N0iDL|HJcygQ7j|VTa6>WN*8)Q>IeBm277JgQs +oMDrWKCfqKL|l0N=M_exXKN?b>gFKdF8KqwB-rjQ*?v-f+nsEU8k$()|S?@zO*(hn`{RbRrB;VYgBV! +QYGIf1o$uSL;&2zB!K*d4)qfK@3k*ri +;eFqYsO6*_AUv|K*d*wJY)Y;t%&~c(w*Q8Lv^jRue%@!?c7IrkHPm8`3p1VWet+Z?#^(!oYq4VSJqfQ|~y$tn^)&>TK--R+h>ShRQ^>b$G~2x+RfK9ewJz{2TY +L%>7MfwX>vCjp!m2RE`2LZe(lHg;W;-1|)N+>(rwFV7q=lPS^e$-u>BX!y +1BOqVAx*}f}G$O!NN4uIo#&5=DQI}jqj^ZQR!VVTstuq-9l-dIp|Ukw;PKx-BSL$u=)*O6K|UN8I+ +PLh_bx?a6m(#y_@m2vXCpoigudoSqq$M`PgGQ)Du3gpBzOpd0?wGVeq@e@&)NzZbYjJyZ8K(Y>}BgqN +lac#PZysWpR`3mOW;0uBF_eXp84b5c*v{_=4#3S>oQRUBbdy4S$eV^Bx1_y@SyMTbwzTvZ#C}n=A$y2 +ON+sq`YrV{)Ve15%SZ#ampOa_XB=SZra5d%rFXYSpqfKu;zIfs+*;5>iha29_|jr-y4&@XG@0Y6IX|t +kuD{62ZPSqJNS7f?zh$}Zfq0qC*n*(tmu(h6W@p3He3JNiW}GPy3L2@<&Bk8qP&{d`34sjiJfi#5oS2Ik*5PHA$>Ra623KEr1Lsfseavzo@(&bR{lqa ++!GVLi_{Sr%#*OGo)e1$wa5yX}!41-Vo);#3@8Grv}2Mqa|60<+XzT{Iq`^l+$nvG|=0(DNxGAjo<11 +VJOcd8)d!bpmeXX9veh7Fx?q>L7HM;xZ4r|-n+8?#P;dqY^T08MnJ$WW@AnCP=fVt^&1UBj3ee&6sL>o8Ob+9j2Uq%kK7$^QAS)nLM +aaE7Y%}wFroGBYZdUceH8i6?Z`hel|h|`Q<(;R9@IZ7gxBx8YXgOom~yr=H@-TVLZ^}w6;n$|R4sK*# +KLq5CpWBlo*MmoG4y1O?tNaCdGt8fcTl82>Jp8aH#@# +_uxnld!Pj^9n&pKv7{!X|r@c5R&@lmQ%>R6AkbDbJd#e;~6oT%a{t+{1^731Be9<~+qU(Ds0*Wf4Lhh +ReFPb*IZ#uSS#q*lp!Mh83x^yGPUv=l6uFWq}Mr#lq-wxIn)SB2jxO|n1HH^v^Sv(jP--a*5?3knFj; +bk9MUM6Nrl0a!_%UdN1z29N@E#vUDmOk^wL)GM#xm*=drieD9dD{Yn(}z@@%wW->)YLc +FBv}w7eQLY%YB_-q{h_dR;~6*V}K%aqbODTOt`KA$JQY{9kzT+qVK0a-!l#0TJzEY<%#LUnn~BRJmk8 +796FQBwXnwEJrJN5l|uKKJ>i?8z{x+>$S;iFSd+-)J5LzYaUV3K%L0#c!T@15dLZdg5}6I!cJ$#Y_z#J +e}9!k9nE8Oo)<;45yS)p&D>5q=^lkv-a(#P?Zd9(p;B`jOhDjMQWGwHCEU6MhBLPK(e#F>VG6QA81pESKC6k +3^pNI&y}RLg!#wJOcIUGQf~4?2iEAQ?Uu9&jXAKdSx~>M`{!oZ|8j5YpZT +8mW$X0gK9L%${(4FoSqWlGOZ-@cmpG_>h9~#e)mA$$?Lcx2JAK$~Iqtvl?H`==SXOV|-S20GQ7+Um%v +UnN_d*s*wn>>4HH>>SMKZ}f$yY*(QDv*t|GgXhq-^ia_MOA<$|(*pl>w=YTxR`|o!EoXY|23;!A`z{G +AA%B=M5x^AgJ){SN`+vz&q*CL?2E`CXF9i%pj(_6*8njl+bb_fQY~y=ID`I_J<4gwAeV3P&@R~b<*EB +;BR)^>ypm;&Zapi9MCg%SA@_rs1eYw;ioh5zX5MmQCUbpH$LOLlS>^=V=k3`9yBJ$?LfKJ4~Hs}93-v6NcQiR|KR +H>3SMK3W-lD5S9zRj-;bP9vk<@y6$IikPy?3I4eVf1~@9Ye0*OQB!D1<$h?9HLbnou6sk|*_ze^qhkaY)j$`2j-NMz-}~SH$T#+ +{S1izkf{(o6%OKJ{Fif?ubc@NT9ZK#n$82|+>1bHNMwXf_PGEnQ{vX($>-KfxR>Qx|x@_tcXaNAWh+t +Sk(j*^i2JH0NiZ}(D?n4qUPxT1>cWY(LtE8D;XD)9j!EHzGemLTZ<@bc|RVM_^+8Y>)EauR2e>BKg-G2%OL!C+Kx~sUs}yL?v7(Gll6cXly(aN +I#RK9poKM*V4Qc!9)8{k{_W7K;uHFDQ_T0JZUed2fa5uj2$^%z7_jX5itVQ$0i3Ec3X=QQtE>^`8 +6&)IlgPP19ya(WVLe*`b1>Cbs{^-5O6Bawb=0w$Yn{!~PIN$fBbgMI_O`qPl~ew=%ZKbH +ReF->gGCiU(vQNCfD%@XvbWcT)WyPn*&c);0_fNY~trvv*15?S+l%mTUSAGAGZieBNbf`?!2VO-ns#K +hx>ic7>@%+;x^ZqTTw^+Ecbt*P4#C3jt?TbJP;>tt+*axV{T)8;W7WLDhCuu(u3eR0T?gW=-G5gynEd +H&G`pvYMG7>!>w}U?5J@xme``)q9C#A+XeUvcg2WO(7VY0Rh9VZ31n0tf@Y37eL!p+5x8w +r0$t-t!PzI+4I7;xX95N1tIg=3<0htT?i={G~nZluB{4@JSF$03c~{k(?oH`@DqC#`i2Prg6H6+_#@qMeD>zOTqu7zxXLc1Gf;&<3?bejaXbMO^>aBZ~h^h4KsFdqABQOC_TL9JB_Hfb$J&js862Ap~g! +M4m5}P?7SAPoI|3aGd~npJA5&1d`@K(@aE(VQ;E>4$V7YFa+n++&@Z +&Ah8$Yy{E}|fAjW_^}Q%j&cG@D#)#=;s{4C?}TxF%Hr_3RA&ncshceH96=F%Q`(ePd}tHC*P5UyTX&# +NcqS*!x~Zt7%!83#uGcWrqgdp_gx<;~XMk%kZGi>< +)vECq-se{-iyI_MdjY!As9v*~PxpOz@dHnqs+K;<$uRbwUve949bakn +2Y;D&HmqFu!ZPn;38wn-?$;}h@izBknerV_wD^A)ziQdb~i_a;ykqH&CyLN1`#h4=BSMFViwF4$#3~! +k<<w?{1SWji~p=+~I3OtHoEfmv7d)DulZu8brnPT*c@#ralTo=vUiSDo; +owwL4SlOiM+jEA)61!=9 +)wYIH=1D|$DLYIt4}243+t=bzfKY0ANWU(7&QUWcesMaR!Ql!=B#OqheOg`>&dt`cd;paD88<3O8a{< +)#?7wYud8sCOYai)@~@~~U%MJExuQ{hVFhcwZk$F=R$S{5ZR9g61*5x<1q9DRMIBe-&9ZkfDN4QJtO6 +B^%w3d&v>_3Yfm9w#1BpjVn4yE_nqf4**eJpoTc-$K=)>7;%k4=AfLF +nA{6zH`>7j0RID(<{vunBp=tUnciLLHgF4VbPDk96Lbo)Z^^$V+{kEZ9t7q4y +ON33V^g{O`CD6#_tp9TJKDgE=JH_)vpV#ddM+t$zw*+TG7Y4SuHrttFxo+C9~pmTu>-YnkP2dhevUB> +=$JoGwzZ7)oDxdpAqy0Ne$;lCeH-jn|U{saE!*)_V)>ud9W8TL$XImHxC>VNuS{I&HM5Y7#}99lE9b; +v`&$}_~6lG)^u=V#wb7N-VzD2d#y(1iYu#h<_x)}$E9q<*4S^WcwiBT*qsUtAy4`P_E&AxO{i9<**vs +hjONG70hg>=*xA?0rHtSo&lzyWQ7+b$FJQf5i)^*z3XGP*g#ztXPO}$-->M@Y!B9LPsrEMrcdCtl(#7 +!Z#*L>aoB3ZIeHHCdc)cjgC&VcS6#!BoAaK+fg6;BT&MJL})`*lvm&+h8_k|lnw0u-iQ8#{p)qL+tAd +%E-!R*!J5n+sd($qgnNjqQO7ASCnNV2=ybm75UzB#AsqL3BKc;C)kfLtx;@( +;`?UEALMtBUtcb8c~DCM0u%!j0000805+CpNlQtjWitT)07wD=01p5F000000 +00000HlFQ4*&pgX>c!JUu|J&ZeL$6aCuNm0Rj{Q6aWAK2mm&gW=Vn=i}gbd004$A000sI0000000000 +005+csSp4FaA|NaVqtS-V{dJ3VQyqDaCuNm0Rj{Q6aWAK2mm&gW=X57{yU}&007}A000pH000000000 +0005+c93B7waA|NaVqtS-aA9(DWpXZXc~DCM0u%!j0000805+CpNlTeBA$}4709rr*01*HH00000000 +000HlHODgXd*X>c!NZDen7bZKvHb1rasP)h*<6ay3h000O8HkM{dn{PY_m?HoHt9<|f4*&oF0000000 +000q=BA2003}la4%$UcW!KNVPr0Fc~DCM0u%!j0000805+CpNxpiPn7ax90J$Fk01*HH00000000000 +HlFqVE_PdX>c!Pcw=R7bZKvHb1rasP)h*<6ay3h000O8HkM{dHuxp~U@8Cr4x9i03;+NC0000000000 +q=8Lr003}la4%_YWMz0RaCuNm0Rj{Q6aWAK2mm&gW=XdXcbSn0008bZKvHb1rasP)h*<6ay3h000O8HkM{d`Y438OAY`4?y-E^v8JO928D0~7!N00;m!mS#zXiI$3p5dZ*SR{#JO00000000000001_fsWe +%0B~t=FJE?LZe(wAFJW+SWNC79E^v8JO928D0~7!N00;m!mS#zj!N9H{BLD!+l>h)00000000000000 +1_flBQF0B~t=FJE?LZe(wAFJx(RbaHPlaCuNm0Rj{Q6aWAK2mm&gW=Y+|rUhv`001yK0RR{P0000000 +000005+coe%*4aA|NaUv_0~WN&gWX>eg=WO8M5b1rasP)h*<6ay3h000O8HkM{d)>0WG69xbP{to~E8 +UO$Q0000000000q=7t40RV7ma4%nWWo~3|axZUkWMy(?WMpY$bS`jtP)h*<6ay3h000O8HkM{d!60;w +>d*iHt7`)Q7ytkO0000000000q=AQ00RV7ma4%nWWo~3|axZXsaA9(DX>MmOaCuNm0Rj{Q6aWAK2mm& +gW=UWk2aRR{000F8000;O0000000000005+cry~LYaA|NaUv_0~WN&gWa%C-cWo~3|axQRrP)h*<6ay +3h000O8HkM{dA$zv0swGna4%nWWo~3|axZdabaHuVZf7oVc~ +DCM0u%!j0000805+CpNtswpT1XuL0Fre801^NI00000000000HlFOF9HB?X>c!Jc4cm4Z*nhlX?QMhc +~DCM0u%!j0000805+CpNdQ)?I<5c!04@Ol03-ka00000000000HlGxOacIKX>c!Jc4cm4Z*nhVVPj}z +V{dMBa&K%eUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!XR7Rx(0ssIg1pojb00000000000001_fv-& +h0B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gD9ZDcNRc~DCM0u%!j0000805+CpNl@mgEK~&m000sI03! +eZ00000000000HlHNPXYjNX>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eVPs)&bY*fbaCuNm0Rj{Q6aWAK2m +m&gW=RsN#_%iw000&P001EX0000000000005+cg;fFoaA|NaUv_0~WN&gWV_{=xWn*t{baHQOFJob2X +k{*Nc~DCM0u%!j0000805+CpNqG`W@Xi1L0H6T?03rYY00000000000HlHNRssNUX>c!Jc4cm4Z*nhV +VPj}zV{dMBa&K%eV{dJ6VRSBVc~DCM0u%!j0000805+CpNylKh-Utr>0N^qJ044wc00000000000HlH +bR{{WVX>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eV{dMBa&K&GWpXZXc~DCM0u%!j0000805+CpNo*!GeE9 +c!Jc4cm4Z*nhVVPj}zV{dMBa&K%eW@&6?cXDBHaAk5XaC +uNm0Rj{Q6aWAK2mm&gW=RfI9{j-t001oz001Tc0000000000005+ch-(4>aA|NaUv_0~WN&gWV_{=xW +n*t{baHQOFKA_Ta%ppPX=8IPaCuNm0Rj{Q6aWAK2mm&gW=RrZfVe0K004*?001Qb0000000000005+c +jd211aA|NaUv_0~WN&gWV_{=xWn*t{baHQOFLPybX<=+>dSxzfc~DCM0u%!j0000805+CpNsD{MLc9O +~0P+C<03!eZ00000000000HlHVc>(}%X>c!Jc4cm4Z*nhVVPj}zV{dMBa&K%ecXDBHaAk5XaCuNm0Rj +{Q6aWAK2mm&gW=WnMR{YBV0040T001ih0000000000005+c^?CvTaA|NaUv_0~WN&gWV_{=xWn*t{ba +HQOFJob2Xk~LRUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!8rw0F91pold4FCWw00000000000001_f +eCy90B~t=FJE?LZe(wAFJob2Xk}w>Zgg^QY%gPBV`yb_FJ@_MWnW`qV`ybAaCuNm0Rj{Q6aWAK2mm&g +W=YeC##E*O007Mc001rk0000000000005+cuYm#paA|NaUv_0~WN&gWV_{=xWn*t{baHQOFJob2Xk~L +Ra%E&`b6;a&V`ybAaCuNm0Rj{Q6aWAK2mm&gW=UAoX*sh1008g+001BW0000000000005+cp@RYdaA| +NaUv_0~WN&gWV{dG4a$#*@FJE72ZfSI1UoLQYP)h*<6ay3h000O8HkM{dJ{6~5ivs`v+z9{x8~^|S00 +00000000q=Axz0swGna4%nWWo~3|axY_VY;SU5ZDB8AZgXiaaCuNm0Rj{Q6aWAK2mm&gW=Y3mz}avL0 +06`#001KZ0000000000005+cSBL@taA|NaUv_0~WN&gWV{dG4a$#*@FJW$TX>@OQX>KzzE^v8JO928D +0~7!N00;m!mS#zP*4QtF0ssJg2LJ#f00000000000001_fe4cV0B~t=FJE?LZe(wAFJo_PZ*pO6VJ~T +JX>@5}Y-w|4E^v8JO928D0~7!N00;m!mS#x}ZK6F)1pol`6aWAn00000000000001_fz6cy0B~t=FJE +?LZe(wAFJo_PZ*pO6VJ~-SZZk42aCuNm0Rj{Q6aWAK2mm&gW=VH@XCdMR005F00018V000000000000 +5+cRGR_-aA|NaUv_0~WN&gWV{dG4a$#*@FL!BfbY*gFE^v8JO928D0~7!N00;m!mS#yNoKcru0RR9+0 +ssIX00000000000001_fpeh(0B~t=FJE?LZe(wAFJx(RbZlv2FJE72ZfSI1UoLQYP)h*<6ay3h000O8 +HkM{dUkP(yXes~zVV?j19RL6T0000000000q=5~i0swGna4%nWWo~3|axY|Qb98KJVlQKFZE#_9E^v8 +JO928D0~7!N00;m!mS#yh3d6j=E&u=s!TbZ>HVE^v8JO928D0~7!N00;m!mS#zYm$jR05C8z$ +IRF4300000000000001_feJ+f0B~t=FJE?LZe(wAFJx(RbZlv2FKuCNX=Y_}bS`jtP)h*<6ay3h000O +8HkM{dJrS+~jRyb#iWmR@9smFU0000000000q=BOV0000000000q=9^00|0Poa4%nWWo~3|axY|Qb9 +8KJVlQoFbYWy+bYU)Vc~DCM0u%!j0000805+CpNyxWFn5YW?01heu03ZMW00000000000HlF%fdc?=X +>c!Jc4cm4Z*nhWX>)XJX<{#OWpi(Ja${w4E^v8JO928D0~7!N00;m!mS#!1|LfZd5&!^rI{*M400000 +000000001_fmV$J0B~t=FJE?LZe(wAFJx(RbZlv2FLPsZX>fFNE^v8JO928D0~7!N00;m!mS#!yn2-# +-ssI20Tmb+Z00000000000001_ft;TM0B~t=FJE?LZe(wAFJx(RbZlv2FLX09E@gOSP)h*<6ay3h000 +O8HkM{dp5nz>TetuK0Db`g8vp0|fwZX>c!Jc4cm4Z*nhWX>)XJX +<{#RbZKlZaCuNm0Rj{Q6aWAK2mm&gW=Wv^1y-*a005s{0015U0000000000005+c6+Q(3aA|NaUv_0~ +WN&gWWNCABY-wUIc4cyNX>V>WaCuNm0Rj{Q6aWAK2mm&gW=Yt60Et?r0000^0RS5S0000000000005+ +c09XY8aA|NaUv_0~WN&gWWNCABY-wUIcQZ0BWq4&!O928D0~7!N00;m!mS#y_%uDYLwEzGBZ~*`t000 +00000000001_fs_6P0B~t=FJE?LZe(wAFJx(RbZlv2FLyRHE@gOSP)h*<6ay3h000O8HkM{dU(}$f4J +7~o%a{NF8~^|S0000000000q=DJ91^{qra4%nWWo~3|axY|Qb98KJVlQ`SWo2wGaCuNm0Rj{Q6aWAK2 +mm&gW=SLOXZ*te000sJ001cf0000000000005+cAlU{0aA|NaUv_0~WN&gWWNCABY-wUIUt(cnYjAIJ +bT40DX>MtBUtcb8c~DCM0u%!j0000805+CpNw118WzGQr0Luda03`qb00000000000HlE`+6Dk{X>c! +Jc4cm4Z*nhWX>)XJX<{#5Vqs%zaBp&SFKuaaV=i!cP)h*<6ay3h000O8HkM{d;$l6}M;rhEFJu4!Cjb +Bd0000000000q=7r!1^{qra4%nWWo~3|axY|Qb98KJVlQ7}VPk7>Z*p`mb7*yRX>2ZVc~DCM0u%!j00 +00805+CpNpBVat@Z%`067W(04o3h00000000000HlG(_yz!QX>c!Jc4cm4Z*nhWX>)XJX<{#5Vqs%za +Bp&SFLQZwV{dL|X=g5DW@k`K0Rj{Q6aWAK2mm&gW=S>=Qr74m002vA001fg0000000000005+c2Kxp8 +aA|NaUv_0~WN&gWWNCABY-wUIUt(cnYjAIJbT4yxb7OCAW@%?GaCuNm0Rj{Q6aWAK2mm&gW=TXsA46h +U007i!0RSif0000000000005+cHW~*2aA|NaUv_0~WN&gWWNCABY-wUIUt(cnYjAIJbT4#aa%O34WiD +`eP)h*<6ay3h000O8HkM{dqMMnVuK@r63bYEXCaCuNm0Rj{Q6aWAK2mm&gW=Yj}4&o&g002Qj001EX0000000000005+c%XJ3;a +A|NaUv_0~WN&gWXmo9CHEd~OFJEbBVRU79ZEP-Zc~DCM0u%!j0000805+CpNgfPsHCrD502F@!03-ka +00000000000HlF0iU$C2X>c!Jc4cm4Z*nhabZu-kY-wUIUukY|b#!xda%Ev{E^v8JO928D0~7!N00;m +!mS#!BMrszn8~^|$D**r^00000000000001_fy}7~0B~t=FJE?LZe(wAFKBdaY&C3YVlQ8GZ);_4X?k +UHE^v8JO928D0~7!N00;m!mS#yN4R0B~t=FJE?LZe(wAFK +BdaY&C3YVlQ8HbZKmJE^v8JO928D0~7!N00;m!mS#!Fq<#JgNB{u4MF9XI00000000000001_fkVv)0 +B~t=FJE?LZe(wAFKBdaY&C3YVlQKFZgX^DZgg`laCuNm0Rj{Q6aWAK2mm&gW=Uh%cihZE006Sd0RSTa +0000000000005+cixmg}aA|NaUv_0~WN&gWXmo9CHEd~OFKBdaY&CFUa&u*JE^v8JO928D0~7!N00;m +!mS#!Z$GbFh4*&pRHvj-400000000000001_ftXkb0B~t=FJE?LZe(wAFKBdaY&C3YVlQ)La%o{~X?k +UHE^v8JO928D0~7!N00;m!mS#!s)2|Pv0000X0RR9d00000000000001_flFuz0B~t=FJE?LZe(wAFK +BdaY&C3YVlQ8Ga%p8RUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!Jl|Gi70RRBg0{{Rc00000000000 +001_fi-Ce0B~t=FJE?LZe(wAFKBdaY&C3YVlQ8Ga%p8RUt(c%WiD`eP)h*<6ay3h000O8HkM{dBvqZM +rU3u|ngjp001BW0000000000005+c`fLaQaA|NaUv_0~WN&gWXmo9CHEd +~OFJE+WX=N{Pc`k5yP)h*<6ay3h000O8HkM{d000000ssI200000C;$Ke0000000000q=8j$2mo+ta4 +%nWWo~3|axZ9fZEQ7cX<{#CX>4?5a&s?VUukY>bYEXCaCuNm0Rj{Q6aWAK2mm&gW=U?)e1IPT0034?5a&s?fZfa#?bYE>{bYWj(Xkl`5WpplZc~ +DCM0u%!j0000805+CpNqy_mwf6!503{6o03-ka00000000000HlHMbO-=&X>c!Jc4cm4Z*nhabZu-kY +-wUIW@&76WpZ;bY-w(EE^v8JO928D0~7!N00;m!mS#yI?VTja1^@siDF6U000000000000001_fhc$g +0B~t=FJE?LZe(wAFKBdaY&C3YVlQTCY;c!Jc4cm4Z*nhabZu-kY-wUIW@&76WpZ;bb75|2bZL +5JaxQRrP)h*<6ay3h000O8HkM{dpN?v+&;bAda|8eYDgXcg0000000000q=9jj2mo+ta4%nWWo~3|ax +Z9fZEQ7cX<{#CX>4?5a&s?tXlZn1b8ul}WiD`eP)h*<6ay3h000O8HkM{df-++yj{pDw&;S4cEdT%j0 +000000000q=AW-2mo+ta4%nWWo~3|axZ9fZEQ7cX<{#Qa%E*?y-E^v8JO928D +0~7!N00;m!mS#yYC&#`K0ssIL1^@sn00000000000001_fn%5m0B~t=FJE?LZe(wAFKBdaY&C3YVlQ- +ZWo2PxVQ_S1a&s?dWo~n5X)bViP)h*<6ay3h000O8HkM{dMtBUtcb8c~DCM0u%!j0000805+CpNkqz4s&Wnh0CqM204V?f00000000000HlFSq6h$RX>c!Jc4cm4 +Z*nhabZu-kY-wUIbaG{7Vs&Y3WMy)5FJfVHWiD`eP)h*<6ay3h000O8HkM{d2MtBUtcb8c~DCM0u%!j0000805+CpNlhb|z@h{I080}904M+e00000000000HlHN*9ZV`X>c!Jc4c +m4Z*nhabZu-kY-wUIbaG{7cVTR6WpZ;bVqtS-E^v8JO928D0~7!N00;m!mS#z1if^g+0RRAn1poji00 +000000000001_f!N##0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo36^Y-?q5b1!6XZ7y(mP)h*<6ay3h0 +00O8HkM{dBEb+b5(NMNOcDS9DF6Tf0000000000q=6LQ2mo+ta4%nWWo~3|axZ9fZEQ7cX<{#Qa%E+A +VQgz<{p00000000000001_fg$S%0B~t=FJE?LZe(wAFKBdaY&C3YVlQ-ZWo36^Y-?q5b1!FQZg +Xg9E^v8JO928D0~7!N00;m!mS#!wnInLL3IG6`Bme*)00000000000001_fidm~0B~t=FJE?LZe(wAF +KlmPYi4O|WiMY}X>MtBUtcb8c~DCM0u%!j0000805+CpNh{v+Cn5s?09*c!Jc4cm4Z*nheZ)0m_X>4ULY-w(5Y;R+0W@&6?E^v8JO928D0~7!N00;m!mS#yICcJ)g0{{R +R3;+Nn00000000000001_fmQqn0B~t=FJE?LZe(wAFKlmPYi4O|WiM@OWNC72Z)0m_X>4UKaCuNm0Rj +{Q6aWAK2mm&gW=SACaxEGN007Dt001KZ0000000000005+c3jhfKaA|NaUv_0~WN&gWY;R+0W@&6?FK +}sOY;R+0W@&6?E^v8JO928D0~7!N00;m!mS#!2h48%z1poko6#xJx00000000000001_fo2E^0B~t=F +JE?LZe(wAFKlmPYi4O|WiNAaY-x05Y;R+0W@&6?E^v8JO928D0~7!N00;m!mS#zjBMI3(0{{Rx3IG5n +00000000000001_fwK(>0B~t=FJE?LZe(wAFKlmPYi4O|WiNAiZER_7Yiw_0Yi4O|WiD`eP)h*<6ay3 +h000O8HkM{dJSkYli2(or&;kGeA^-pY0000000000q=7XN2>@_ua4%nWWo~3|axZXUV{2h&X>MmPUte +KjZ*_EEUoLQYP)h*<6ay3h000O8HkM{dfp(V47y$qP0RjL3ApigX0000000000q=Eht2>@_ua4%nWWo +~3|axZXUV{2h&X>MmPUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!jX-ebE0RRA80{{RZ00000000000 +001_fmIX<0B~t=FJE?LZe(wAFK}UFYhh<;Zf7rFV{dJ6VRSBVc~DCM0u%!j0000805+CpN&5Yy5_16n +0Eh(u03-ka00000000000HlFl76|}wX>c!Jc4cm4Z*nhiVPk7yXK8L{FJE(Xa&=>Lb#i5ME^v8JO928 +D0~7!N00;m!mS#zPEGt(93IG5mAOHX$00000000000001_ffE=B0B~t=FJE?LZe(wAFK}UFYhh<;Zf7 +rTVRCC_a&sc!Jc4 +cm4Z*nhiVPk7yXK8L{FLGsZb!l>CZDnqBb1rasP)h*<6ay3h000O8HkM{dd_{wdj~D;|d2IjyBLDyZ0 +000000000q=67A2>@_ua4%nWWo~3|axZXUV{2h&X>MmPb8uy2X=Z6c!Jc4cm4Z*nhiVPk7yXK8L{FLiWjY;!Jfc~DC +M0u%!j0000805+CpNe=JEpc!Jc4cm4Z*nhiVPk7yXK8 +L{FLq^eb7^mGE^v8JO928D0~7!N00;m!mS#!GEkGtsZ2$m1lK}uF00000000000001_fy__|0B~t=FJ +E?LZe(wAFK}yTUvg!0Z*_8GWpgiIUukY>bYEXCaCuNm0Rj{Q6aWAK2mm&gW=Z;5ag34#007Sm001BW0 +000000000005+cT)qhaaA|NaUv_0~WN&gWaB^>Fa%FRKFJE72ZfSI1UoLQYP)h*<6ay3h000O8HkM{d +55q@_ua4%nWWo~3|axZXlZ)b94b8|0ZVR9~Tc~DCM0u%! +j0000805+CpNh*KwFb@L&0Nw=v03QGV00000000000HlGL#|Z#%X>c!Jc4cm4Z*nhia&KpHWpi^cV{d +hCbY*fbaCuNm0Rj{Q6aWAK2mm&gW=YQM4^I07001Tn0018V0000000000005+c<;n>FaA|NaUv_0~WN +&gWaB^>Fa%FRKFKA_KaAk6HE^v8JO928D0~7!N00;m!mS#zJ2vU3K0ssIa1poja00000000000001_f +gR5Y0B~t=FJE?LZe(wAFK}{iXL4n8b1!pnX>M+1axQRrP)h*<6ay3h000O8HkM{dX({S?U<3dF76||V +AOHXW0000000000q=7=x2>@_ua4%nWWo~3|axZdaadl;LbaO9XUukY>bYEXCaCuNm0Rj{Q6aWAK2mm& +gW=VDXxhYT+0010K001BW0000000000005+c;MNHMaA|NaUv_0~WN&gWa%FLKWpi|MFJWY1aCBvIb1r +asP)h*<6ay3h000O8HkM{d$g9t&!UX^Tq80!E8vp@_ua4%nWWo~3|axZdaad +l;LbaO9ZaA_`Zc~DCM0u%!j0000805+CpNnB7pCt3*r0Pi0F02}}S00000000000HlFw@Cg8LX>c!Jc +4cm4Z*nhkWpQ<7b98erVRdw9E^v8JO928D0~7!N00;m!mS#zrDnMzG%K`w1LInUH00000000000001_ +f&KXj0B~t=FJE?LZe(wAFLGsZb!BsOb1!3IV`Xx5E^uXSP)h*<6ay3h000O8HkM{dE+307XaN8KaRLA +U9RL6T0000000000q=C!D3;=Lxa4%nWWo~3|axZdaadl;LbaO9bWpZ?LE^v8JO928D0~7!N00;m!mS# +z}SqnXx0ssJ)1^@sa00000000000001_fo{hP0B~t=FJE?LZe(wAFLGsZb!BsOb1!3WZE#_9E^v8JO9 +28D0~7!N00;m!mS#y*v#Y{=6951pM*sjH00000000000001_fkVm+0B~t=FJE?LZe(wAFLGsZb!BsOb +1!3WZ)<5~b1rasP)h*<6ay3h000O8HkM{dX>g)+)dK(kEDHbtA^-pY0000000000q=Eh23;=Lxa4%nW +Wo~3|axZdaadl;LbaO9dcw=R7bZKvHb1rasP)h*<6ay3h000O8HkM{ddD^4OdI10c{{jF29RL6T0000 +000000q=6FR3;=Lxa4%nWWo~3|axZdaadl;LbaO9gZ*OaJE^v8JO928D0~7!N00;m!mS#zucispl00000000000001_frJJP0B~t=FJE?LZe(wAFLGsZb!BsOb1!pcb8~5LZ +gVbhc~DCM0u%!j0000805+CpN!(>A^ZNt<0Q3w103-ka00000000000HlF|A`Jj=X>c!Jc4cm4Z*nhk +WpQ<7b98erb97;Jb#q^1Z)9b2E^v8JO928D0~7!N00;m!mS#!jAj%JX1ONcU3jhEj00000000000001 +_fxagV0B~t=FJE?LZe(wAFLGsZb!BsOb1!pra&=>Lb#i5ME^v8JO928D0~7!N00;m!mS#x{=(3^?9{> +PjUH||c00000000000001_fqE4;YaCuNm0Rj{Q6aWAK2m +m&gW=WnnC&jq}003wO001cf0000000000005+c!%GbSaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b +1z?CX>MtBUtcb8c~DCM0u%!j0000805+CpNpWmS{EY$t01pKK05Jdn00000000000HlG#P7MHXX>c!J +c4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJE72ZfSI1UoLQYP)h*<6ay3h000O8HkM{dah$& +~caZ=9qCx=xF#rGn0000000000q=BDN4FGUya4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMy +WppoMX=gQXa&KZ~axQRrP)h*<6ay3h000O8HkM{dd +9qhoGXwwt$O!-dGXMYp0000000000q=C`q4FGUya4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP= +WMykR; +KX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJow7a%5?9baH88b#!TOZZ2?nP)h*<6ay +3h000O8HkM{dIfAWpXZXc~DCM0u%!j0000805+CpN%$G)gIfat0B#2W0 +5$*s00000000000HlG3`3(SYX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJow7a&u*L +aB^>AWpXZXc~DCM0u%!j0000805+CpNx<0c!Jc4cm +4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJo_HX>Mn8bYXO5ZDC_*X>MgMaCuNm0Rj{Q6aWAK2mm +&gW=SCX-8oSL004yq001ul0000000000005+cZvhSfaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1 +!3PVRB?;bT4CXZE#_9E^v8JO928D0~7!N00;m!mS#!(Rlv`-0ssIv1pojt00000000000001_fei!>0 +B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoNZ*FsRVQzGDE^v8JO928D0~7!N00;m! +mS#z-1}4T#0{{T_1^@sw00000000000001_ffEM~0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgi +MXkl_>WppoNa5*$NaB^>AWpXZXc~DCM0u%!j0000805+CpNv18*IdKF40CNlg05Sjo00000000000Hl +Gj3Jw5pX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJ*IMaB^>AWpXZXc~DCM0u%!j00 +00805+CpN!CdH%*h1+0G}QJ04@Lk00000000000HlF(4-NouX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>V +P|D?FJow7a%5$6FJ*IMb8Rkgc~DCM0u%!j0000805+CpNvwRlMGFN00A3CN05kvq00000000000HlG3 +6%GJ!X>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJ*OOYH)CJZ(?O~E^v8JO928D0~7! +N00;m!mS#yRWppoPbz^ICW^!e5E^v8JO928D0~7!N00;m!mS#x>v&Q5Z0{{Sv1^@sw000000000000 +01_f#Yrt0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoPbz^ICaB^>AWpXZXc~DCM0 +u%!j0000805+CpNhMFC6yHDq062&M05Sjo00000000000HlFVat;7+X>c!Jc4cm4Z*nhkWpQ<7b98er +aA9L>VP|D?FJow7a%5$6FJ*OOba!TQWpOTWc~DCM0u%!j0000805+CpNiCu{R2c&R0E`9z05kvq0000 +0000000HlF^vkm}oX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FJ*OOba!xaZ(?O~E^v +8JO928D0~7!N00;m!mS#ygjr0xcLI41(i~s;L00000000000001_f#|jl0B~t=FJE?LZe(wAFLGsZb! +BsOb1!gVV{2h&WpgiMXkl_>WppoRVlp!^GG=mRaV~IqP)h*<6ay3h000O8HkM{dAGO=|8Up|Tkp=(&H +2?qr0000000000q=6**4ghdza4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMyWppoSWnyw=cW`oVVr6nJaCuNm0Rj{Q6aWAK2mm&gW=WT?nhw +5J007gt001xm0000000000005+cPY@3PaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3PVRB?;bT +4XYb7pd7aV~IqP)h*<6ay3h000O8HkM{d8-?V^OA`P9luG~rF8}}l0000000000q=8#!4*+m!a4%nWW +o~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMyc!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKl6 +MXJU11XJK+_VQy`2WMynFaCuNm0Rj{Q6aWAK2mm&gW=Wi$w`2Va002Ej0024w0000000000005+cScV +S(aA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3PVRB?;bT4dSZf9e8a%pUAX=80~WMynFaCuNm0R +j{Q6aWAK2mm&gW=RntLmg!a002}m001`t0000000000005+ct&$G_aA|NaUv_0~WN&gWa%FLKWpi|MF +K}UFYhh<)b1!3PVRB?;bT4dSZf9q5Wo2t^Z)9a`E^v8JO928D0~7!N00;m!mS#yGqI(LS2><{#EC2vF +00000000000001_foGf#0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoWVQyz=Wnyw +=cWrNEWo#~Rc~DCM0u%!j0000805+CpNl>?%e#Z&`0QfKf06PEx00000000000HlFirVjvcX>c!Jc4c +m4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKl6MXJ~b9XJK+_VQy`2WMynFaCuNm0Rj{Q6aWAK2m +m&gW=Tsue_iDY000Xt001@s0000000000005+cd$A7yaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b +1!3PVRB?;bT4dSZfA68VQFn|WMynFaCuNm0Rj{Q6aWAK2mm&gW=Z9ms+oHR003|l001=r0000000000 +005+cw7d@haA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3PVRB?;bT4dSbZKreaB^>AWpXZXc~DC +M0u%!j0000805+CpNu``|bDabL0K^Oc05|{u00000000000HlF}!w&#(X>c!Jc4cm4Z*nhkWpQ<7b98 +eraA9L>VP|D?FJow7a%5$6FKuFDXkl`5Wpr?IZ(?O~E^v8JO928D0~7!N00;m!mS#!LjE_560{{T82L +J##00000000000001_fpy3a0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&WpgiMXkl_>WppoXVqa +&L8TaB^>AWpXZXc~DCM0u%!j0000805+CpN%7@pnoJA;0ESEe051Rl00000000000HlE=%ntx?X>c!J +c4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FJow7a%5$6FKuFDb8~GjaCuNm0Rj{Q6aWAK2mm&gW=Z-Q6}Wl +^006lX001}u0000000000005+cz1R-`aA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!3PVRB?;bT4 +yaV`yP=b7gdJa&KZ~axQRrP)h*<6ay3h000O8HkM{dq}=7dBm@8e+YA5zH~;_u0000000000q=Aj!4* ++m!a4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQV`yP=WMy)LLZ(?O~E^v8JO928D0~7!N00;m!mS#zWppofZfSO9a&uv9WMy<^V{~ +tFE^v8JO928D0~7!N00;m!mS#y``ygu`1ONbB3IG5z00000000000001_fdugn0B~t=FJE?LZe(wAFL +GsZb!BsOb1!gVV{2h&WpgiMXkl_>WppofbY?hka&KZ~axQRrP)h*<6ay3h000O8HkM{d&d{T~b_4(bB +ntolF#rGn0000000000q=9qw4*+m!a4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kUtei% +X>?y-E^v8JO928D0~7!N00;m!mS#x@Xc0Bo3;+N*DF6U900000000000001_fjIgP0B~t=FJE?LZe(w +AFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyvaV{dG1Wn*+{Z*FrgaCuNm0Rj{Q6aWAK2mm&gW=R2F4Gf +wN003bv001)p0000000000005+cV+RlbaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vrY;0*_Gc +RLrZf<2`bZKvHE^v8JO928D0~7!N00;m!mS#y6e_NEJBme+6g8%?G00000000000001_fld|>0B~t=F +JE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyveZ*Fd7V{~b6Zg6jJY%XwlP)h*<6ay3h000O8 +HkM{d6r)PD76$+T-xUA=GXMYp0000000000q=7~|5CCv#a4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvC +Qb#iQMX<{=kWq4y{aCB*JZgVbhc~DCM0u%!j0000805+CpN!PCU=_v;Q04o;&051Rl00000000000Hl +GfLJ$COX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFJ@_FY-DpTaCuNm0Rj{Q6aWAK2m +m&gW=Wm-upv(a000mP001!n0000000000005+cBT5heaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b +1!vrY;0*_GcRUoY-Mn7b963nc~DCM0u%!j0000805+CpNjDCd5N8hn03c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFK};fY;9p~VP|D>E^v8JO928D0~7! +N00;m!mS#zPGjy()2LJ$M7XSb-00000000000001_fqGpK0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2 +h&Wpgiea%^mAVlyvtWpQ<7b963nc~DCM0u%!j0000805+CpNyj{$K^+tT0Jlg005Jdn00000000000H +lFnWe@;xX>c!Jc4cm4Z*nhkWpQ<7b98eraA9L>VP|D?FLiQkY-wUMFLGsbaBpsNWiD`eP)h*<6ay3h0 +00O8HkM{d000000ssI200000IRF3v0000000000q=C$N5CCv#a4%nWWo~3|axZdaadl;LbaO9oVPk7y +XJvCQb#iQMX<{=kV{dMBa%o~OUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!5n4CII2><{A9{>P40000 +0000000001_fhBqn0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyveZ*FvQX<{#7aBy +XAXK8L_E^v8JO928D0~7!N00;m!mS#!V5}&rK1polE5dZ)=00000000000001_fy#pr0B~t=FJE?LZe +(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyveZ*FvQX<{#KbZl*KZ*OcaaCuNm0Rj{Q6aWAK2mm&gW +=SLDzYK8>0006m0024w0000000000005+c%!v>HaA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vr +Y;0*_GcRLrZgg^KVlQxcZ*XO9b8~DiaCuNm0Rj{Q6aWAK2mm&gW=R^~ig~;S001Nw001@s000000000 +0005+cm6#9!aA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vrY;0*_GcRLrZgg^KVlQ)VV{3CRaCu +Nm0Rj{Q6aWAK2mm&gW=W4-pnOmO003bYEXCaCuNm0Rj{Q6aWAK2mm&gW=TfDrf2X90 +08GA002G!0000000000005+cO`s3}aA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vrY;0*_GcRyq +V{2h&WpgiYa%5$4Wn^DuX=8LQaCuNm0Rj{Q6aWAK2mm&gW=WY?O0aA|NaUv_0~WN&gWa%FLKWpi|MFK}UFYhh<)b1!vrY;0*_GcRyqV{2h&WpgicX?QMhc~DCM0u% +!j0000805+CpNf5AT<=p@P0L%dZ08Ib@00000000000HlF5$q)c=X>c!Jc4cm4Z*nhkWpQ<7b98eraA +9L>VP|D?FLiQkY-wUMFK}UFYhh<)b1!pqY+r3*bYo~=Xm4|LZeeX@FJE72ZfSI1UoLQYP)h*<6ay3h0 +00O8HkM{dt<;VP|D?FLQHjUu|J@V`yJ!Z*z2RVQpnEUukV{Y-Md_ZggREX>V>WaCuNm0Rj{ +Q6aWAK2mm&gW=R{kXYqCc004Xg001@s0000000000005+c^3V_faA|NaUv_0~WN&gWa%FLKWpi|MFK} +UFYhh<)b1!vrY;0*_GcR>?X>2cFUukY>bYEXCaCuNm0Rj{Q6aWAK2mm&gW=W?X>2cJZ*Fd7V +{~b6ZZ2?nP)h*<6ay3h000O8HkM{d%)z`q+5!LoPzV43H2?qr0000000000q=7`*5CCv#a4%nWWo~3| +axZdaadl;LbaO9oVPk7yXJvCQb#iQMX<{=kb#!TLFLGsZb!BsOE^v8JO928D0~7!N00;m!mS#z9=K&m +@0{{SZ2mk;!00000000000001_fpOgs0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVly +vwbZKlaa%FRHZ*FsCE^v8JO928D0~7!N00;m!mS#y5kQj;?4FCYBDF6U700000000000001_fnwnh0B +~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{2h&Wpgiea%^mAVlyvwbZKlaa%FUKc`k5yP)h*<6ay3h000O8H +kM{dLjYkeiVpw)W-R~!G5`Po0000000000q=C%t5CCv#a4%nWWo~3|axZdaadl;LbaO9oVPk7yXJvCQ +b#iQMX<{=kb#!TLFLQHjUoLQYP)h*<6ay3h000O8HkM{dZ?0761S-00000000000001_fk_Gx0B~t=FJE?LZe(wAFLGsZb!BsOb1!gVV{ +2h&Wpgiea%^mAVlyvwbZKlab#iPjaCuNm0Rj{Q6aWAK2mm&gW=U_sp*SuJ002-a001Na00000000000 +05+crxFnWaA|NaUv_0~WN&gWcV%K_Zewp`X>Mn8FJE72ZfSI1UoLQYP)h*<6ay3h000O8HkM{d$E^s9 +1qJ{B6C(fsA^-pY0000000000q=6S65dd&$a4%nWWo~3|axZsfVr6b)Z)9n1XLB!XVPa)$b1rasP)h* +<6ay3h000O8HkM{dP=7HWL;?T+83h0UBme*a0000000000q=8%{5dd&$a4%nWWo~3|axZsfVr6b)Z)9 +n1XLB!YYiwa+Wo&aUaCuNm0Rj{Q6aWAK2mm&gW=R&CJ{`IR005#H001EX0000000000005+c;wBLQaA +|NaUv_0~WN&gWcV%K_Zewp`X>Mn8FLY&dbaO6nc~DCM0u%!j0000805+CpNl0%+zN7>I0MZZu04e|g0 +0000000000HlH2ED->3X>c!Jc4cm4Z*nhpWnyJ+V{c?>ZfA2ZcwcpMWpZC+WoBt^Wn?aJc~DCM0u%!j +0000805+CpNstYPL#F}&0K^CY02lxO00000000000HlG(F%bZ8X>c!NZ*6U1Ze(*WUtei%X>?y-E^v8 +JO928D0~7!N00;m!mS#yEVLM;#0RRAI1pojQ00000000000001_fuuAM0B~t=FJo_QZDDR?b1!3PWn* +hDaCuNm0Rj{Q6aWAK2mm&gW=Sx?%(G_$005N<000^Q0000000000005+c#5NHCaA|NaV{dJ3VQyq|FJ +o_QaBO9CX>V>WaCuNm0Rj{Q6aWAK2mm&gW=Yu|nWhv7004p>000;O0000000000005+cV>%H4aA|NaV +{dJ3VQyq|FJy0bZftL1WG--dP)h*<6ay3h000O8HkM{d!}jxF*#iIo6AJ(U761SM0000000000q=BtM +5dd&$a4%zTZEaz0WOFZOa%E+DWiD`eP)h*<6ay3h000O8HkM{d_=)VKy#fFLJq7>(6aWAK000000000 +0q=C9d5dd&$a4%zTZEaz0WOFZQVRL9MaCuNm0Rj{Q6aWAK2mm&gW=S3v(4DFQ007nl000yK00000000 +00005+csYww4aA|NaV{dJ3VQyq|FKA_Ka4v9pP)h*<6ay3h000O8HkM{dOC^RDv=0CP1VjJ;7XSbN00 +00000000q=AJ?5dd&$a4%zTZEaz0WOFZRZgX^DY-}!Yc~DCM0u%!j0000805+CpNe@fMIKK-30BI}$0 +2BZK00000000000HlF#TM+c!NZ*6U1Ze(*WY-w|JE^v8JO928D0~7!N00;m!mS#z=LWJBV1^@t- +5dZ)d00000000000001_fnR440B~t=FJo_QZDDR?b1!pcVRB<=E^v8JO928D0~7!N00;m!mS#x|Qy(P +!1^@s97XSbh00000000000001_fw^rF0B~t=FJo_QZDDR?b1!pfZ+9+mc~DCM0u%!j0000805+CpNvn +w&KhOgJ07MG_02u%P00000000000HlHEbP)h>X>c!NZ*6U1Ze(*Wb#7^Hb97;BY%XwlP)h*<6ay3h00 +0O8HkM{dmp60f{09I4F&+Q_6#xJL0000000000q=D{u5dd&$a4%zTZEaz0WOFZfXk}$=E^v8JO928D0 +~7!N00;m!mS#zrC#iAl1^@s+5&!@e00000000000001_fgOPn0B~t=FJo_QaA9;WUtei%X>?y-E^v8J +O928D0~7!N00;m!mS#zUqNSHj6#xJ@S^xkT00000000000001_fjx*30B~t=FJo_QaA9;WWNBk`V{dL +|X=g5Qc~DCM0u%!j0000805+CpNvaxWyg>i}07n1-02TlM00000000000HlGyoe=c!XZ)9a`b1z +?CX>MtBUtcb8c~DCM0u%!j0000805+CpNoYc!XZ) +9a`b1!LbWMz0RaCuNm0Rj{Q6aWAK2mm&gW=Q}50006200000000^Q0000000000005+cN1qV@aA|NaZ +*XODVRUJ4ZgVeRUukY>bYEXCaCuNm0Rj{Q6aWAK2mm&gW=YRwVyLbG001@y000*N0000000000005+c +fu9ioaA|NaZ*XODVRUJ4ZgVeVXk}w-E^v8JO928D0~7!N00;m!mS#!$A~Q391poj_6aWAi000000000 +00001_fn=c(0B~t=FK=*Va$$67Z*FrhW^!d^dSxzfc~DCM0u%!j0000805+CpNnB~t8Grx)02BcL022 +TJ00000000000HlE$rx5^fX>c!cWpOWGUukY>bYEXCaCuNm0Rj{Q6aWAK2mm&gW=S02j0$ND005RQ00 +0vJ0000000000005+c%cl_laA|Naa%FKZa%FK}W@&6?E^v8JO928D0~7!N00;m!mS#zTZB@hfEdT(Qw +EzGX00000000000001_fn~K30B~t=FLGsZFLGsZUukZ0bYX04E^v8JO928D0~7!N00;m!mS#y3-I8{* +ApiiLh5!H(00000000000001_fso@70B~t=FLGsZFLGsZUvp)2E^v8JO928D0~7!N00;m!mS#x>M#OM +X2mk=_8UO$o00000000000001_fpY~C0B~t=FLGsZFLGsZUv+M2ZgX^DY-}!Yc~DCM0u%!j0000805+ +CpN#I(vz7rt;05fU;02KfL00000000000HlHW4H5uwX>c!fbZKmJFJE72ZfSI1UoLQYP)h*<6ay3h00 +0O8HkM{dH45H4sR{r9Ya##u6aWAK0000000000q=7##5&&>%a4&UqX>4;ZVQ_F{X>xNeaCuNm0Rj{Q6 +aWAK2mm&gW=YKqO)dZe001Bb000sI0000000000005+c8afgHaA|Nab#!TLb1!0bX>4RJaCuNm0Rj{Q +6aWAK2mm&gW=U}#Y9s~&006iM000;O0000000000005+cN<0z(aA|Nab#!TLb1!6NaB^j1VRUJ4ZZ2? +nP)h*<6ay3h000O8HkM{dy;?u8x&Z(H%L4!a6#xJL0000000000q=AM%5&&>%a4&UqX>4;ZWo~0{WNB +_^E^v8JO928D0~7!N00;m!mS#!vL+!w%0RRAl0{{RQ00000000000001_fpb9;0B~t=FLiWjY;!MWX> +4V4d2@7SZ7y(mP)h*<6ay3h000O8HkM{dAU6ec-~<2wdkX*n5&!@I0000000000q=8IB5&&>%a4&UqX +>4;ZXKZO=V=i!cP)h*<6ay3h000O8HkM{dsWj;XeFOjiG7A6z6951J0000000000q=8&W5&&>%a4&Uq +X>4;ZXkl|`WpgfYc~DCM0u%!j0000805+CpNoOY4c(Vim0RIdC02BZK00000000000HlEmO%ecbX>c! +fbZKmJFKlmTXK8L{E^v8JO928D0~7!N00;m!mS#yvRM_f?1^@t06#xJg00000000000001_f$vcg0B~ +t=FLiWjY;!Mfb#!E5bY)~NaCuNm0Rj{Q6aWAK2mm&gW=Rd^lDOvr001Be000&M0000000000005+ct5 +^~MaA|Nab#!TLb1!gVV{2h&X>MmOaCuNm0Rj{Q6aWAK2mm&gW=R&J@=Ch^000&N0012T00000000000 +05+c##<5qaA|Nab#!TLb1!pcbailaZ*OdKUt)D>Y-BEQc~DCM0u%!j0000805+CpN#){@m0}J608K3b +01p5F00000000000HlGuToM3qX>c!fbZKmJFLh}yaCuNm0Rj{Q6aWAK2mm&gW=Y6a#Y^K20034n000v +J0000000000005+cOKTDUaA|Nac4KodUtei%X>?y-E^v8JO928D0~7!N00;m!mS#!&z|6%n1pols4gd +fV00000000000001_fnRwN0B~t=FLq;dFJfVOVPSGEaCuNm0Rj{Q6aWAK2mm&gW=SZ%-Y@_S006x!00 +0gE0000000000005+c!G00|aA|Nac4KodXK8dUaCuNm0Rj{Q6aWAK2mm&gW=VNsY8_z&0058;000yK0 +000000000005+c?TZosaA|Nac4KodZDn#}b#iH8Y%XwlP)h*<6ay3h000O8HkM{dZZwraAPWEhh9m$0 +6#xJL0000000000q=A5t5&&>%a4&Xab1!psVs>S6b7^mGE^v8JO928D0~7!N00;m&mS#z-aWq#E0ssI +91poje00000000000001_fzz830B~t=EjcbQE-@}-X>)WfX>Mk3FGNLCLsCglR7p=xE^>2pP)h*<6ay +3h000O8I+kWhZ!-C~DgXcgL;wH)Bme*a0000000000q=6-#5&&>%a4k75FfK7JWNCABEop9MZ!cwTba +HuLaBpdDbaO6rcyv%p0Rj{Q6aWAK2mm^kW=YQ5y3cct$E-)@JE@WwQbS-IaW^XTaZ*X61Wp-t3E_8TwP)h*<6ay3h000O8I+kWhtJ{J +TUjP6AZU6uP82|tP0000000000q=A&75&&>%a4k75FfK7JWNCABEop9MZ!cF!MMX?dO928D0~7!N00; +m&mS#y_txRE}0{{Tw2><{b00000000000001_fhwXB0B~t=EjcbQE-@}-X>)WfX>Mk3FHJ>MK}11RK~ +PHp0u%!j0000806LatN$y5^m0m3X0LEPa02%-Q00000000000HlEirV;>fX>ct$E-)@JE@WwQbS-IaW +^XT2MMF 0: + days = t + return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) + else: + return '%02d:%02d:%02d' % (hours, minutes, seconds) + return '' + + def format_pos(self): + pos = str(self.pos) + if self.length_known: + pos += '/%s' % self.length + return pos + + def format_pct(self): + return ('% 4d%%' % int(self.pct * 100))[1:] + + def format_progress_line(self): + show_percent = self.show_percent + + info_bits = [] + if self.length_known: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + if show_percent is None: + show_percent = not self.show_pos + else: + if self.finished: + bar = self.fill_char * self.width + else: + bar = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + bar[int((math.cos(self.pos * self.time_per_iteration) + / 2.0 + 0.5) * self.width)] = self.fill_char + bar = ''.join(bar) + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return (self.bar_template % { + 'label': self.label, + 'bar': bar, + 'info': self.info_sep.join(info_bits) + }).rstrip() + + def render_progress(self): + from .termui import get_terminal_size + nl = False + + if self.is_hidden: + buf = [self.label] + nl = True + else: + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, get_terminal_size()[0] - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(' ' * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + buf.append(line) + + buf.append(' ' * (clear_width - line_len)) + line = ''.join(buf) + + # Render the line only if it changed. + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=nl) + self.file.flush() + + def make_step(self, n_steps): + self.pos += n_steps + if self.length_known and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + self.avg = self.avg[-6:] + [-(self.start - time.time()) / (self.pos)] + + self.eta_known = self.length_known + + def update(self, n_steps): + self.make_step(n_steps) + self.render_progress() + + def finish(self): + self.eta_known = 0 + self.current_item = None + self.finished = True + + def next(self): + if self.is_hidden: + return next(self.iter) + try: + rv = next(self.iter) + self.current_item = rv + except StopIteration: + self.finish() + self.render_progress() + raise StopIteration() + else: + self.update(1) + return rv + + if not PY2: + __next__ = next + del next + + +def pager(text, color=None): + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, text, color) + pager_cmd = (os.environ.get('PAGER', None) or '').strip() + if pager_cmd: + if WIN: + return _tempfilepager(text, pager_cmd, color) + return _pipepager(text, pager_cmd, color) + if os.environ.get('TERM') in ('dumb', 'emacs'): + return _nullpager(stdout, text, color) + if WIN or sys.platform.startswith('os2'): + return _tempfilepager(text, 'more <', color) + if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: + return _pipepager(text, 'less', color) + + import tempfile + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: + return _pipepager(text, 'more', color) + return _nullpager(stdout, text, color) + finally: + os.unlink(filename) + + +def _pipepager(text, cmd, color): + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit('/', 1)[-1].split() + if color is None and cmd_detail[0] == 'less': + less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:]) + if not less_flags: + env['LESS'] = '-R' + color = True + elif 'r' in less_flags or 'R' in less_flags: + color = True + + if not color: + text = strip_ansi(text) + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, + env=env) + encoding = get_best_encoding(c.stdin) + try: + c.stdin.write(text.encode(encoding, 'replace')) + c.stdin.close() + except (IOError, KeyboardInterrupt): + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager(text, cmd, color): + """Page through text by invoking a program on a temporary file.""" + import tempfile + filename = tempfile.mktemp() + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, 'wb')[0] as f: + f.write(text.encode(encoding)) + try: + os.system(cmd + ' "' + filename + '"') + finally: + os.unlink(filename) + + +def _nullpager(stream, text, color): + """Simply print unformatted text. This is the ultimate fallback.""" + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor(object): + + def __init__(self, editor=None, env=None, require_save=True, + extension='.txt'): + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self): + if self.editor is not None: + return self.editor + for key in 'VISUAL', 'EDITOR': + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return 'notepad' + for editor in 'vim', 'nano': + if os.system('which %s >/dev/null 2>&1' % editor) == 0: + return editor + return 'vi' + + def edit_file(self, filename): + import subprocess + editor = self.get_editor() + if self.env: + environ = os.environ.copy() + environ.update(self.env) + else: + environ = None + try: + c = subprocess.Popen('%s "%s"' % (editor, filename), + env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException('%s: Editing failed!' % editor) + except OSError as e: + raise ClickException('%s: Editing failed: %s' % (editor, e)) + + def edit(self, text): + import tempfile + + text = text or '' + if text and not text.endswith('\n'): + text += '\n' + + fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) + try: + if WIN: + encoding = 'utf-8-sig' + text = text.replace('\n', '\r\n') + else: + encoding = 'utf-8' + text = text.encode(encoding) + + f = os.fdopen(fd, 'wb') + f.write(text) + f.close() + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save \ + and os.path.getmtime(name) == timestamp: + return None + + f = open(name, 'rb') + try: + rv = f.read() + finally: + f.close() + return rv.decode('utf-8-sig').replace('\r\n', '\n') + finally: + os.unlink(name) + + +def open_url(url, wait=False, locate=False): + import subprocess + + def _unquote_file(url): + try: + import urllib + except ImportError: + import urllib + if url.startswith('file://'): + url = urllib.unquote(url[7:]) + return url + + if sys.platform == 'darwin': + args = ['open'] + if wait: + args.append('-W') + if locate: + args.append('-R') + args.append(_unquote_file(url)) + null = open('/dev/null', 'w') + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = 'explorer /select,"%s"' % _unquote_file( + url.replace('"', '')) + else: + args = 'start %s "" "%s"' % ( + wait and '/WAIT' or '', url.replace('"', '')) + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or '.' + else: + url = _unquote_file(url) + c = subprocess.Popen(['xdg-open', url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(('http://', 'https://')) and not locate and not wait: + import webbrowser + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch): + if ch == '\x03': + raise KeyboardInterrupt() + if ch == '\x04': + raise EOFError() + + +if WIN: + import msvcrt + + def getchar(echo): + rv = msvcrt.getch() + if echo: + msvcrt.putchar(rv) + _translate_ch_to_exc(rv) + if PY2: + enc = getattr(sys.stdin, 'encoding', None) + if enc is not None: + rv = rv.decode(enc, 'replace') + else: + rv = rv.decode('cp1252', 'replace') + return rv +else: + import tty + import termios + + def getchar(echo): + if not isatty(sys.stdin): + f = open('/dev/tty') + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + try: + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = os.read(fd, 32) + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + if f is not None: + f.close() + except termios.error: + pass + _translate_ch_to_exc(ch) + return ch.decode(get_best_encoding(sys.stdin), 'replace') diff --git a/pipenv/vendor/click/_textwrap.py b/pipenv/vendor/click/_textwrap.py new file mode 100644 index 00000000..7e776031 --- /dev/null +++ b/pipenv/vendor/click/_textwrap.py @@ -0,0 +1,38 @@ +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + + def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent): + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text): + rv = [] + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + if idx > 0: + indent = self.subsequent_indent + rv.append(indent + line) + return '\n'.join(rv) diff --git a/pipenv/vendor/click/_unicodefun.py b/pipenv/vendor/click/_unicodefun.py new file mode 100644 index 00000000..9e17a384 --- /dev/null +++ b/pipenv/vendor/click/_unicodefun.py @@ -0,0 +1,118 @@ +import os +import sys +import codecs + +from ._compat import PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +click = sys.modules[__name__.rsplit('.', 1)[0]] + + +def _find_unicode_literals_frame(): + import __future__ + frm = sys._getframe(1) + idx = 1 + while frm is not None: + if frm.f_globals.get('__name__', '').startswith('click.'): + frm = frm.f_back + idx += 1 + elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: + return idx + else: + break + return 0 + + +def _check_for_unicode_literals(): + if not __debug__: + return + if not PY2 or click.disable_unicode_literals_warning: + return + bad_frame = _find_unicode_literals_frame() + if bad_frame <= 0: + return + from warnings import warn + warn(Warning('Click detected the use of the unicode_literals ' + '__future__ import. This is heavily discouraged ' + 'because it can introduce subtle bugs in your ' + 'code. You should instead use explicit u"" literals ' + 'for your unicode strings. For more information see ' + 'http://click.pocoo.org/python3/'), + stacklevel=bad_frame) + + +def _verify_python3_env(): + """Ensures that the environment is good for unicode on Python 3.""" + if PY2: + return + try: + import locale + fs_enc = codecs.lookup(locale.getpreferredencoding()).name + except Exception: + fs_enc = 'ascii' + if fs_enc != 'ascii': + return + + extra = '' + if os.name == 'posix': + import subprocess + rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + good_locales = set() + has_c_utf8 = False + + # Make sure we're operating on text here. + if isinstance(rv, bytes): + rv = rv.decode('ascii', 'replace') + + for line in rv.splitlines(): + locale = line.strip() + if locale.lower().endswith(('.utf-8', '.utf8')): + good_locales.add(locale) + if locale.lower() in ('c.utf8', 'c.utf-8'): + has_c_utf8 = True + + extra += '\n\n' + if not good_locales: + extra += ( + 'Additional information: on this system no suitable UTF-8\n' + 'locales were discovered. This most likely requires resolving\n' + 'by reconfiguring the locale system.' + ) + elif has_c_utf8: + extra += ( + 'This system supports the C.UTF-8 locale which is recommended.\n' + 'You might be able to resolve your issue by exporting the\n' + 'following environment variables:\n\n' + ' export LC_ALL=C.UTF-8\n' + ' export LANG=C.UTF-8' + ) + else: + extra += ( + 'This system lists a couple of UTF-8 supporting locales that\n' + 'you can pick from. The following suitable locales where\n' + 'discovered: %s' + ) % ', '.join(sorted(good_locales)) + + bad_locale = None + for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'): + if locale and locale.lower().endswith(('.utf-8', '.utf8')): + bad_locale = locale + if locale is not None: + break + if bad_locale is not None: + extra += ( + '\n\nClick discovered that you exported a UTF-8 locale\n' + 'but the locale system could not pick up from it because\n' + 'it does not exist. The exported locale is "%s" but it\n' + 'is not supported' + ) % bad_locale + + raise RuntimeError('Click will abort further execution because Python 3 ' + 'was configured to use ASCII as encoding for the ' + 'environment. Consult http://click.pocoo.org/python3/' + 'for mitigation steps.' + extra) diff --git a/pipenv/vendor/click/_winconsole.py b/pipenv/vendor/click/_winconsole.py new file mode 100644 index 00000000..9aed9421 --- /dev/null +++ b/pipenv/vendor/click/_winconsole.py @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prmopt. + +import io +import os +import sys +import zlib +import time +import ctypes +import msvcrt +from click._compat import _NonClosingTextIOWrapper, text_type, PY2 +from ctypes import byref, POINTER, c_int, c_char, c_char_p, \ + c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE +try: + from ctypes import pythonapi + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release +except ImportError: + pythonapi = None +from ctypes.wintypes import LPWSTR, LPCWSTR + + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)( + ('GetCommandLineW', windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE( + POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ('CommandLineToArgvW', windll.shell32)) + + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b'\x1a' +MAX_BYTES_WRITTEN = 32767 + + +class Py_buffer(ctypes.Structure): + _fields_ = [ + ('buf', c_void_p), + ('obj', py_object), + ('len', c_ssize_t), + ('itemsize', c_ssize_t), + ('readonly', c_int), + ('ndim', c_int), + ('format', c_char_p), + ('shape', c_ssize_p), + ('strides', c_ssize_p), + ('suboffsets', c_ssize_p), + ('internal', c_void_p) + ] + + if PY2: + _fields_.insert(-1, ('smalltable', c_ssize_t * 2)) + + +# On PyPy we cannot get buffers so our ability to operate here is +# serverly limited. +if pythonapi is None: + get_buffer = None +else: + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + + def __init__(self, handle): + self.handle = handle + + def isatty(self): + io.RawIOBase.isatty(self) + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError('cannot read odd number of bytes from ' + 'UTF-16-LE encoded console') + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read, + byref(code_units_read), None) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError('Windows error: %s' % GetLastError()) + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return 'ERROR_SUCCESS' + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return 'ERROR_NOT_ENOUGH_MEMORY' + return 'Windows error %s' % errno + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, + MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW(self.handle, buf, code_units_to_be_written, + byref(code_units_written), None) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream(object): + + def __init__(self, text_stream, byte_stream): + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self): + return self.buffer.name + + def write(self, x): + if isinstance(x, text_type): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __getattr__(self, name): + return getattr(self._text_stream, name) + + def isatty(self): + return self.buffer.isatty() + + def __repr__(self): + return '' % ( + self.name, + self.encoding, + ) + + +def _get_text_stdin(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stdout(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDOUT_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stderr(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDERR_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +if PY2: + def _hash_py_argv(): + return zlib.crc32('\x00'.join(sys.argv[1:])) + + _initial_argv_hash = _hash_py_argv() + + def _get_windows_argv(): + argc = c_int(0) + argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) + argv = [argv_unicode[i] for i in range(0, argc.value)] + + if not hasattr(sys, 'frozen'): + argv = argv[1:] + while len(argv) > 0: + arg = argv[0] + if not arg.startswith('-') or arg == '-': + break + argv = argv[1:] + if arg.startswith(('-c', '-m')): + break + + return argv[1:] + + +_stream_factories = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _get_windows_console_stream(f, encoding, errors): + if get_buffer is not None and \ + encoding in ('utf-16-le', None) \ + and errors in ('strict', None) and \ + hasattr(f, 'isatty') and f.isatty(): + func = _stream_factories.get(f.fileno()) + if func is not None: + if not PY2: + f = getattr(f, 'buffer') + if f is None: + return None + else: + # If we are on Python 2 we need to set the stream that we + # deal with to binary mode as otherwise the exercise if a + # bit moot. The same problems apply as for + # get_binary_stdin and friends from _compat. + msvcrt.setmode(f.fileno(), os.O_BINARY) + return func(f) diff --git a/pipenv/vendor/click/core.py b/pipenv/vendor/click/core.py new file mode 100644 index 00000000..74564514 --- /dev/null +++ b/pipenv/vendor/click/core.py @@ -0,0 +1,1744 @@ +import errno +import os +import sys +from contextlib import contextmanager +from itertools import repeat +from functools import update_wrapper + +from .types import convert_type, IntRange, BOOL +from .utils import make_str, make_default_short_help, echo, get_os_args +from .exceptions import ClickException, UsageError, BadParameter, Abort, \ + MissingParameter +from .termui import prompt, confirm +from .formatting import HelpFormatter, join_options +from .parser import OptionParser, split_opt +from .globals import push_context, pop_context + +from ._compat import PY2, isidentifier, iteritems +from ._unicodefun import _check_for_unicode_literals, _verify_python3_env + + +_missing = object() + + +SUBCOMMAND_METAVAR = 'COMMAND [ARGS]...' +SUBCOMMANDS_METAVAR = 'COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...' + + +def _bashcomplete(cmd, prog_name, complete_var=None): + """Internal handler for the bash completion support.""" + if complete_var is None: + complete_var = '_%s_COMPLETE' % (prog_name.replace('-', '_')).upper() + complete_instr = os.environ.get(complete_var) + if not complete_instr: + return + + from ._bashcomplete import bashcomplete + if bashcomplete(cmd, prog_name, complete_var, complete_instr): + sys.exit(1) + + +def _check_multicommand(base_command, cmd_name, cmd, register=False): + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = 'It is not possible to add multi commands as children to ' \ + 'another multi command that is in chain mode' + else: + hint = 'Found a multi command as subcommand to a multi command ' \ + 'that is in chain mode. This is not supported' + raise RuntimeError('%s. Command "%s" is set to chain and "%s" was ' + 'added as subcommand but it in itself is a ' + 'multi command. ("%s" is a %s within a chained ' + '%s named "%s"). This restriction was supposed to ' + 'be lifted in 6.0 but the fix was flawed. This ' + 'will be fixed in Click 7.0' % ( + hint, base_command.name, cmd_name, + cmd_name, cmd.__class__.__name__, + base_command.__class__.__name__, + base_command.name)) + + +def batch(iterable, batch_size): + return list(zip(*repeat(iter(iterable), batch_size))) + + +def invoke_param_callback(callback, ctx, param, value): + code = getattr(callback, '__code__', None) + args = getattr(code, 'co_argcount', 3) + + if args < 3: + # This will become a warning in Click 3.0: + from warnings import warn + warn(Warning('Invoked legacy parameter callback "%s". The new ' + 'signature for such callbacks starting with ' + 'click 2.0 is (ctx, param, value).' + % callback), stacklevel=3) + return callback(ctx, value) + return callback(ctx, param, value) + + +@contextmanager +def augment_usage_errors(ctx, param=None): + """Context manager that attaches extra information to exceptions that + fly. + """ + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing(invocation_order, declaration_order): + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + def sort_key(item): + try: + idx = invocation_order.index(item) + except ValueError: + idx = float('inf') + return (not item.is_eager, idx) + + return sorted(declaration_order, key=sort_key) + + +class Context(object): + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + .. versionadded:: 2.0 + Added the `resilient_parsing`, `help_option_names`, + `token_normalize_func` parameters. + + .. versionadded:: 3.0 + Added the `allow_extra_args` and `allow_interspersed_args` + parameters. + + .. versionadded:: 4.0 + Added the `color`, `ignore_unknown_options`, and + `max_content_width` parameters. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + """ + + def __init__(self, command, parent=None, info_name=None, obj=None, + auto_envvar_prefix=None, default_map=None, + terminal_width=None, max_content_width=None, + resilient_parsing=False, allow_extra_args=None, + allow_interspersed_args=None, + ignore_unknown_options=None, help_option_names=None, + token_normalize_func=None, color=None): + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: the parsed parameters except if the value is hidden in which + #: case it's not remembered. + self.params = {} + #: the leftover arguments. + self.args = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args = [] + if obj is None and parent is not None: + obj = parent.obj + #: the user object stored. + self.obj = obj + self._meta = getattr(parent, 'meta', {}) + + #: A dictionary (-like object) with defaults for parameters. + if default_map is None \ + and parent is not None \ + and parent.default_map is not None: + default_map = parent.default_map.get(info_name) + self.default_map = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`resultcallback`. + self.invoked_subcommand = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + #: The width of the terminal (None is autodetection). + self.terminal_width = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ['--help'] + + #: The names for the help options. + self.help_option_names = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures. + self.resilient_parsing = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if parent is not None \ + and parent.auto_envvar_prefix is not None and \ + self.info_name is not None: + auto_envvar_prefix = '%s_%s' % (parent.auto_envvar_prefix, + self.info_name.upper()) + else: + self.auto_envvar_prefix = auto_envvar_prefix.upper() + self.auto_envvar_prefix = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color = color + + self._close_callbacks = [] + self._depth = 0 + + def __enter__(self): + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup=True): + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self): + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utiltiies can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = __name__ + '.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self): + """Creates the formatter for the help and usage output.""" + return HelpFormatter(width=self.terminal_width, + max_width=self.max_content_width) + + def call_on_close(self, f): + """This decorator remembers a function as callback that should be + executed when the context tears down. This is most useful to bind + resource handling to the script execution. For instance, file objects + opened by the :class:`File` type will register their close callbacks + here. + + :param f: the function to execute on teardown. + """ + self._close_callbacks.append(f) + return f + + def close(self): + """Invokes all close callbacks.""" + for cb in self._close_callbacks: + cb() + self._close_callbacks = [] + + @property + def command_path(self): + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = '' + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + rv = self.parent.command_path + ' ' + rv + return rv.lstrip() + + def find_root(self): + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type): + """Finds the closest object of a given type.""" + node = self + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + node = node.parent + + def ensure_object(self, object_type): + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + def lookup_default(self, name): + """Looks up the default for a parameter name. This by default + looks into the :attr:`default_map` if available. + """ + if self.default_map is not None: + rv = self.default_map.get(name) + if callable(rv): + rv = rv() + return rv + + def fail(self, message): + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self): + """Aborts the script.""" + raise Abort() + + def exit(self, code=0): + """Exits the application with a given exit code.""" + sys.exit(code) + + def get_usage(self): + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self): + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def invoke(*args, **kwargs): + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + """ + self, callback = args[:2] + ctx = self + + # It's also possible to invoke another command which might or + # might not have a callback. In that case we also fill + # in defaults and make a new context for this command. + if isinstance(callback, Command): + other_cmd = callback + callback = other_cmd.callback + ctx = Context(other_cmd, info_name=other_cmd.name, parent=self) + if callback is None: + raise TypeError('The given command does not have a ' + 'callback that can be invoked.') + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.get_default(ctx) + + args = args[2:] + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(*args, **kwargs): + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + """ + self, cmd = args[:2] + + # It's also possible to invoke another command which might or + # might not have a callback. + if not isinstance(cmd, Command): + raise TypeError('Callback is not a command.') + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, **kwargs) + + +class BaseCommand(object): + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__(self, name, context_settings=None): + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + if context_settings is None: + context_settings = {} + #: an optional dictionary with defaults passed to the context. + self.context_settings = context_settings + + def get_usage(self, ctx): + raise NotImplementedError('Base commands cannot get usage') + + def get_help(self, ctx): + raise NotImplementedError('Base commands cannot get help') + + def make_context(self, info_name, args, parent=None, **extra): + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + :param info_name: the info name for this invokation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the script. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + """ + for key, value in iteritems(self.context_settings): + if key not in extra: + extra[key] = value + ctx = Context(self, info_name=info_name, parent=parent, **extra) + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx, args): + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError('Base commands do not know how to parse ' + 'arguments.') + + def invoke(self, ctx): + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError('Base commands are not invokable by default') + + def main(self, args=None, prog_name=None, complete_var=None, + standalone_mode=True, **extra): + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + .. versionadded:: 3.0 + Added the `standalone_mode` flag to control the standalone mode. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + """ + # If we are in Python 3, we will verify that the environment is + # sane at this point of reject further execution to avoid a + # broken script. + if not PY2: + _verify_python3_env() + else: + _check_for_unicode_literals() + + if args is None: + args = get_os_args() + else: + args = list(args) + + if prog_name is None: + prog_name = make_str(os.path.basename( + sys.argv and sys.argv[0] or __file__)) + + # Hook for the Bash completion. This only activates if the Bash + # completion is actually enabled, otherwise this is quite a fast + # noop. + _bashcomplete(self, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except IOError as e: + if e.errno == errno.EPIPE: + sys.exit(1) + else: + raise + except Abort: + if not standalone_mode: + raise + echo('Aborted!', file=sys.stderr) + sys.exit(1) + + def __call__(self, *args, **kwargs): + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + """ + + def __init__(self, name, context_settings=None, callback=None, + params=None, help=None, epilog=None, short_help=None, + options_metavar='[OPTIONS]', add_help_option=True): + BaseCommand.__init__(self, name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + if short_help is None and help: + short_help = make_default_short_help(help) + self.short_help = short_help + self.add_help_option = add_help_option + + def get_usage(self, ctx): + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def get_params(self, ctx): + rv = self.params + help_option = self.get_help_option(ctx) + if help_option is not None: + rv = rv + [help_option] + return rv + + def format_usage(self, ctx, formatter): + """Writes the usage line into the formatter.""" + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, ' '.join(pieces)) + + def collect_usage_pieces(self, ctx): + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + return rv + + def get_help_option_names(self, ctx): + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return all_names + + def get_help_option(self, ctx): + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + if not help_options or not self.add_help_option: + return + + def show_help(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + return Option(help_options, is_flag=True, + is_eager=True, expose_value=False, + callback=show_help, + help='Show this message and exit.') + + def make_parser(self, ctx): + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + parser.allow_interspersed_args = ctx.allow_interspersed_args + parser.ignore_unknown_options = ctx.ignore_unknown_options + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx): + """Formats the help into a string and returns it. This creates a + formatter and will call into the following formatting methods: + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def format_help(self, ctx, formatter): + """Writes the help into the formatter if it exists. + + This calls into the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx, formatter): + """Writes the help text to the formatter if it exists.""" + if self.help: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.help) + + def format_options(self, ctx, formatter): + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section('Options'): + formatter.write_dl(opts) + + def format_epilog(self, ctx, formatter): + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.epilog) + + def parse_args(self, ctx, args): + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing( + param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail('Got unexpected extra argument%s (%s)' + % (len(args) != 1 and 's' or '', + ' '.join(map(make_str, args)))) + + ctx.args = args + return args + + def invoke(self, ctx): + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: the result callback to attach to this multi + command. + """ + allow_extra_args = True + allow_interspersed_args = False + + def __init__(self, name=None, invoke_without_command=False, + no_args_is_help=None, subcommand_metavar=None, + chain=False, result_callback=None, **attrs): + Command.__init__(self, name, **attrs) + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + if subcommand_metavar is None: + if chain: + subcommand_metavar = SUBCOMMANDS_METAVAR + else: + subcommand_metavar = SUBCOMMAND_METAVAR + self.subcommand_metavar = subcommand_metavar + self.chain = chain + #: The result callback that is stored. This can be set or + #: overridden with the :func:`resultcallback` decorator. + self.result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError('Multi commands in chain mode cannot ' + 'have optional arguments.') + + def collect_usage_pieces(self, ctx): + rv = Command.collect_usage_pieces(self, ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx, formatter): + Command.format_options(self, ctx, formatter) + self.format_commands(ctx, formatter) + + def resultcallback(self, replace=False): + """Adds a result callback to the chain command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.resultcallback() + def process_result(result, input): + return result + input + + .. versionadded:: 3.0 + + :param replace: if set to `True` an already existing result + callback will be removed. + """ + def decorator(f): + old_callback = self.result_callback + if old_callback is None or replace: + self.result_callback = f + return f + def function(__value, *args, **kwargs): + return f(old_callback(__value, *args, **kwargs), + *args, **kwargs) + self.result_callback = rv = update_wrapper(function, f) + return rv + return decorator + + def format_commands(self, ctx, formatter): + """Extra format methods for multi methods that adds all the commands + after the options. + """ + rows = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + + help = cmd.short_help or '' + rows.append((subcommand, help)) + + if rows: + with formatter.section('Commands'): + formatter.write_dl(rows) + + def parse_args(self, ctx, args): + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = Command.parse_args(self, ctx, args) + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx): + def _process_result(value): + if self.result_callback is not None: + value = ctx.invoke(self.result_callback, value, + **ctx.params) + return value + + if not ctx.protected_args: + # If we are invoked without command the chain flag controls + # how this happens. If we are not in chain mode, the return + # value here is the return value of the command. + # If however we are in chain mode, the return value is the + # return value of the result processor invoked with an empty + # list (which means that no subcommand actually was executed). + if self.invoke_without_command: + if not self.chain: + return Command.invoke(self, ctx) + with ctx: + Command.invoke(self, ctx) + return _process_result([]) + ctx.fail('Missing command.') + + # Fetch args back out + args = ctx.protected_args + ctx.args + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + ctx.invoked_subcommand = cmd_name + Command.invoke(self, ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = args and '*' or None + Command.invoke(self, ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command(self, ctx, args): + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail('No such command "%s".' % original_cmd_name) + + return cmd_name, cmd, args[1:] + + def get_command(self, ctx, cmd_name): + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError() + + def list_commands(self, ctx): + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is the + most common way to implement nesting in Click. + + :param commands: a dictionary of commands. + """ + + def __init__(self, name=None, commands=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: the registered subcommands by their exported names. + self.commands = commands or {} + + def add_command(self, cmd, name=None): + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError('Command has no name.') + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + def command(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def group(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def get_command(self, ctx, cmd_name): + return self.commands.get(cmd_name) + + def list_commands(self, ctx): + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__(self, name=None, sources=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: The list of registered multi commands. + self.sources = sources or [] + + def add_source(self, multi_cmd): + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx, cmd_name): + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + return rv + + def list_commands(self, ctx): + rv = set() + for source in self.sources: + rv.update(source.list_commands(ctx)) + return sorted(rv) + + +class Parameter(object): + """A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. In Click 2.0, the old callback format will still work, + but it will raise a warning to give you change to migrate the + code easier. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: a callback that should be executed after the parameter + was matched. This is called as ``fn(ctx, param, + value)`` and needs to return the value. Before Click + 2.0, the signature was ``(ctx, value)``. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + """ + param_type_name = 'parameter' + + def __init__(self, param_decls=None, type=None, required=False, + default=None, callback=None, nargs=None, metavar=None, + expose_value=True, is_eager=False, envvar=None): + self.name, self.opts, self.secondary_opts = \ + self._parse_decls(param_decls or (), expose_value) + + self.type = convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = False + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + + @property + def human_readable_name(self): + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + metavar = self.type.get_metavar(self) + if metavar is None: + metavar = self.type.name.upper() + if self.nargs != 1: + metavar += '...' + return metavar + + def get_default(self, ctx): + """Given a context variable this calculates the default value.""" + # Otherwise go with the regular default. + if callable(self.default): + rv = self.default() + else: + rv = self.default + return self.type_cast_value(ctx, rv) + + def add_to_parser(self, parser, ctx): + pass + + def consume_value(self, ctx, opts): + value = opts.get(self.name) + if value is None: + value = ctx.lookup_default(self.name) + if value is None: + value = self.value_from_envvar(ctx) + return value + + def type_cast_value(self, ctx, value): + """Given a value this runs it properly through the type system. + This automatically handles things like `nargs` and `multiple` as + well as composite types. + """ + if self.type.is_composite: + if self.nargs <= 1: + raise TypeError('Attempted to invoke composite type ' + 'but nargs has been set to %s. This is ' + 'not supported; nargs needs to be set to ' + 'a fixed value > 1.' % self.nargs) + if self.multiple: + return tuple(self.type(x or (), self, ctx) for x in value or ()) + return self.type(value or (), self, ctx) + + def _convert(value, level): + if level == 0: + return self.type(value, self, ctx) + return tuple(_convert(x, level - 1) for x in value or ()) + return _convert(value, (self.nargs != 1) + bool(self.multiple)) + + def process_value(self, ctx, value): + """Given a value and context this runs the logic to convert the + value as necessary. + """ + # If the value we were given is None we do nothing. This way + # code that calls this can easily figure out if something was + # not provided. Otherwise it would be converted into an empty + # tuple for multiple invocations which is inconvenient. + if value is not None: + return self.type_cast_value(ctx, value) + + def value_is_missing(self, value): + if value is None: + return True + if (self.nargs != 1 or self.multiple) and value == (): + return True + return False + + def full_process_value(self, ctx, value): + value = self.process_value(ctx, value) + + if value is None: + value = self.get_default(ctx) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + return value + + def resolve_envvar_value(self, ctx): + if self.envvar is None: + return + if isinstance(self.envvar, (tuple, list)): + for envvar in self.envvar: + rv = os.environ.get(envvar) + if rv is not None: + return rv + else: + return os.environ.get(self.envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + return rv + + def handle_parse_result(self, ctx, opts, args): + with augment_usage_errors(ctx, param=self): + value = self.consume_value(ctx, opts) + try: + value = self.full_process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + value = None + if self.callback is not None: + try: + value = invoke_param_callback( + self.callback, ctx, self, value) + except Exception: + if not ctx.resilient_parsing: + raise + + if self.expose_value: + ctx.params[self.name] = value + return value, args + + def get_help_record(self, ctx): + pass + + def get_usage_pieces(self, ctx): + return [] + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: controls if the default value should be shown on the + help page. Normally, defaults are not shown. + :param prompt: if set to `True` or a non empty string then the user will + be prompted for input if not set. If set to `True` the + prompt will be the option name capitalized. + :param confirmation_prompt: if set then the value will need to be confirmed + if it was prompted for. + :param hide_input: if this is `True` then the input on the prompt will be + hidden from the user. This is useful for password + input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + """ + param_type_name = 'option' + + def __init__(self, param_decls=None, show_default=False, + prompt=False, confirmation_prompt=False, + hide_input=False, is_flag=None, flag_value=None, + multiple=False, count=False, allow_from_autoenv=True, + type=None, help=None, **attrs): + default_is_missing = attrs.get('default', _missing) is _missing + Parameter.__init__(self, param_decls, type=type, **attrs) + + if prompt is True: + prompt_text = self.name.replace('_', ' ').capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.hide_input = hide_input + + # Flags + if is_flag is None: + if flag_value is not None: + is_flag = True + else: + is_flag = bool(self.secondary_opts) + if is_flag and default_is_missing: + self.default = False + if flag_value is None: + flag_value = not self.default + self.is_flag = is_flag + self.flag_value = flag_value + if self.is_flag and isinstance(self.flag_value, bool) \ + and type is None: + self.type = BOOL + self.is_bool_flag = True + else: + self.is_bool_flag = False + + # Counting + self.count = count + if count: + if type is None: + self.type = IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.multiple = multiple + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + + # Sanity check for stuff we don't support + if __debug__: + if self.nargs < 0: + raise TypeError('Options cannot have nargs < 0') + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError('Cannot prompt for flags that are not bools.') + if not self.is_bool_flag and self.secondary_opts: + raise TypeError('Got secondary option for non boolean flag.') + if self.is_bool_flag and self.hide_input \ + and self.prompt is not None: + raise TypeError('Hidden input does not work with boolean ' + 'flag prompts.') + if self.count: + if self.multiple: + raise TypeError('Options cannot be multiple and count ' + 'at the same time.') + elif self.is_flag: + raise TypeError('Options cannot be count and flags at ' + 'the same time.') + + def _parse_decls(self, decls, expose_value): + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if isidentifier(decl): + if name is not None: + raise TypeError('Name defined twice') + name = decl + else: + split_char = decl[:1] == '/' and ';' or '/' + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: len(x[0])) + name = possible_names[-1][1].replace('-', '_').lower() + if not isidentifier(name): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError('Could not determine name for option') + + if not opts and not secondary_opts: + raise TypeError('No options defined but a name was passed (%s). ' + 'Did you mean to declare an argument instead ' + 'of an option?' % name) + + return name, opts, secondary_opts + + def add_to_parser(self, parser, ctx): + kwargs = { + 'dest': self.name, + 'nargs': self.nargs, + 'obj': self, + } + + if self.multiple: + action = 'append' + elif self.count: + action = 'count' + else: + action = 'store' + + if self.is_flag: + kwargs.pop('nargs', None) + if self.is_bool_flag and self.secondary_opts: + parser.add_option(self.opts, action=action + '_const', + const=True, **kwargs) + parser.add_option(self.secondary_opts, action=action + + '_const', const=False, **kwargs) + else: + parser.add_option(self.opts, action=action + '_const', + const=self.flag_value, + **kwargs) + else: + kwargs['action'] = action + parser.add_option(self.opts, **kwargs) + + def get_help_record(self, ctx): + any_prefix_is_slash = [] + + def _write_opts(opts): + rv, any_slashes = join_options(opts) + if any_slashes: + any_prefix_is_slash[:] = [True] + if not self.is_flag and not self.count: + rv += ' ' + self.make_metavar() + return rv + + rv = [_write_opts(self.opts)] + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or '' + extra = [] + if self.default is not None and self.show_default: + extra.append('default: %s' % ( + ', '.join('%s' % d for d in self.default) + if isinstance(self.default, (list, tuple)) + else self.default, )) + if self.required: + extra.append('required') + if extra: + help = '%s[%s]' % (help and help + ' ' or '', '; '.join(extra)) + + return ((any_prefix_is_slash and '; ' or ' / ').join(rv), help) + + def get_default(self, ctx): + # If we're a non boolean flag out default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value + return None + return Parameter.get_default(self, ctx) + + def prompt_for_value(self, ctx): + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt(self.prompt, default=default, + hide_input=self.hide_input, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x)) + + def resolve_envvar_value(self, ctx): + rv = Parameter.resolve_envvar_value(self, ctx) + if rv is not None: + return rv + if self.allow_from_autoenv and \ + ctx.auto_envvar_prefix is not None: + envvar = '%s_%s' % (ctx.auto_envvar_prefix, self.name.upper()) + return os.environ.get(envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is None: + return None + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0 and rv is not None: + rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + return rv + + def full_process_value(self, ctx, value): + if value is None and self.prompt is not None \ + and not ctx.resilient_parsing: + return self.prompt_for_value(ctx) + return Parameter.full_process_value(self, ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + param_type_name = 'argument' + + def __init__(self, param_decls, required=None, **attrs): + if required is None: + if attrs.get('default') is not None: + required = False + else: + required = attrs.get('nargs', 1) > 0 + Parameter.__init__(self, param_decls, required=required, **attrs) + if self.default is not None and self.nargs < 0: + raise TypeError('nargs=-1 in combination with a default value ' + 'is not supported.') + + @property + def human_readable_name(self): + if self.metavar is not None: + return self.metavar + return self.name.upper() + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + var = self.name.upper() + if not self.required: + var = '[%s]' % var + if self.nargs != 1: + var += '...' + return var + + def _parse_decls(self, decls, expose_value): + if not decls: + if not expose_value: + return None, [], [] + raise TypeError('Could not determine name for argument') + if len(decls) == 1: + name = arg = decls[0] + name = name.replace('-', '_').lower() + elif len(decls) == 2: + name, arg = decls + else: + raise TypeError('Arguments take exactly one or two ' + 'parameter declarations, got %d' % len(decls)) + return name, [arg], [] + + def get_usage_pieces(self, ctx): + return [self.make_metavar()] + + def add_to_parser(self, parser, ctx): + parser.add_argument(dest=self.name, nargs=self.nargs, + obj=self) + + +# Circular dependency between decorators and core +from .decorators import command, group diff --git a/pipenv/vendor/click/decorators.py b/pipenv/vendor/click/decorators.py new file mode 100644 index 00000000..98934526 --- /dev/null +++ b/pipenv/vendor/click/decorators.py @@ -0,0 +1,304 @@ +import sys +import inspect + +from functools import update_wrapper + +from ._compat import iteritems +from ._unicodefun import _check_for_unicode_literals +from .utils import echo +from .globals import get_current_context + + +def pass_context(f): + """Marks a callback as wanting to receive the current context + object as first argument. + """ + def new_func(*args, **kwargs): + return f(get_current_context(), *args, **kwargs) + return update_wrapper(new_func, f) + + +def pass_obj(f): + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + def new_func(*args, **kwargs): + return f(get_current_context().obj, *args, **kwargs) + return update_wrapper(new_func, f) + + +def make_pass_decorator(object_type, ensure=False): + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + def decorator(f): + def new_func(*args, **kwargs): + ctx = get_current_context() + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + if obj is None: + raise RuntimeError('Managed to invoke callback without a ' + 'context object of type %r existing' + % object_type.__name__) + return ctx.invoke(f, obj, *args[1:], **kwargs) + return update_wrapper(new_func, f) + return decorator + + +def _make_command(f, name, attrs, cls): + if isinstance(f, Command): + raise TypeError('Attempted to convert a callback into a ' + 'command twice.') + try: + params = f.__click_params__ + params.reverse() + del f.__click_params__ + except AttributeError: + params = [] + help = attrs.get('help') + if help is None: + help = inspect.getdoc(f) + if isinstance(help, bytes): + help = help.decode('utf-8') + else: + help = inspect.cleandoc(help) + attrs['help'] = help + _check_for_unicode_literals() + return cls(name=name or f.__name__.lower(), + callback=f, params=params, **attrs) + + +def command(name=None, cls=None, **attrs): + """Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function. If you + want to change that, you can pass the intended name as the first + argument. + + All keyword arguments are forwarded to the underlying command class. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + """ + if cls is None: + cls = Command + def decorator(f): + cmd = _make_command(f, name, attrs, cls) + cmd.__doc__ = f.__doc__ + return cmd + return decorator + + +def group(name=None, **attrs): + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + """ + attrs.setdefault('cls', Group) + return command(name, **attrs) + + +def _param_memo(f, param): + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, '__click_params__'): + f.__click_params__ = [] + f.__click_params__.append(param) + + +def argument(*param_decls, **attrs): + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + def decorator(f): + ArgumentClass = attrs.pop('cls', Argument) + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + return decorator + + +def option(*param_decls, **attrs): + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + def decorator(f): + if 'help' in attrs: + attrs['help'] = inspect.cleandoc(attrs['help']) + OptionClass = attrs.pop('cls', Option) + _param_memo(f, OptionClass(param_decls, **attrs)) + return f + return decorator + + +def confirmation_option(*param_decls, **attrs): + """Shortcut for confirmation prompts that can be ignored by passing + ``--yes`` as parameter. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + def callback(ctx, param, value): + if not value: + ctx.abort() + + @click.command() + @click.option('--yes', is_flag=True, callback=callback, + expose_value=False, prompt='Do you want to continue?') + def dropdb(): + pass + """ + def decorator(f): + def callback(ctx, param, value): + if not value: + ctx.abort() + attrs.setdefault('is_flag', True) + attrs.setdefault('callback', callback) + attrs.setdefault('expose_value', False) + attrs.setdefault('prompt', 'Do you want to continue?') + attrs.setdefault('help', 'Confirm the action without prompting.') + return option(*(param_decls or ('--yes',)), **attrs)(f) + return decorator + + +def password_option(*param_decls, **attrs): + """Shortcut for password prompts. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + @click.command() + @click.option('--password', prompt=True, confirmation_prompt=True, + hide_input=True) + def changeadmin(password): + pass + """ + def decorator(f): + attrs.setdefault('prompt', True) + attrs.setdefault('confirmation_prompt', True) + attrs.setdefault('hide_input', True) + return option(*(param_decls or ('--password',)), **attrs)(f) + return decorator + + +def version_option(version=None, *param_decls, **attrs): + """Adds a ``--version`` option which immediately ends the program + printing out the version number. This is implemented as an eager + option that prints the version and exits the program in the callback. + + :param version: the version number to show. If not provided Click + attempts an auto discovery via setuptools. + :param prog_name: the name of the program (defaults to autodetection) + :param message: custom message to show instead of the default + (``'%(prog)s, version %(version)s'``) + :param others: everything else is forwarded to :func:`option`. + """ + if version is None: + module = sys._getframe(1).f_globals.get('__name__') + def decorator(f): + prog_name = attrs.pop('prog_name', None) + message = attrs.pop('message', '%(prog)s, version %(version)s') + + def callback(ctx, param, value): + if not value or ctx.resilient_parsing: + return + prog = prog_name + if prog is None: + prog = ctx.find_root().info_name + ver = version + if ver is None: + try: + import pkg_resources + except ImportError: + pass + else: + for dist in pkg_resources.working_set: + scripts = dist.get_entry_map().get('console_scripts') or {} + for script_name, entry_point in iteritems(scripts): + if entry_point.module_name == module: + ver = dist.version + break + if ver is None: + raise RuntimeError('Could not determine version') + echo(message % { + 'prog': prog, + 'version': ver, + }, color=ctx.color) + ctx.exit() + + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('is_eager', True) + attrs.setdefault('help', 'Show the version and exit.') + attrs['callback'] = callback + return option(*(param_decls or ('--version',)), **attrs)(f) + return decorator + + +def help_option(*param_decls, **attrs): + """Adds a ``--help`` option which immediately ends the program + printing out the help page. This is usually unnecessary to add as + this is added by default to all commands unless suppressed. + + Like :func:`version_option`, this is implemented as eager option that + prints in the callback and exits. + + All arguments are forwarded to :func:`option`. + """ + def decorator(f): + def callback(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('help', 'Show this message and exit.') + attrs.setdefault('is_eager', True) + attrs['callback'] = callback + return option(*(param_decls or ('--help',)), **attrs)(f) + return decorator + + +# Circular dependencies between core and decorators +from .core import Command, Group, Argument, Option diff --git a/pipenv/vendor/click/exceptions.py b/pipenv/vendor/click/exceptions.py new file mode 100644 index 00000000..74a4542b --- /dev/null +++ b/pipenv/vendor/click/exceptions.py @@ -0,0 +1,201 @@ +from ._compat import PY2, filename_to_ui, get_text_stderr +from .utils import echo + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception + exit_code = 1 + + def __init__(self, message): + if PY2: + if message is not None: + message = message.encode('utf-8') + Exception.__init__(self, message) + self.message = message + + def format_message(self): + return self.message + + def show(self, file=None): + if file is None: + file = get_text_stderr() + echo('Error: %s' % self.format_message(), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + exit_code = 2 + + def __init__(self, message, ctx=None): + ClickException.__init__(self, message) + self.ctx = ctx + + def show(self, file=None): + if file is None: + file = get_text_stderr() + color = None + if self.ctx is not None: + color = self.ctx.color + echo(self.ctx.get_usage() + '\n', file=file, color=color) + echo('Error: %s' % self.format_message(), file=file, color=color) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__(self, message, ctx=None, param=None, + param_hint=None): + UsageError.__init__(self, message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + return 'Invalid value: %s' % self.message + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + return 'Invalid value for %s: %s' % (param_hint, self.message) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__(self, message=None, ctx=None, param=None, + param_hint=None, param_type=None): + BadParameter.__init__(self, message, ctx, param, param_hint) + self.param_type = param_type + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + param_hint = None + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += '. ' + msg_extra + else: + msg = msg_extra + + return 'Missing %s%s%s%s' % ( + param_type, + param_hint and ' %s' % param_hint or '', + msg and '. ' or '.', + msg or '', + ) + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__(self, option_name, message=None, possibilities=None, + ctx=None): + if message is None: + message = 'no such option: %s' % option_name + UsageError.__init__(self, message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self): + bits = [self.message] + if self.possibilities: + if len(self.possibilities) == 1: + bits.append('Did you mean %s?' % self.possibilities[0]) + else: + possibilities = sorted(self.possibilities) + bits.append('(Possible options: %s)' % ', '.join(possibilities)) + return ' '.join(bits) + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename, hint=None): + ui_filename = filename_to_ui(filename) + if hint is None: + hint = 'unknown error' + ClickException.__init__(self, hint) + self.ui_filename = ui_filename + self.filename = filename + + def format_message(self): + return 'Could not open file %s: %s' % (self.ui_filename, self.message) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" diff --git a/pipenv/vendor/click/formatting.py b/pipenv/vendor/click/formatting.py new file mode 100644 index 00000000..a3d6a4d3 --- /dev/null +++ b/pipenv/vendor/click/formatting.py @@ -0,0 +1,256 @@ +from contextlib import contextmanager +from .termui import get_terminal_size +from .parser import split_opt +from ._compat import term_len + + +# Can force a width. This is used by the test system +FORCED_WIDTH = None + + +def measure_table(rows): + widths = {} + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows(rows, col_count): + for row in rows: + row = tuple(row) + yield row + ('',) * (col_count - len(row)) + + +def wrap_text(text, width=78, initial_indent='', subsequent_indent='', + preserve_paragraphs=False): + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + text = text.expandtabs() + wrapper = TextWrapper(width, initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False) + if not preserve_paragraphs: + return wrapper.fill(text) + + p = [] + buf = [] + indent = None + + def _flush_par(): + if not buf: + return + if buf[0].strip() == '\b': + p.append((indent or 0, True, '\n'.join(buf[1:]))) + else: + p.append((indent or 0, False, ' '.join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(' ' * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return '\n\n'.join(rv) + + +class HelpFormatter(object): + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__(self, indent_increment=2, width=None, max_width=None): + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(get_terminal_size()[0], max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer = [] + + def write(self, string): + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self): + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self): + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog, args='', prefix='Usage: '): + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: the prefix for the first line. + """ + usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog) + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = ' ' * term_len(usage_prefix) + self.write(wrap_text(args, text_width, + initial_indent=usage_prefix, + subsequent_indent=indent)) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write('\n') + indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4) + self.write(wrap_text(args, text_width, + initial_indent=indent, + subsequent_indent=indent)) + + self.write('\n') + + def write_heading(self, heading): + """Writes a heading into the buffer.""" + self.write('%*s%s:\n' % (self.current_indent, '', heading)) + + def write_paragraph(self): + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write('\n') + + def write_text(self, text): + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + text_width = max(self.width - self.current_indent, 11) + indent = ' ' * self.current_indent + self.write(wrap_text(text, text_width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True)) + self.write('\n') + + def write_dl(self, rows, col_max=30, col_spacing=2): + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError('Expected two columns for definition list') + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write('%*s%s' % (self.current_indent, '', first)) + if not second: + self.write('\n') + continue + if term_len(first) <= first_col - col_spacing: + self.write(' ' * (first_col - term_len(first))) + else: + self.write('\n') + self.write(' ' * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + lines = iter(wrap_text(second, text_width).splitlines()) + if lines: + self.write(next(lines) + '\n') + for line in lines: + self.write('%*s%s\n' % ( + first_col + self.current_indent, '', line)) + else: + self.write('\n') + + @contextmanager + def section(self, name): + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self): + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self): + """Returns the buffer contents.""" + return ''.join(self.buffer) + + +def join_options(options): + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + for opt in options: + prefix = split_opt(opt)[0] + if prefix == '/': + any_prefix_is_slash = True + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + + rv = ', '.join(x[1] for x in rv) + return rv, any_prefix_is_slash diff --git a/pipenv/vendor/click/globals.py b/pipenv/vendor/click/globals.py new file mode 100644 index 00000000..14338e6b --- /dev/null +++ b/pipenv/vendor/click/globals.py @@ -0,0 +1,48 @@ +from threading import local + + +_local = local() + + +def get_current_context(silent=False): + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing it's behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: is set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return getattr(_local, 'stack')[-1] + except (AttributeError, IndexError): + if not silent: + raise RuntimeError('There is no active click context.') + + +def push_context(ctx): + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault('stack', []).append(ctx) + + +def pop_context(): + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color=None): + """"Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + ctx = get_current_context(silent=True) + if ctx is not None: + return ctx.color diff --git a/pipenv/vendor/click/parser.py b/pipenv/vendor/click/parser.py new file mode 100644 index 00000000..9775c9ff --- /dev/null +++ b/pipenv/vendor/click/parser.py @@ -0,0 +1,426 @@ +# -*- coding: utf-8 -*- +""" + click.parser + ~~~~~~~~~~~~ + + This module started out as largely a copy paste from the stdlib's + optparse module with the features removed that we do not need from + optparse because we implement them in Click on a higher level (for + instance type handling, help formatting and a lot more). + + The plan is to remove more and more from here over time. + + The reason this is a different module and not optparse from the stdlib + is that there are differences in 2.x and 3.x about the error messages + generated and optparse in the stdlib uses gettext for no good reason + and might cause us issues. +""" +import re +from collections import deque +from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \ + BadArgumentUsage + + +def _unpack_args(args, nargs_spec): + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv = [] + spos = None + + def _fetch(c): + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError('Cannot have two nargs < 0') + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1:] = reversed(rv[spos + 1:]) + + return tuple(rv), list(args) + + +def _error_opt_args(nargs, opt): + if nargs == 1: + raise BadOptionUsage('%s option requires an argument' % opt) + raise BadOptionUsage('%s option requires %d arguments' % (opt, nargs)) + + +def split_opt(opt): + first = opt[:1] + if first.isalnum(): + return '', opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt, ctx): + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return prefix + ctx.token_normalize_func(opt) + + +def split_arg_string(string): + """Given an argument string this attempts to split it into small parts.""" + rv = [] + for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'" + r'|"([^"\\]*(?:\\.[^"\\]*)*)"' + r'|\S+)\s*', string, re.S): + arg = match.group().strip() + if arg[:1] == arg[-1:] and arg[:1] in '"\'': + arg = arg[1:-1].encode('ascii', 'backslashreplace') \ + .decode('unicode-escape') + try: + arg = type(string)(arg) + except UnicodeError: + pass + rv.append(arg) + return rv + + +class Option(object): + + def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError('Invalid start character for option (%s)' + % opt) + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = 'store' + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self): + return self.action in ('store', 'append') + + def process(self, value, state): + if self.action == 'store': + state.opts[self.dest] = value + elif self.action == 'store_const': + state.opts[self.dest] = self.const + elif self.action == 'append': + state.opts.setdefault(self.dest, []).append(value) + elif self.action == 'append_const': + state.opts.setdefault(self.dest, []).append(self.const) + elif self.action == 'count': + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 + else: + raise ValueError('unknown action %r' % self.action) + state.order.append(self.obj) + + +class Argument(object): + + def __init__(self, dest, nargs=1, obj=None): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process(self, value, state): + if self.nargs > 1: + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage('argument %s takes %d values' + % (self.dest, self.nargs)) + state.opts[self.dest] = value + state.order.append(self.obj) + + +class ParsingState(object): + + def __init__(self, rargs): + self.opts = {} + self.largs = [] + self.rargs = rargs + self.order = [] + + +class OptionParser(object): + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx=None): + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + self._short_opt = {} + self._long_opt = {} + self._opt_prefixes = set(['-', '--']) + self._args = [] + + def add_option(self, opts, dest, action=None, nargs=1, const=None, + obj=None): + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``appnd_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(opts, dest, action=action, nargs=nargs, + const=const, obj=obj) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, dest, nargs=1, obj=None): + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) + + def parse_args(self, args): + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state): + pargs, args = _unpack_args(state.largs + state.rargs, + [x.nargs for x in self._args]) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state): + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == '--': + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt(self, opt, explicit_value, state): + if opt not in self._long_opt: + possibilities = [word for word in self._long_opt + if word.startswith(opt)] + raise NoSuchOption(opt, possibilities=possibilities) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + elif explicit_value is not None: + raise BadOptionUsage('%s option does not take a value' % opt) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg, state): + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(prefix + ch, self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(prefix + ''.join(unknown_options)) + + def _process_opts(self, arg, state): + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if '=' in arg: + long_opt, explicit_value = arg.split('=', 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + return self._match_short_opt(arg, state) + if not self.ignore_unknown_options: + raise + state.largs.append(arg) diff --git a/pipenv/vendor/click/termui.py b/pipenv/vendor/click/termui.py new file mode 100644 index 00000000..d9fba523 --- /dev/null +++ b/pipenv/vendor/click/termui.py @@ -0,0 +1,539 @@ +import os +import sys +import struct + +from ._compat import raw_input, text_type, string_types, \ + isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN +from .utils import echo +from .exceptions import Abort, UsageError +from .types import convert_type +from .globals import resolve_color_default + + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func = raw_input + +_ansi_colors = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', + 'cyan', 'white', 'reset') +_ansi_reset_all = '\033[0m' + + +def hidden_prompt_func(prompt): + import getpass + return getpass.getpass(prompt) + + +def _build_prompt(text, suffix, show_default=False, default=None): + prompt = text + if default is not None and show_default: + prompt = '%s [%s]' % (prompt, default) + return prompt + suffix + + +def prompt(text, default=None, hide_input=False, + confirmation_prompt=False, type=None, + value_proc=None, prompt_suffix=': ', + show_default=True, err=False): + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending a interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: asks for confirmation for the value. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + result = None + + def prompt_func(text): + f = hide_input and hidden_prompt_func or visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text, nl=False, err=err) + return f('') + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt(text, prompt_suffix, show_default, default) + + while 1: + while 1: + value = prompt_func(prompt) + if value: + break + # If a default is set and used, then the confirmation + # prompt is always skipped because that's the only thing + # that really makes sense. + elif default is not None: + return default + try: + result = value_proc(value) + except UsageError as e: + echo('Error: %s' % e.message, err=err) + continue + if not confirmation_prompt: + return result + while 1: + value2 = prompt_func('Repeat for confirmation: ') + if value2: + break + if value == value2: + return result + echo('Error: the two entered values do not match', err=err) + + +def confirm(text, default=False, abort=False, prompt_suffix=': ', + show_default=True, err=False): + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the question to ask. + :param default: the default for the prompt. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + prompt = _build_prompt(text, prompt_suffix, show_default, + default and 'Y/n' or 'y/N') + while 1: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt, nl=False, err=err) + value = visible_prompt_func('').lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() + if value in ('y', 'yes'): + rv = True + elif value in ('n', 'no'): + rv = False + elif value == '': + rv = default + else: + echo('Error: invalid input', err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def get_terminal_size(): + """Returns the current size of the terminal as tuple in the form + ``(width, height)`` in columns and rows. + """ + # If shutil has get_terminal_size() (Python 3.3 and later) use that + if sys.version_info >= (3, 3): + import shutil + shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None) + if shutil_get_terminal_size: + sz = shutil_get_terminal_size() + return sz.columns, sz.lines + + if get_winterm_size is not None: + return get_winterm_size() + + def ioctl_gwinsz(fd): + try: + import fcntl + import termios + cr = struct.unpack( + 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) + except Exception: + return + return cr + + cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + try: + cr = ioctl_gwinsz(fd) + finally: + os.close(fd) + except Exception: + pass + if not cr or not cr[0] or not cr[1]: + cr = (os.environ.get('LINES', 25), + os.environ.get('COLUMNS', DEFAULT_COLUMNS)) + return int(cr[1]), int(cr[0]) + + +def echo_via_pager(text, color=None): + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text: the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + if not isinstance(text, string_types): + text = text_type(text) + from ._termui_impl import pager + return pager(text + '\n', color) + + +def progressbar(iterable=None, length=None, label=None, show_eta=True, + show_percent=None, show_pos=False, + item_show_func=None, fill_char='#', empty_char='-', + bar_template='%(label)s [%(bar)s] %(info)s', + info_sep=' ', width=36, file=None, color=None): + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already displayed. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `color` parameter. Added a `update` method to the + progressbar object. + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: a function called with the current item which + can return a string to show the current item + next to the progress bar. Note that the current + item can be `None`! + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: the file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + """ + from ._termui_impl import ProgressBar + color = resolve_color_default(color) + return ProgressBar(iterable=iterable, length=length, show_eta=show_eta, + show_percent=show_percent, show_pos=show_pos, + item_show_func=item_show_func, fill_char=fill_char, + empty_char=empty_char, bar_template=bar_template, + info_sep=info_sep, file=file, label=label, + width=width, color=color) + + +def clear(): + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + # If we're on Windows and we don't have colorama available, then we + # clear the screen by shelling out. Otherwise we can use an escape + # sequence. + if WIN: + os.system('cls') + else: + sys.stdout.write('\033[2J\033[1;1H') + + +def style(text, fg=None, bg=None, bold=None, dim=None, underline=None, + blink=None, reverse=None, reset=True): + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``reset`` (reset the color code only) + + .. versionadded:: 2.0 + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + """ + bits = [] + if fg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(fg) + 30)) + except ValueError: + raise TypeError('Unknown color %r' % fg) + if bg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(bg) + 40)) + except ValueError: + raise TypeError('Unknown color %r' % bg) + if bold is not None: + bits.append('\033[%dm' % (1 if bold else 22)) + if dim is not None: + bits.append('\033[%dm' % (2 if dim else 22)) + if underline is not None: + bits.append('\033[%dm' % (4 if underline else 24)) + if blink is not None: + bits.append('\033[%dm' % (5 if blink else 25)) + if reverse is not None: + bits.append('\033[%dm' % (7 if reverse else 27)) + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return ''.join(bits) + + +def unstyle(text): + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho(text, file=None, nl=True, err=False, color=None, **styles): + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + .. versionadded:: 2.0 + """ + return echo(style(text, **styles), file=file, nl=nl, err=err, color=color) + + +def edit(text=None, editor=None, env=None, require_save=True, + extension='.txt', filename=None): + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + editor = Editor(editor=editor, env=env, require_save=require_save, + extension=extension) + if filename is None: + return editor.edit(text) + editor.edit_file(filename) + + +def launch(url, wait=False, locate=False): + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('http://click.pocoo.org/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: waits for the program to stop. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar = None + + +def getchar(echo=False): + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + f = _getchar + if f is None: + from ._termui_impl import getchar as f + return f(echo) + + +def pause(info='Press any key to continue ...', err=False): + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: the info string to print before pausing. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/pipenv/vendor/click/testing.py b/pipenv/vendor/click/testing.py new file mode 100644 index 00000000..4416c774 --- /dev/null +++ b/pipenv/vendor/click/testing.py @@ -0,0 +1,322 @@ +import os +import sys +import shutil +import tempfile +import contextlib + +from ._compat import iteritems, PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +clickpkg = sys.modules[__name__.rsplit('.', 1)[0]] + + +if PY2: + from cStringIO import StringIO +else: + import io + from ._compat import _find_binary_reader + + +class EchoingStdin(object): + + def __init__(self, input, output): + self._input = input + self._output = output + + def __getattr__(self, x): + return getattr(self._input, x) + + def _echo(self, rv): + self._output.write(rv) + return rv + + def read(self, n=-1): + return self._echo(self._input.read(n)) + + def readline(self, n=-1): + return self._echo(self._input.readline(n)) + + def readlines(self): + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self): + return iter(self._echo(x) for x in self._input) + + def __repr__(self): + return repr(self._input) + + +def make_input_stream(input, charset): + # Is already an input stream. + if hasattr(input, 'read'): + if PY2: + return input + rv = _find_binary_reader(input) + if rv is not None: + return rv + raise TypeError('Could not find binary reader for input stream.') + + if input is None: + input = b'' + elif not isinstance(input, bytes): + input = input.encode(charset) + if PY2: + return StringIO(input) + return io.BytesIO(input) + + +class Result(object): + """Holds the captured result of an invoked CLI script.""" + + def __init__(self, runner, output_bytes, exit_code, exception, + exc_info=None): + #: The runner that created the result + self.runner = runner + #: The output as bytes. + self.output_bytes = output_bytes + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happend if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self): + """The output as unicode string.""" + return self.output_bytes.decode(self.runner.charset, 'replace') \ + .replace('\r\n', '\n') + + def __repr__(self): + return '' % ( + self.exception and repr(self.exception) or 'okay', + ) + + +class CliRunner(object): + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. This is + UTF-8 by default and should not be changed currently as + the reporting to Click only works in Python 2 properly. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + """ + + def __init__(self, charset=None, env=None, echo_stdin=False): + if charset is None: + charset = 'utf-8' + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + + def get_default_prog_name(self, cli): + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or 'root' + + def make_env(self, overrides=None): + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation(self, input=None, env=None, color=False): + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + input = make_input_stream(input, self.charset) + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = clickpkg.formatting.FORCED_WIDTH + clickpkg.formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + if PY2: + sys.stdout = sys.stderr = bytes_output = StringIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + else: + bytes_output = io.BytesIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + input = io.TextIOWrapper(input, encoding=self.charset) + sys.stdout = sys.stderr = io.TextIOWrapper( + bytes_output, encoding=self.charset) + + sys.stdin = input + + def visible_input(prompt=None): + sys.stdout.write(prompt or '') + val = input.readline().rstrip('\r\n') + sys.stdout.write(val + '\n') + sys.stdout.flush() + return val + + def hidden_input(prompt=None): + sys.stdout.write((prompt or '') + '\n') + sys.stdout.flush() + return input.readline().rstrip('\r\n') + + def _getchar(echo): + char = sys.stdin.read(1) + if echo: + sys.stdout.write(char) + sys.stdout.flush() + return char + + default_color = color + def should_strip_ansi(stream=None, color=None): + if color is None: + return not default_color + return not color + + old_visible_prompt_func = clickpkg.termui.visible_prompt_func + old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func + old__getchar_func = clickpkg.termui._getchar + old_should_strip_ansi = clickpkg.utils.should_strip_ansi + clickpkg.termui.visible_prompt_func = visible_input + clickpkg.termui.hidden_prompt_func = hidden_input + clickpkg.termui._getchar = _getchar + clickpkg.utils.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in iteritems(env): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield bytes_output + finally: + for key, value in iteritems(old_env): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + clickpkg.termui.visible_prompt_func = old_visible_prompt_func + clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func + clickpkg.termui._getchar = old__getchar_func + clickpkg.utils.should_strip_ansi = old_should_strip_ansi + clickpkg.formatting.FORCED_WIDTH = old_forced_width + + def invoke(self, cli, args=None, input=None, env=None, + catch_exceptions=True, color=False, **extra): + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + .. versionadded:: 3.0 + The ``catch_exceptions`` parameter was added. + + .. versionchanged:: 3.0 + The result object now has an `exc_info` attribute with the + traceback if available. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param cli: the command to invoke + :param args: the arguments to invoke + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as out: + exception = None + exit_code = 0 + + try: + cli.main(args=args or (), + prog_name=self.get_default_prog_name(cli), **extra) + except SystemExit as e: + if e.code != 0: + exception = e + + exc_info = sys.exc_info() + + exit_code = e.code + if not isinstance(exit_code, int): + sys.stdout.write(str(exit_code)) + sys.stdout.write('\n') + exit_code = 1 + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = -1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + output = out.getvalue() + + return Result(runner=self, + output_bytes=output, + exit_code=exit_code, + exception=exception, + exc_info=exc_info) + + @contextlib.contextmanager + def isolated_filesystem(self): + """A context manager that creates a temporary folder and changes + the current working directory to it for isolated filesystem tests. + """ + cwd = os.getcwd() + t = tempfile.mkdtemp() + os.chdir(t) + try: + yield t + finally: + os.chdir(cwd) + try: + shutil.rmtree(t) + except (OSError, IOError): + pass diff --git a/pipenv/vendor/click/types.py b/pipenv/vendor/click/types.py new file mode 100644 index 00000000..36390026 --- /dev/null +++ b/pipenv/vendor/click/types.py @@ -0,0 +1,550 @@ +import os +import stat + +from ._compat import open_stream, text_type, filename_to_ui, \ + get_filesystem_encoding, get_streerror, _get_argv_encoding, PY2 +from .exceptions import BadParameter +from .utils import safecall, LazyFile + + +class ParamType(object): + """Helper for converting values through types. The following is + necessary for a valid type: + + * it needs a name + * it needs to pass through None unchanged + * it needs to convert from a string + * it needs to convert its result type through unchanged + (eg: needs to be idempotent) + * it needs to be able to deal with param and context being `None`. + This can be the case when the object is used with prompt + inputs. + """ + is_composite = False + + #: the descriptive name of this type + name = None + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter = None + + def __call__(self, value, param=None, ctx=None): + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param): + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param): + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert(self, value, param, ctx): + """Converts the value. This is not invoked for values that are + `None` (the missing value). + """ + return value + + def split_envvar_value(self, rv): + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or '').split(self.envvar_list_splitter) + + def fail(self, message, param=None, ctx=None): + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self): + raise NotImplementedError() + + +class FuncParamType(ParamType): + + def __init__(self, func): + self.name = func.__name__ + self.func = func + + def convert(self, value, param, ctx): + try: + return self.func(value) + except ValueError: + try: + value = text_type(value) + except UnicodeError: + value = str(value).decode('utf-8', 'replace') + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + return value + + def __repr__(self): + return 'UNPROCESSED' + + +class StringParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode('utf-8', 'replace') + return value + return value + + def __repr__(self): + return 'STRING' + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set of + supported values. All of these values have to be strings. + + See :ref:`choice-opts` for an example. + """ + name = 'choice' + + def __init__(self, choices): + self.choices = choices + + def get_metavar(self, param): + return '[%s]' % '|'.join(self.choices) + + def get_missing_message(self, param): + return 'Choose from %s.' % ', '.join(self.choices) + + def convert(self, value, param, ctx): + # Exact match + if value in self.choices: + return value + + # Match through normalization + if ctx is not None and \ + ctx.token_normalize_func is not None: + value = ctx.token_normalize_func(value) + for choice in self.choices: + if ctx.token_normalize_func(choice) == value: + return choice + + self.fail('invalid choice: %s. (choose from %s)' % + (value, ', '.join(self.choices)), param, ctx) + + def __repr__(self): + return 'Choice(%r)' % list(self.choices) + + +class IntParamType(ParamType): + name = 'integer' + + def convert(self, value, param, ctx): + try: + return int(value) + except (ValueError, UnicodeError): + self.fail('%s is not a valid integer' % value, param, ctx) + + def __repr__(self): + return 'INT' + + +class IntRange(IntParamType): + """A parameter that works similar to :data:`click.INT` but restricts + the value to fit into a range. The default behavior is to fail if the + value falls outside the range, but it can also be silently clamped + between the two edges. + + See :ref:`ranges` for an example. + """ + name = 'integer range' + + def __init__(self, min=None, max=None, clamp=False): + self.min = min + self.max = max + self.clamp = clamp + + def convert(self, value, param, ctx): + rv = IntParamType.convert(self, value, param, ctx) + if self.clamp: + if self.min is not None and rv < self.min: + return self.min + if self.max is not None and rv > self.max: + return self.max + if self.min is not None and rv < self.min or \ + self.max is not None and rv > self.max: + if self.min is None: + self.fail('%s is bigger than the maximum valid value ' + '%s.' % (rv, self.max), param, ctx) + elif self.max is None: + self.fail('%s is smaller than the minimum valid value ' + '%s.' % (rv, self.min), param, ctx) + else: + self.fail('%s is not in the valid range of %s to %s.' + % (rv, self.min, self.max), param, ctx) + return rv + + def __repr__(self): + return 'IntRange(%r, %r)' % (self.min, self.max) + + +class BoolParamType(ParamType): + name = 'boolean' + + def convert(self, value, param, ctx): + if isinstance(value, bool): + return bool(value) + value = value.lower() + if value in ('true', '1', 'yes', 'y'): + return True + elif value in ('false', '0', 'no', 'n'): + return False + self.fail('%s is not a valid boolean' % value, param, ctx) + + def __repr__(self): + return 'BOOL' + + +class FloatParamType(ParamType): + name = 'float' + + def convert(self, value, param, ctx): + try: + return float(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid floating point value' % + value, param, ctx) + + def __repr__(self): + return 'FLOAT' + + +class UUIDParameterType(ParamType): + name = 'uuid' + + def convert(self, value, param, ctx): + import uuid + try: + if PY2 and isinstance(value, text_type): + value = value.encode('ascii') + return uuid.UUID(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid UUID value' % value, param, ctx) + + def __repr__(self): + return 'UUID' + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or + upon first IO. The default is to be non lazy for standard input and + output streams as well as files opened for reading, lazy otherwise. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + name = 'filename' + envvar_list_splitter = os.path.pathsep + + def __init__(self, mode='r', encoding=None, errors='strict', lazy=None, + atomic=False): + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def resolve_lazy_flag(self, value): + if self.lazy is not None: + return self.lazy + if value == '-': + return False + elif 'w' in self.mode: + return True + return False + + def convert(self, value, param, ctx): + try: + if hasattr(value, 'read') or hasattr(value, 'write'): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f = LazyFile(value, self.mode, self.encoding, self.errors, + atomic=self.atomic) + if ctx is not None: + ctx.call_on_close(f.close_intelligently) + return f + + f, should_close = open_stream(value, self.mode, + self.encoding, self.errors, + atomic=self.atomic) + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + return f + except (IOError, OSError) as e: + self.fail('Could not open file: %s: %s' % ( + filename_to_ui(value), + get_streerror(e), + ), param, ctx) + + +class Path(ParamType): + """The path type is similar to the :class:`File` type but it performs + different checks. First of all, instead of returning an open file + handle it returns just the filename. Secondly, it can perform various + basic checks about what the file or directory should be. + + .. versionchanged:: 6.0 + `allow_dash` was added. + + :param exists: if set to true, the file or directory needs to exist for + this value to be valid. If this is not required and a + file does indeed not exist, then all further checks are + silently skipped. + :param file_okay: controls if a file is a possible value. + :param dir_okay: controls if a directory is a possible value. + :param writable: if true, a writable check is performed. + :param readable: if true, a readable check is performed. + :param resolve_path: if this is true, then the path is fully resolved + before the value is passed onwards. This means + that it's absolute and symlinks are resolved. + :param allow_dash: If this is set to `True`, a single dash to indicate + standard streams is permitted. + :param type: optionally a string type that should be used to + represent the path. The default is `None` which + means the return value will be either bytes or + unicode depending on what makes most sense given the + input data Click deals with. + """ + envvar_list_splitter = os.path.pathsep + + def __init__(self, exists=False, file_okay=True, dir_okay=True, + writable=False, readable=True, resolve_path=False, + allow_dash=False, path_type=None): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.writable = writable + self.readable = readable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = 'file' + self.path_type = 'File' + if self.dir_okay and not self.file_okay: + self.name = 'directory' + self.path_type = 'Directory' + else: + self.name = 'path' + self.path_type = 'Path' + + def coerce_path_result(self, rv): + if self.type is not None and not isinstance(rv, self.type): + if self.type is text_type: + rv = rv.decode(get_filesystem_encoding()) + else: + rv = rv.encode(get_filesystem_encoding()) + return rv + + def convert(self, value, param, ctx): + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b'-', '-') + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail('%s "%s" does not exist.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail('%s "%s" is a file.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail('%s "%s" is a directory.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.writable and not os.access(value, os.W_OK): + self.fail('%s "%s" is not writable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.readable and not os.access(value, os.R_OK): + self.fail('%s "%s" is not readable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + return self.coerce_path_result(rv) + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types): + self.types = [convert_type(ty) for ty in types] + + @property + def name(self): + return "<" + " ".join(ty.name for ty in self.types) + ">" + + @property + def arity(self): + return len(self.types) + + def convert(self, value, param, ctx): + if len(value) != len(self.types): + raise TypeError('It would appear that nargs is set to conflict ' + 'with the composite type arity.') + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty, default=None): + """Converts a callable or python ty into the most appropriate param + ty. + """ + guessed_type = False + if ty is None and default is not None: + if isinstance(default, tuple): + ty = tuple(map(type, default)) + else: + ty = type(default) + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + if isinstance(ty, ParamType): + return ty + if ty is text_type or ty is str or ty is None: + return STRING + if ty is int: + return INT + # Booleans are only okay if not guessed. This is done because for + # flags the default value is actually a bit of a lie in that it + # indicates which of the flags is the one we want. See get_default() + # for more information. + if ty is bool and not guessed_type: + return BOOL + if ty is float: + return FLOAT + if guessed_type: + return STRING + + # Catch a common mistake + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError('Attempted to use an uninstantiated ' + 'parameter type (%s).' % ty) + except TypeError: + pass + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but internally +#: no string conversion takes place. This is necessary to achieve the +#: same bytes/unicode behavior on Python 2/3 in situations where you want +#: to not convert argument types. This is usually useful when working +#: with file paths as they can appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/pipenv/vendor/click/utils.py b/pipenv/vendor/click/utils.py new file mode 100644 index 00000000..eee626d3 --- /dev/null +++ b/pipenv/vendor/click/utils.py @@ -0,0 +1,415 @@ +import os +import sys + +from .globals import resolve_color_default + +from ._compat import text_type, open_stream, get_filesystem_encoding, \ + get_streerror, string_types, PY2, binary_streams, text_streams, \ + filename_to_ui, auto_wrap_for_ansi, strip_ansi, should_strip_ansi, \ + _default_text_stdout, _default_text_stderr, is_bytes, WIN + +if not PY2: + from ._compat import _find_binary_writer +elif WIN: + from ._winconsole import _get_windows_argv, \ + _hash_py_argv, _initial_argv_hash + + +echo_native_types = string_types + (bytes, bytearray) + + +def _posixify(name): + return '-'.join(name.split()).lower() + + +def safecall(func): + """Wraps a function so that it swallows exceptions.""" + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception: + pass + return wrapper + + +def make_str(value): + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode('utf-8', 'replace') + return text_type(value) + + +def make_default_short_help(help, max_length=45): + words = help.split() + total_length = 0 + result = [] + done = False + + for word in words: + if word[-1:] == '.': + done = True + new_length = result and 1 + len(word) or len(word) + if total_length + new_length > max_length: + result.append('...') + done = True + else: + if result: + result.append(' ') + result.append(word) + if done: + break + total_length += new_length + + return ''.join(result) + + +class LazyFile(object): + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__(self, filename, mode='r', encoding=None, errors='strict', + atomic=False): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + + if filename == '-': + self._f, self.should_close = open_stream(filename, mode, + encoding, errors) + else: + if 'r' in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name): + return getattr(self.open(), name) + + def __repr__(self): + if self._f is not None: + return repr(self._f) + return '' % (self.name, self.mode) + + def open(self): + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream(self.name, self.mode, + self.encoding, + self.errors, + atomic=self.atomic) + except (IOError, OSError) as e: + from .exceptions import FileError + raise FileError(self.name, hint=get_streerror(e)) + self._f = rv + return rv + + def close(self): + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self): + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close_intelligently() + + def __iter__(self): + self.open() + return iter(self._f) + + +class KeepOpenFile(object): + + def __init__(self, file): + self._file = file + + def __getattr__(self, name): + return getattr(self._file, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + pass + + def __repr__(self): + return repr(self._file) + + def __iter__(self): + return iter(self._file) + + +def echo(message=None, file=None, nl=True, err=False, color=None): + """Prints a message plus a newline to the given file or stdout. On + first sight, this looks like the print function, but it has improved + support for handling Unicode and binary data that does not fail no + matter how badly configured the system is. + + Primarily it means that you can print binary data as well as Unicode + data on both 2.x and 3.x to the given file in the most appropriate way + possible. This is a very carefree function as in that it will try its + best to not fail. As of Click 6.0 this includes support for unicode + output on the Windows console. + + In addition to that, if `colorama`_ is installed, the echo function will + also support clever handling of ANSI codes. Essentially it will then + do the following: + + - add transparent handling of ANSI color codes on Windows. + - hide ANSI codes automatically if the destination file is not a + terminal. + + .. _colorama: http://pypi.python.org/pypi/colorama + + .. versionchanged:: 6.0 + As of Click 6.0 the echo function will properly support unicode + output on the windows console. Not that click does not modify + the interpreter in any way which means that `sys.stdout` or the + print statement or function will still not provide unicode support. + + .. versionchanged:: 2.0 + Starting with version 2.0 of Click, the echo function will work + with colorama if it's installed. + + .. versionadded:: 3.0 + The `err` parameter was added. + + .. versionchanged:: 4.0 + Added the `color` flag. + + :param message: the message to print + :param file: the file to write to (defaults to ``stdout``) + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``. This is faster and easier than calling + :func:`get_text_stderr` yourself. + :param nl: if set to `True` (the default) a newline is printed afterwards. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, echo_native_types): + message = text_type(message) + + if nl: + message = message or u'' + if isinstance(message, text_type): + message += u'\n' + else: + message += b'\n' + + # If there is a message, and we're in Python 3, and the value looks + # like bytes, we manually need to find the binary stream and write the + # message in there. This is done separately so that most stream + # types will work as you would expect. Eg: you can write to StringIO + # for other cases. + if message and not PY2 and is_bytes(message): + binary_file = _find_binary_writer(file) + if binary_file is not None: + file.flush() + binary_file.write(message) + binary_file.flush() + return + + # ANSI-style support. If there is no message or we are dealing with + # bytes nothing is happening. If we are connected to a file we want + # to strip colors. If we are on windows we either wrap the stream + # to strip the color or we use the colorama support to translate the + # ansi codes to API calls. + if message and not is_bytes(message): + color = resolve_color_default(color) + if should_strip_ansi(file, color): + message = strip_ansi(message) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) + elif not color: + message = strip_ansi(message) + + if message: + file.write(message) + file.flush() + + +def get_binary_stream(name): + """Returns a system stream for byte processing. This essentially + returns the stream from the sys module with the given name but it + solves some compatibility issues between different Python versions. + Primarily this function is necessary for getting binary streams on + Python 3. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener() + + +def get_text_stream(name, encoding=None, errors='strict'): + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts on Python 3 + for already correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener(encoding, errors) + + +def open_file(filename, mode='r', encoding=None, errors='strict', + lazy=False, atomic=False): + """This is similar to how the :class:`File` works but for manual + usage. Files are opened non lazy by default. This can open regular + files as well as stdin/stdout if ``'-'`` is passed. + + If stdin/stdout is returned the stream is wrapped so that the context + manager will not close the stream accidentally. This makes it possible + to always use the function like this without having to worry to + accidentally close a standard stream:: + + with open_file(filename) as f: + ... + + .. versionadded:: 3.0 + + :param filename: the name of the file to open (or ``'-'`` for stdin/stdout). + :param mode: the mode in which to open the file. + :param encoding: the encoding to use. + :param errors: the error handling for this file. + :param lazy: can be flipped to true to open the file lazily. + :param atomic: in atomic mode writes go into a temporary file and it's + moved on close. + """ + if lazy: + return LazyFile(filename, mode, encoding, errors, atomic=atomic) + f, should_close = open_stream(filename, mode, encoding, errors, + atomic=atomic) + if not should_close: + f = KeepOpenFile(f) + return f + + +def get_os_args(): + """This returns the argument part of sys.argv in the most appropriate + form for processing. What this means is that this return value is in + a format that works for Click to process but does not necessarily + correspond well to what's actually standard for the interpreter. + + On most environments the return value is ``sys.argv[:1]`` unchanged. + However if you are on Windows and running Python 2 the return value + will actually be a list of unicode strings instead because the + default behavior on that platform otherwise will not be able to + carry all possible values that sys.argv can have. + + .. versionadded:: 6.0 + """ + # We can only extract the unicode argv if sys.argv has not been + # changed since the startup of the application. + if PY2 and WIN and _initial_argv_hash == _hash_py_argv(): + return _get_windows_argv() + return sys.argv[1:] + + +def format_filename(filename, shorten=False): + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + return filename_to_ui(filename) + + +def get_app_dir(app_name, roaming=True, force_posix=False): + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Win XP (roaming): + ``C:\Documents and Settings\\Local Settings\Application Data\Foo Bar`` + Win XP (not roaming): + ``C:\Documents and Settings\\Application Data\Foo Bar`` + Win 7 (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Win 7 (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = roaming and 'APPDATA' or 'LOCALAPPDATA' + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser('~') + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser('~/.' + _posixify(app_name))) + if sys.platform == 'darwin': + return os.path.join(os.path.expanduser( + '~/Library/Application Support'), app_name) + return os.path.join( + os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), + _posixify(app_name)) diff --git a/pipenv/vendor/click_completion.py b/pipenv/vendor/click_completion.py new file mode 100644 index 00000000..c55d05ec --- /dev/null +++ b/pipenv/vendor/click_completion.py @@ -0,0 +1,470 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +from __future__ import print_function, absolute_import + +import os +import platform +import re +import sys +import shlex +import subprocess + +import click +import six + +from click import echo, MultiCommand, Option, Argument, ParamType + +__version__ = '0.2.1' + + +FISH_TEMPLATE = 'complete --command {{prog_name}} --arguments "(env {{complete_var}}=complete-fish COMMANDLINE=(commandline -cp){% for k, v in extra_env.items() %} {{k}}={{v}}{% endfor %} {{prog_name}})" -f' + +ZSH_TEMPLATE = ''' +#compdef {{prog_name}} +_{{prog_name}}() { + eval $(env COMMANDLINE="${words[1,$CURRENT]}" {{complete_var}}=complete-zsh {% for k, v in extra_env.items() %} {{k}}={{v}}{% endfor %} {{prog_name}}) +} +if [[ "$(basename ${(%):-%x})" != "_{{prog_name}}" ]]; then + autoload -U compinit && compinit + compdef _{{prog_name}} {{prog_name}} +fi +''' + +POWERSHELL_COMPLETION_SCRIPT = ''' +if ((Test-Path Function:\TabExpansion) -and -not (Test-Path Function:\{{prog_name}}TabExpansionBackup)) { + Rename-Item Function:\TabExpansion {{prog_name}}TabExpansionBackup +} + +function TabExpansion($line, $lastWord) { + $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart() + $aliases = @("{{prog_name}}") + @(Get-Alias | where { $_.Definition -eq "{{prog_name}}" } | select -Exp Name) + $aliasPattern = "($($aliases -join '|'))" + if($lastBlock -match "^$aliasPattern ") { + $Env:{{complete_var}} = "complete-powershell" + $Env:COMMANDLINE = "$lastBlock" +{%- for k, v in extra_env.items() %} + $Env:{{k}} = "{{v}}" +{%- endfor %} + ({{prog_name}}) | ? {$_.trim() -ne "" } + Remove-Item Env:{{complete_var}} + Remove-Item Env:COMMANDLINE +{%- for k in extra_env.keys() %} + Remove-Item $Env:{{k}} +{%- endfor %} + } + elseif (Test-Path Function:\{{prog_name}}TabExpansionBackup) { + # Fall back on existing tab expansion + {{prog_name}}TabExpansionBackup $line $lastWord + } +} +''' + +BASH_COMPLETION_SCRIPT = ''' +_{{prog_name}}_completion() { + local IFS=$'\\t' + COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ +{%- for k, v in extra_env.items() %} + {{k}}={{v}} \\ +{%- endfor %} + {{complete_var}}=complete-bash $1 ) ) + return 0 +} + +complete -F _{{prog_name}}_completion -o default {{prog_name}} +''' + +_invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]') + + +def resolve_ctx(cli, prog_name, args): + ctx = cli.make_context(prog_name, list(args), resilient_parsing=True) + while ctx.args + ctx.protected_args and isinstance(ctx.command, MultiCommand): + a = ctx.protected_args + ctx.args + cmd = ctx.command.get_command(ctx, a[0]) + if cmd is None: + return None + ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True) + return ctx + + +def startswith(string, incomplete): + """Returns True when string starts with incomplete + + It might be overridden with a fuzzier version - for example a case insensitive version""" + return string.startswith(incomplete) + + +def get_choices(cli, prog_name, args, incomplete): + ctx = resolve_ctx(cli, prog_name, args) + if ctx is None: + return + + optctx = None + if args: + for param in ctx.command.get_params(ctx): + if isinstance(param, Option) and not param.is_flag and args[-1] in param.opts + param.secondary_opts: + optctx = param + + choices = [] + if optctx: + choices += [c if isinstance(c, tuple) else (c, None) for c in optctx.type.complete(ctx, incomplete)] + elif incomplete and not incomplete[:1].isalnum(): + for param in ctx.command.get_params(ctx): + if not isinstance(param, Option): + continue + for opt in param.opts: + if startswith(opt, incomplete): + choices.append((opt, param.help)) + for opt in param.secondary_opts: + if startswith(opt, incomplete): + # don't put the doc so fish won't group the primary and + # and secondary options + choices.append((opt, None)) + elif isinstance(ctx.command, MultiCommand): + for name in ctx.command.list_commands(ctx): + if startswith(name, incomplete): + choices.append((name, ctx.command.get_command_short_help(ctx, name))) + else: + for param in ctx.command.get_params(ctx): + if isinstance(param, Argument): + choices += [c if isinstance(c, tuple) else (c, None) for c in param.type.complete(ctx, incomplete)] + + for item, help in choices: + yield (item, help) + + +def split_args(line): + """Version of shlex.split that silently accept incomplete strings.""" + lex = shlex.shlex(line, posix=True) + lex.whitespace_split = True + lex.commenters = '' + res = [] + try: + while True: + res.append(next(lex)) + except ValueError: # No closing quotation + pass + except StopIteration: # End of loop + pass + if lex.token: + res.append(lex.token) + return res + + +def decode_args(strings): + res = [] + for s in strings: + s = split_args(s) + s = s[0] if s else '' + res.append(s) + return res + + +def do_bash_complete(cli, prog_name): + comp_words = os.environ['COMP_WORDS'] + try: + cwords = shlex.split(comp_words) + quoted = False + except ValueError: # No closing quotation + cwords = split_args(comp_words) + quoted = True + cword = int(os.environ['COMP_CWORD']) + args = cwords[1:cword] + try: + incomplete = cwords[cword] + except IndexError: + incomplete = '' + choices = get_choices(cli, prog_name, args, incomplete) + + if quoted: + echo('\t'.join(opt for opt, _ in choices), nl=False) + else: + echo('\t'.join(re.sub(r"""([\s\\"'])""", r'\\\1', opt) for opt, _ in choices), nl=False) + + return True + + +def do_fish_complete(cli, prog_name): + commandline = os.environ['COMMANDLINE'] + args = split_args(commandline)[1:] + if args and not commandline.endswith(' '): + incomplete = args[-1] + args = args[:-1] + else: + incomplete = '' + + for item, help in get_choices(cli, prog_name, args, incomplete): + if help: + echo("%s\t%s" % (item, help)) + else: + echo(item) + + return True + + +def do_zsh_complete(cli, prog_name): + commandline = os.environ['COMMANDLINE'] + args = split_args(commandline)[1:] + if args and not commandline.endswith(' '): + incomplete = args[-1] + args = args[:-1] + else: + incomplete = '' + + def escape(s): + return s.replace('"', '""').replace("'", "''").replace('$', '\\$') + res = [] + for item, help in get_choices(cli, prog_name, args, incomplete): + if help: + res.append('"%s"\:"%s"' % (escape(item), escape(help))) + else: + res.append('"%s"' % escape(item)) + echo("_arguments '*: :((%s))'" % '\n'.join(res)) + + return True + + +def do_powershell_complete(cli, prog_name): + commandline = os.environ['COMMANDLINE'] + args = split_args(commandline)[1:] + quote = single_quote + incomplete = '' + if args and not commandline.endswith(' '): + incomplete = args[-1] + args = args[:-1] + quote_pos = commandline.rfind(incomplete) - 1 + if quote_pos >= 0 and commandline[quote_pos] == '"': + quote = double_quote + + for item, help in get_choices(cli, prog_name, args, incomplete): + echo(quote(item)) + + return True + + +find_unsafe = re.compile(r'[^\w@%+=:,./-]').search + + +def single_quote(s): + """Return a shell-escaped version of the string *s*.""" + if not s: + return "''" + if find_unsafe(s) is None: + return s + + # use single quotes, and put single quotes into double quotes + # the string $'b is then quoted as '$'"'"'b' + return "'" + s.replace("'", "'\"'\"'") + "'" + + +def double_quote(s): + '''Return a shell-escaped version of the string *s*.''' + if not s: + return '""' + if find_unsafe(s) is None: + return s + + # use double quotes, and put double quotes into single quotes + # the string $"b is then quoted as "$"'"'"b" + return '"' + s.replace('"', '"\'"\'"') + '"' + + +# extend click completion features + +def param_type_complete(self, ctx, incomplete): + return [] + + +def choice_complete(self, ctx, incomplete): + return [c for c in self.choices if c.startswith(incomplete)] + + +def multicommand_get_command_short_help(self, ctx, cmd_name): + return self.get_command(ctx, cmd_name).short_help + + +def _shellcomplete(cli, prog_name, complete_var=None): + """Internal handler for the bash completion support.""" + if complete_var is None: + complete_var = '_%s_COMPLETE' % (prog_name.replace('-', '_')).upper() + complete_instr = os.environ.get(complete_var) + if not complete_instr: + return + + if complete_instr == 'source': + echo(get_code(prog_name=prog_name, env_name=complete_var)) + elif complete_instr == 'source-bash': + echo(get_code('bash', prog_name, complete_var)) + elif complete_instr == 'source-fish': + echo(get_code('fish', prog_name, complete_var)) + elif complete_instr == 'source-powershell': + echo(get_code('powershell', prog_name, complete_var)) + elif complete_instr == 'source-zsh': + echo(get_code('zsh', prog_name, complete_var)) + elif complete_instr in ['complete', 'complete-bash']: + # keep 'complete' for bash for backward compatibility + do_bash_complete(cli, prog_name) + elif complete_instr == 'complete-fish': + do_fish_complete(cli, prog_name) + elif complete_instr == 'complete-powershell': + do_powershell_complete(cli, prog_name) + elif complete_instr == 'complete-zsh': + do_zsh_complete(cli, prog_name) + elif complete_instr == 'install': + shell, path = install(prog_name=prog_name, env_name=complete_var) + click.echo('%s completion installed in %s' % (shell, path)) + elif complete_instr == 'install-bash': + shell, path = install(shell='bash', prog_name=prog_name, env_name=complete_var) + click.echo('%s completion installed in %s' % (shell, path)) + elif complete_instr == 'install-fish': + shell, path = install(shell='fish', prog_name=prog_name, env_name=complete_var) + click.echo('%s completion installed in %s' % (shell, path)) + elif complete_instr == 'install-zsh': + shell, path = install(shell='zsh', prog_name=prog_name, env_name=complete_var) + click.echo('%s completion installed in %s' % (shell, path)) + elif complete_instr == 'install-powershell': + shell, path = install(shell='powershell', prog_name=prog_name, env_name=complete_var) + click.echo('%s completion installed in %s' % (shell, path)) + sys.exit() + + +def init(): + """patch click to support enhanced completion""" + import click + click.types.ParamType.complete = param_type_complete + click.types.Choice.complete = choice_complete + click.core.MultiCommand.get_command_short_help = multicommand_get_command_short_help + click.core._bashcomplete = _shellcomplete + + +class DocumentedChoice(ParamType): + """The choice type allows a value to be checked against a fixed set of + supported values. All of these values have to be strings. Each value may + be associated to a help message that will be display in the error message + and during the completion. + """ + name = 'choice' + + def __init__(self, choices): + self.choices = dict(choices) + + def get_metavar(self, param): + return '[%s]' % '|'.join(self.choices.keys()) + + def get_missing_message(self, param): + formated_choices = ['{:<12} {}'.format(k, self.choices[k] or '') for k in sorted(self.choices.keys())] + return 'Choose from\n ' + '\n '.join(formated_choices) + + def convert(self, value, param, ctx): + # Exact match + if value in self.choices: + return value + + # Match through normalization + if ctx is not None and \ + ctx.token_normalize_func is not None: + value = ctx.token_normalize_func(value) + for choice in self.choices: + if ctx.token_normalize_func(choice) == value: + return choice + + self.fail('invalid choice: %s. %s' % + (value, self.get_missing_message(param)), param, ctx) + + def __repr__(self): + return 'DocumentedChoice(%r)' % list(self.choices.keys()) + + def complete(self, ctx, incomplete): + return [(c, v) for c, v in six.iteritems(self.choices) if startswith(c, incomplete)] + + +def get_code(shell=None, prog_name=None, env_name=None, extra_env=None): + """Return the specified completion code""" + from jinja2 import Template + if shell in [None, 'auto']: + shell = get_auto_shell() + prog_name = prog_name or click.get_current_context().find_root().info_name + env_name = env_name or '_%s_COMPLETE' % prog_name.upper().replace('-', '_') + extra_env = extra_env if extra_env else {} + if shell == 'fish': + return Template(FISH_TEMPLATE).render(prog_name=prog_name, complete_var=env_name, extra_env=extra_env) + elif shell == 'bash': + return Template(BASH_COMPLETION_SCRIPT).render(prog_name=prog_name, complete_var=env_name, extra_env=extra_env) + elif shell == 'zsh': + return Template(ZSH_TEMPLATE).render(prog_name=prog_name, complete_var=env_name, extra_env=extra_env) + elif shell == 'powershell': + return Template(POWERSHELL_COMPLETION_SCRIPT).render(prog_name=prog_name, complete_var=env_name, extra_env=extra_env) + else: + raise click.ClickException('%s is not supported.' % shell) + + + + + +def get_auto_shell(): + """Return the shell that is calling this process""" + try: + import psutil + parent = psutil.Process(os.getpid()).parent() + if platform.system() == 'Windows': + parent = parent.parent() or parent + return parent.name().replace('.exe', '') + except ImportError: + raise click.UsageError("Please explicitly give the shell type or install the psutil package to activate the" + " automatic shell detection.") + + +def install(shell=None, prog_name=None, env_name=None, path=None, append=None, extra_env=None): + """Install the completion""" + prog_name = prog_name or click.get_current_context().find_root().info_name + shell = shell or get_auto_shell() + if append is None and path is not None: + append = True + if append is not None: + mode = 'a' if append else 'w' + else: + mode = None + + if shell == 'fish': + path = path or os.path.expanduser('~') + '/.config/fish/completions/%s.fish' % prog_name + mode = mode or 'w' + elif shell == 'bash': + path = path or os.path.expanduser('~') + '/.bash_completion' + mode = mode or 'a' + elif shell == 'zsh': + ohmyzsh = os.path.expanduser('~') + '/.oh-my-zsh' + if os.path.exists(ohmyzsh): + path = path or ohmyzsh + '/completions/_%s' % prog_name + mode = mode or 'w' + else: + path = path or os.path.expanduser('~') + '/.zshrc' + mode = mode or 'a' + elif shell == 'powershell': + subprocess.check_call(['powershell', 'Set-ExecutionPolicy Unrestricted -Scope CurrentUser']) + path = path or subprocess.check_output(['powershell', '-NoProfile', 'echo $profile']).strip() if install else '' + mode = mode or 'a' + else: + raise click.ClickException('%s is not supported.' % shell) + + if append is not None: + mode = 'a' if append else 'w' + else: + mode = mode + d = os.path.dirname(path) + if not os.path.exists(d): + os.makedirs(d) + f = open(path, mode) + f.write(get_code(shell, prog_name, env_name, extra_env)) + f.write("\n") + f.close() + return shell, path + + +shells = { + 'bash': 'Bourne again shell', + 'fish': 'Friendly interactive shell', + 'zsh': 'Z shell', + 'powershell': 'Windows PowerShell' +} diff --git a/pipenv/vendor/colorama/__init__.py b/pipenv/vendor/colorama/__init__.py new file mode 100644 index 00000000..670e6b39 --- /dev/null +++ b/pipenv/vendor/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.3.7' + diff --git a/pipenv/vendor/colorama/ansi.py b/pipenv/vendor/colorama/ansi.py new file mode 100644 index 00000000..78776588 --- /dev/null +++ b/pipenv/vendor/colorama/ansi.py @@ -0,0 +1,102 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' + +CSI = '\033[' +OSC = '\033]' +BEL = '\007' + + +def code_to_chars(code): + return CSI + str(code) + 'm' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/pipenv/vendor/colorama/ansitowin32.py b/pipenv/vendor/colorama/ansitowin32.py new file mode 100644 index 00000000..b7ff6f21 --- /dev/null +++ b/pipenv/vendor/colorama/ansitowin32.py @@ -0,0 +1,236 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import re +import sys +import os + +from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style +from .winterm import WinTerm, WinColor, WinStyle +from .win32 import windll, winapi_test + + +winterm = None +if windll is not None: + winterm = WinTerm() + + +def is_stream_closed(stream): + return not hasattr(stream, 'closed') or stream.closed + + +def is_a_tty(stream): + return hasattr(stream, 'isatty') and stream.isatty() + + +class StreamWrapper(object): + ''' + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()', which is delegated to our + Converter instance. + ''' + def __init__(self, wrapped, converter): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + self.__convertor = converter + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def write(self, text): + self.__convertor.write(text) + + +class AnsiToWin32(object): + ''' + Implements a 'write()' method which, on Windows, will strip ANSI character + sequences from the text, and if outputting to a tty, will convert them into + win32 function calls. + ''' + ANSI_CSI_RE = re.compile('\001?\033\[((?:\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile('\001?\033\]((?:.|;)*?)(\x07)\002?') # Operating System Command + + def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + # The wrapped stream (normally sys.stdout or sys.stderr) + self.wrapped = wrapped + + # should we reset colors to defaults after every .write() + self.autoreset = autoreset + + # create the proxy wrapping our output stream + self.stream = StreamWrapper(wrapped, self) + + on_windows = os.name == 'nt' + # We test if the WinAPI works, because even if we are on Windows + # we may be using a terminal that doesn't support the WinAPI + # (e.g. Cygwin Terminal). In this case it's up to the terminal + # to support the ANSI codes. + conversion_supported = on_windows and winapi_test() + + # should we strip ANSI sequences from our output? + if strip is None: + strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped)) + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped) + self.convert = convert + + # dict of ansi codes to win32 functions and parameters + self.win32_calls = self.get_win32_calls() + + # are we wrapping stderr? + self.on_stderr = self.wrapped is sys.stderr + + def should_wrap(self): + ''' + True if this class is actually needed. If false, then the output + stream will not be affected, nor will win32 calls be issued, so + wrapping stdout is not actually required. This will generally be + False on non-Windows platforms, unless optional functionality like + autoreset has been requested using kwargs to init() + ''' + return self.convert or self.strip or self.autoreset + + def get_win32_calls(self): + if self.convert and winterm: + return { + AnsiStyle.RESET_ALL: (winterm.reset_all, ), + AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), + AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), + AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), + AnsiFore.RED: (winterm.fore, WinColor.RED), + AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), + AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), + AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), + AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), + AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), + AnsiFore.WHITE: (winterm.fore, WinColor.GREY), + AnsiFore.RESET: (winterm.fore, ), + AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), + AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), + AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), + AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), + AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), + AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), + AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), + AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), + AnsiBack.BLACK: (winterm.back, WinColor.BLACK), + AnsiBack.RED: (winterm.back, WinColor.RED), + AnsiBack.GREEN: (winterm.back, WinColor.GREEN), + AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), + AnsiBack.BLUE: (winterm.back, WinColor.BLUE), + AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), + AnsiBack.CYAN: (winterm.back, WinColor.CYAN), + AnsiBack.WHITE: (winterm.back, WinColor.GREY), + AnsiBack.RESET: (winterm.back, ), + AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), + AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), + AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), + AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), + AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), + AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), + AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), + AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), + } + return dict() + + def write(self, text): + if self.strip or self.convert: + self.write_and_convert(text) + else: + self.wrapped.write(text) + self.wrapped.flush() + if self.autoreset: + self.reset_all() + + + def reset_all(self): + if self.convert: + self.call_win32('m', (0,)) + elif not self.strip and not is_stream_closed(self.wrapped): + self.wrapped.write(Style.RESET_ALL) + + + def write_and_convert(self, text): + ''' + Write the given text to our wrapped stream, stripping any ANSI + sequences from the text, and optionally converting them into win32 + calls. + ''' + cursor = 0 + text = self.convert_osc(text) + for match in self.ANSI_CSI_RE.finditer(text): + start, end = match.span() + self.write_plain_text(text, cursor, start) + self.convert_ansi(*match.groups()) + cursor = end + self.write_plain_text(text, cursor, len(text)) + + + def write_plain_text(self, text, start, end): + if start < end: + self.wrapped.write(text[start:end]) + self.wrapped.flush() + + + def convert_ansi(self, paramstring, command): + if self.convert: + params = self.extract_params(command, paramstring) + self.call_win32(command, params) + + + def extract_params(self, command, paramstring): + if command in 'Hf': + params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) + while len(params) < 2: + # defaults: + params = params + (1,) + else: + params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) + if len(params) == 0: + # defaults: + if command in 'JKm': + params = (0,) + elif command in 'ABCD': + params = (1,) + + return params + + + def call_win32(self, command, params): + if command == 'm': + for param in params: + if param in self.win32_calls: + func_args = self.win32_calls[param] + func = func_args[0] + args = func_args[1:] + kwargs = dict(on_stderr=self.on_stderr) + func(*args, **kwargs) + elif command in 'J': + winterm.erase_screen(params[0], on_stderr=self.on_stderr) + elif command in 'K': + winterm.erase_line(params[0], on_stderr=self.on_stderr) + elif command in 'Hf': # cursor position - absolute + winterm.set_cursor_position(params, on_stderr=self.on_stderr) + elif command in 'ABCD': # cursor position - relative + n = params[0] + # A - up, B - down, C - forward, D - back + x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] + winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) + + + def convert_osc(self, text): + for match in self.ANSI_OSC_RE.finditer(text): + start, end = match.span() + text = text[:start] + text[end:] + paramstring, command = match.groups() + if command in '\x07': # \x07 = BEL + params = paramstring.split(";") + # 0 - change title and icon (we will only change title) + # 1 - change icon (we don't support this) + # 2 - change title + if params[0] in '02': + winterm.set_title(params[1]) + return text diff --git a/pipenv/vendor/colorama/initialise.py b/pipenv/vendor/colorama/initialise.py new file mode 100644 index 00000000..834962a3 --- /dev/null +++ b/pipenv/vendor/colorama/initialise.py @@ -0,0 +1,82 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +orig_stdout = None +orig_stderr = None + +wrapped_stdout = None +wrapped_stderr = None + +atexit_done = False + + +def reset_all(): + if AnsiToWin32 is not None: # Issue #74: objects might become None at exit + AnsiToWin32(orig_stdout).reset_all() + + +def init(autoreset=False, convert=None, strip=None, wrap=True): + + if not wrap and any([autoreset, convert, strip]): + raise ValueError('wrap=False conflicts with any other arg=True') + + global wrapped_stdout, wrapped_stderr + global orig_stdout, orig_stderr + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + + if sys.stdout is None: + wrapped_stdout = None + else: + sys.stdout = wrapped_stdout = \ + wrap_stream(orig_stdout, convert, strip, autoreset, wrap) + if sys.stderr is None: + wrapped_stderr = None + else: + sys.stderr = wrapped_stderr = \ + wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + + global atexit_done + if not atexit_done: + atexit.register(reset_all) + atexit_done = True + + +def deinit(): + if orig_stdout is not None: + sys.stdout = orig_stdout + if orig_stderr is not None: + sys.stderr = orig_stderr + + +@contextlib.contextmanager +def colorama_text(*args, **kwargs): + init(*args, **kwargs) + try: + yield + finally: + deinit() + + +def reinit(): + if wrapped_stdout is not None: + sys.stdout = wrapped_stdout + if wrapped_stderr is not None: + sys.stderr = wrapped_stderr + + +def wrap_stream(stream, convert, strip, autoreset, wrap): + if wrap: + wrapper = AnsiToWin32(stream, + convert=convert, strip=strip, autoreset=autoreset) + if wrapper.should_wrap(): + stream = wrapper.stream + return stream + + diff --git a/pipenv/vendor/colorama/win32.py b/pipenv/vendor/colorama/win32.py new file mode 100644 index 00000000..3d1d2f2d --- /dev/null +++ b/pipenv/vendor/colorama/win32.py @@ -0,0 +1,154 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleA + _SetConsoleTitleW.argtypes = [ + wintypes.LPCSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + handles = { + STDOUT: _GetStdHandle(STDOUT), + STDERR: _GetStdHandle(STDERR), + } + + def winapi_test(): + handle = handles[STDOUT] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = handles[stream_id] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = handles[stream_id] + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = handles[stream_id] + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = handles[stream_id] + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = handles[stream_id] + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) diff --git a/pipenv/vendor/colorama/winterm.py b/pipenv/vendor/colorama/winterm.py new file mode 100644 index 00000000..60309d3c --- /dev/null +++ b/pipenv/vendor/colorama/winterm.py @@ -0,0 +1,162 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from . import win32 + + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + if mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + if mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/pipenv/vendor/crayons.py b/pipenv/vendor/crayons.py new file mode 100644 index 00000000..455d3e90 --- /dev/null +++ b/pipenv/vendor/crayons.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- + +""" +clint.colored +~~~~~~~~~~~~~ + +This module provides a simple and elegant wrapper for colorama. + +""" + +import os +import re +import sys + +PY3 = sys.version_info[0] >= 3 + +import colorama + +__all__ = ( + 'red', 'green', 'yellow', 'blue', + 'black', 'magenta', 'cyan', 'white', + 'clean', 'disable' +) + +COLORS = __all__[:-2] + +if 'get_ipython' in dir(): + """ + when ipython is fired lot of variables like _oh, etc are used. + There are so many ways to find current python interpreter is ipython. + get_ipython is easiest is most appealing for readers to understand. + """ + DISABLE_COLOR = True +else: + DISABLE_COLOR = False + + +class ColoredString(object): + """Enhanced string for __len__ operations on Colored output.""" + def __init__(self, color, s, always_color=False, bold=False): + super(ColoredString, self).__init__() + if not PY3 and isinstance(s, unicode): + self.s = s.encode('utf-8') + else: + self.s = s + self.color = color + self.always_color = always_color + self.bold = bold + if os.environ.get('CLINT_FORCE_COLOR'): + self.always_color = True + + def __getattr__(self, att): + def func_help(*args, **kwargs): + result = getattr(self.s, att)(*args, **kwargs) + try: + is_result_string = isinstance(result, basestring) + except NameError: + is_result_string = isinstance(result, str) + if is_result_string: + return self._new(result) + elif isinstance(result, list): + return [self._new(x) for x in result] + else: + return result + return func_help + + @property + def color_str(self): + style = 'BRIGHT' if self.bold else 'NORMAL' + c = '%s%s%s%s%s' % (getattr(colorama.Fore, self.color), getattr(colorama.Style, style), self.s, colorama.Fore.RESET, getattr(colorama.Style, 'NORMAL')) + + if self.always_color: + return c + elif sys.stdout.isatty() and not DISABLE_COLOR: + return c + else: + return self.s + + + def __len__(self): + return len(self.s) + + def __repr__(self): + return "<%s-string: '%s'>" % (self.color, self.s) + + def __unicode__(self): + value = self.color_str + if isinstance(value, bytes): + return value.decode('utf8') + return value + + if PY3: + __str__ = __unicode__ + else: + def __str__(self): + return self.color_str + + def __iter__(self): + return iter(self.color_str) + + def __add__(self, other): + return str(self.color_str) + str(other) + + def __radd__(self, other): + return str(other) + str(self.color_str) + + def __mul__(self, other): + return (self.color_str * other) + + def _new(self, s): + return ColoredString(self.color, s) + + +def clean(s): + strip = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)") + txt = strip.sub('', str(s)) + + strip = re.compile(r'\[\d+m') + txt = strip.sub('', txt) + + return txt + + +def black(string, always=False, bold=False): + return ColoredString('BLACK', string, always_color=always, bold=bold) + +def red(string, always=False, bold=False): + return ColoredString('RED', string, always_color=always, bold=bold) + +def green(string, always=False, bold=False): + return ColoredString('GREEN', string, always_color=always, bold=bold) + +def yellow(string, always=False, bold=False): + return ColoredString('YELLOW', string, always_color=always, bold=bold) + +def blue(string, always=False, bold=False): + return ColoredString('BLUE', string, always_color=always, bold=bold) + +def magenta(string, always=False, bold=False): + return ColoredString('MAGENTA', string, always_color=always, bold=bold) + +def cyan(string, always=False, bold=False): + return ColoredString('CYAN', string, always_color=always, bold=bold) + +def white(string, always=False, bold=False): + return ColoredString('WHITE', string, always_color=always, bold=bold) + +def disable(): + """Disables colors.""" + global DISABLE_COLOR + + DISABLE_COLOR = True diff --git a/pipenv/vendor/delegator.py b/pipenv/vendor/delegator.py new file mode 100644 index 00000000..2404a1b6 --- /dev/null +++ b/pipenv/vendor/delegator.py @@ -0,0 +1,220 @@ +import os +import subprocess +import shlex + +from pexpect.popen_spawn import PopenSpawn + +# Enable Python subprocesses to work with expect functionality. +os.environ['PYTHONUNBUFFERED'] = '1' + +class Command(object): + def __init__(self, cmd): + super(Command, self).__init__() + self.cmd = cmd + self.subprocess = None + self.blocking = None + self.was_run = False + self.__out = None + + def __repr__(self): + return ''.format(self.cmd) + + @property + def _popen_args(self): + return self.cmd + + @property + def _default_popen_kwargs(self): + return { + 'env': os.environ.copy(), + 'stdin': subprocess.PIPE, + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + 'shell': True, + 'universal_newlines': True, + 'bufsize': 0, + } + + @property + def _default_pexpect_kwargs(self): + return { + 'env': os.environ.copy(), + } + + @property + def _uses_subprocess(self): + return isinstance(self.subprocess, subprocess.Popen) + + @property + def _uses_pexpect(self): + return isinstance(self.subprocess, PopenSpawn) + + @property + def std_out(self): + return self.subprocess.stdout + + @property + def _pexpect_out(self): + result = '' + + if self.subprocess.before: + result += self.subprocess.before + + if isinstance(self.subprocess.after, str): + result += self.subprocess.after + + result += self.subprocess.read().decode('utf-8') + return result + + @property + def out(self): + """Std/out output (cached), as well as stderr for non-blocking runs.""" + if self.__out: + return self.__out + + if self._uses_subprocess: + self.__out = self.std_out.read() + else: + self.__out = self._pexpect_out + + return self.__out + + @property + def std_err(self): + return self.subprocess.stderr + + @property + def err(self): + if self._uses_subprocess: + return self.std_err.read() + else: + return self._pexpect_out + + @property + def pid(self): + """The process' PID.""" + # Support for pexpect's functionality. + if hasattr(self.subprocess, 'proc'): + return self.subprocess.proc.pid + # Standard subprocess method. + return self.subprocess.pid + + @property + def return_code(self): + return self.subprocess.returncode + + @property + def std_in(self): + return self.subprocess.stdin + + def run(self, block=True): + """Runs the given command, with or without pexpect functionality enabled.""" + self.blocking = block + + # Use subprocess. + if self.blocking: + s = subprocess.Popen(self._popen_args, **self._default_popen_kwargs) + + # Otherwise, use pexpect. + else: + s = PopenSpawn(self._popen_args, **self._default_pexpect_kwargs) + self.subprocess = s + self.was_run = True + + def expect(self, pattern, timeout=-1): + """Waits on the given pattern to appear in std_out""" + + if self.blocking: + raise RuntimeError('expect can only be used on non-blocking commands.') + + self.subprocess.expect(pattern=pattern, timeout=timeout) + + def send(self, s, end=os.linesep, signal=False): + """Sends the given string or signal to std_in.""" + + if self.blocking: + raise RuntimeError('send can only be used on non-blocking commands.') + + if not signal: + if self._uses_subprocess: + return self.subprocess.communicate(s + end) + else: + return self.subprocess.send(s + end) + else: + self.subprocess.send_signal(s) + + def terminate(self): + self.subprocess.terminate() + + def kill(self): + self.subprocess.kill() + + def block(self): + """Blocks until process is complete.""" + self.subprocess.wait() + + def pipe(self, command): + """Runs the current command and passes its output to the next + given process. + """ + if not self.was_run: + self.run(block=False) + + data = self.out + + c = Command(command) + c.run(block=False) + if data: + c.send(data) + c.subprocess.sendeof() + c.block() + return c + + +def _expand_args(command): + """Parses command strings and returns a Popen-ready list.""" + + # Prepare arguments. + if isinstance(command, (str, unicode)): + splitter = shlex.shlex(command.encode('utf-8')) + splitter.whitespace = '|' + splitter.whitespace_split = True + command = [] + + while True: + token = splitter.get_token() + if token: + command.append(token) + else: + break + + command = list(map(shlex.split, command)) + + return command + + +def chain(command): + commands = _expand_args(command) + data = None + + for command in commands: + + c = run(command, block=False) + + if data: + c.send(data) + c.subprocess.sendeof() + + data = c.out + + return c + + +def run(command, block=True): + c = Command(command) + c.run(block=block) + + if block: + c.block() + + return c diff --git a/pipenv/vendor/parse.py b/pipenv/vendor/parse.py new file mode 100755 index 00000000..6a02a3bb --- /dev/null +++ b/pipenv/vendor/parse.py @@ -0,0 +1,1209 @@ +r'''Parse strings using a specification based on the Python format() syntax. + + ``parse()`` is the opposite of ``format()`` + +The module is set up to only export ``parse()``, ``search()`` and +``findall()`` when ``import *`` is used: + +>>> from parse import * + +From there it's a simple thing to parse a string: + +>>> parse("It's {}, I love it!", "It's spam, I love it!") + +>>> _[0] +'spam' + +Or to search a string for some pattern: + +>>> search('Age: {:d}\n', 'Name: Rufus\nAge: 42\nColor: red\n') + + +Or find all the occurrences of some pattern in a string: + +>>> ''.join(r.fixed[0] for r in findall(">{}<", "

    the bold text

    ")) +'the bold text' + +If you're going to use the same pattern to match lots of strings you can +compile it once: + +>>> from parse import compile +>>> p = compile("It's {}, I love it!") +>>> print(p) + +>>> p.parse("It's spam, I love it!") + + +("compile" is not exported for ``import *`` usage as it would override the +built-in ``compile()`` function) + + +Format Syntax +------------- + +A basic version of the `Format String Syntax`_ is supported with anonymous +(fixed-position), named and formatted fields:: + + {[field name]:[format spec]} + +Field names must be a valid Python identifiers, including dotted names; +element indexes imply dictionaries (see below for example). + +Numbered fields are also not supported: the result of parsing will include +the parsed fields in the order they are parsed. + +The conversion of fields to types other than strings is done based on the +type in the format specification, which mirrors the ``format()`` behaviour. +There are no "!" field conversions like ``format()`` has. + +Some simple parse() format string examples: + +>>> parse("Bring me a {}", "Bring me a shrubbery") + +>>> r = parse("The {} who say {}", "The knights who say Ni!") +>>> print(r) + +>>> print(r.fixed) +('knights', 'Ni!') +>>> r = parse("Bring out the holy {item}", "Bring out the holy hand grenade") +>>> print(r) + +>>> print(r.named) +{'item': 'hand grenade'} +>>> print(r['item']) +hand grenade + +Dotted names and indexes are possible though the application must make +additional sense of the result: + +>>> r = parse("Mmm, {food.type}, I love it!", "Mmm, spam, I love it!") +>>> print(r) + +>>> print(r.named) +{'food.type': 'spam'} +>>> print(r['food.type']) +spam +>>> r = parse("My quest is {quest[name]}", "My quest is to seek the holy grail!") +>>> print(r) + +>>> print(r['quest']) +{'name': 'to seek the holy grail!'} +>>> print(r['quest']['name']) +to seek the holy grail! + + +Format Specification +-------------------- + +Most often a straight format-less ``{}`` will suffice where a more complex +format specification might have been used. + +Most of `format()`'s `Format Specification Mini-Language`_ is supported: + + [[fill]align][0][width][.precision][type] + +The differences between `parse()` and `format()` are: + +- The align operators will cause spaces (or specified fill character) to be + stripped from the parsed value. The width is not enforced; it just indicates + there may be whitespace or "0"s to strip. +- Numeric parsing will automatically handle a "0b", "0o" or "0x" prefix. + That is, the "#" format character is handled automatically by d, b, o + and x formats. For "d" any will be accepted, but for the others the correct + prefix must be present if at all. +- Numeric sign is handled automatically. +- The thousands separator is handled automatically if the "n" type is used. +- The types supported are a slightly different mix to the format() types. Some + format() types come directly over: "d", "n", "%", "f", "e", "b", "o" and "x". + In addition some regular expression character group types "D", "w", "W", "s" + and "S" are also available. +- The "e" and "g" types are case-insensitive so there is not need for + the "E" or "G" types. + +===== =========================================== ======== +Type Characters Matched Output +===== =========================================== ======== + w Letters and underscore str + W Non-letter and underscore str + s Whitespace str + S Non-whitespace str + d Digits (effectively integer numbers) int + D Non-digit str + n Numbers with thousands separators (, or .) int + % Percentage (converted to value/100.0) float + f Fixed-point numbers float + e Floating-point numbers with exponent float + e.g. 1.1e-10, NAN (all case insensitive) + g General number format (either d, f or e) float + b Binary numbers int + o Octal numbers int + x Hexadecimal numbers (lower and upper case) int + ti ISO 8601 format date/time datetime + e.g. 1972-01-20T10:21:36Z ("T" and "Z" + optional) + te RFC2822 e-mail format date/time datetime + e.g. Mon, 20 Jan 1972 10:21:36 +1000 + tg Global (day/month) format date/time datetime + e.g. 20/1/1972 10:21:36 AM +1:00 + ta US (month/day) format date/time datetime + e.g. 1/20/1972 10:21:36 PM +10:30 + tc ctime() format date/time datetime + e.g. Sun Sep 16 01:03:52 1973 + th HTTP log format date/time datetime + e.g. 21/Nov/2011:00:07:11 +0000 + ts Linux system log format date/time datetime + e.g. Nov 9 03:37:44 + tt Time time + e.g. 10:21:36 PM -5:30 +===== =========================================== ======== + +Some examples of typed parsing with ``None`` returned if the typing +does not match: + +>>> parse('Our {:d} {:w} are...', 'Our 3 weapons are...') + +>>> parse('Our {:d} {:w} are...', 'Our three weapons are...') +>>> parse('Meet at {:tg}', 'Meet at 1/2/2011 11:00 PM') + + +And messing about with alignment: + +>>> parse('with {:>} herring', 'with a herring') + +>>> parse('spam {:^} spam', 'spam lovely spam') + + +Note that the "center" alignment does not test to make sure the value is +centered - it just strips leading and trailing whitespace. + +Some notes for the date and time types: + +- the presence of the time part is optional (including ISO 8601, starting + at the "T"). A full datetime object will always be returned; the time + will be set to 00:00:00. You may also specify a time without seconds. +- when a seconds amount is present in the input fractions will be parsed + to give microseconds. +- except in ISO 8601 the day and month digits may be 0-padded. +- the date separator for the tg and ta formats may be "-" or "/". +- named months (abbreviations or full names) may be used in the ta and tg + formats in place of numeric months. +- as per RFC 2822 the e-mail format may omit the day (and comma), and the + seconds but nothing else. +- hours greater than 12 will be happily accepted. +- the AM/PM are optional, and if PM is found then 12 hours will be added + to the datetime object's hours amount - even if the hour is greater + than 12 (for consistency.) +- in ISO 8601 the "Z" (UTC) timezone part may be a numeric offset +- timezones are specified as "+HH:MM" or "-HH:MM". The hour may be one or two + digits (0-padded is OK.) Also, the ":" is optional. +- the timezone is optional in all except the e-mail format (it defaults to + UTC.) +- named timezones are not handled yet. + +Note: attempting to match too many datetime fields in a single parse() will +currently result in a resource allocation issue. A TooManyFields exception +will be raised in this instance. The current limit is about 15. It is hoped +that this limit will be removed one day. + +.. _`Format String Syntax`: + http://docs.python.org/library/string.html#format-string-syntax +.. _`Format Specification Mini-Language`: + http://docs.python.org/library/string.html#format-specification-mini-language + + +Result and Match Objects +------------------------ + +The result of a ``parse()`` and ``search()`` operation is either ``None`` (no match), a +``Result`` instance or a ``Match`` instance if ``evaluate_result`` is False. + +The ``Result`` instance has three attributes: + +fixed + A tuple of the fixed-position, anonymous fields extracted from the input. +named + A dictionary of the named fields extracted from the input. +spans + A dictionary mapping the names and fixed position indices matched to a + 2-tuple slice range of where the match occurred in the input. + The span does not include any stripped padding (alignment or width). + +The ``Match`` instance has one method: + +evaluate_result() + Generates and returns a ``Result`` instance for this ``Match`` object. + + + +Custom Type Conversions +----------------------- + +If you wish to have matched fields automatically converted to your own type you +may pass in a dictionary of type conversion information to ``parse()`` and +``compile()``. + +The converter will be passed the field string matched. Whatever it returns +will be substituted in the ``Result`` instance for that field. + +Your custom type conversions may override the builtin types if you supply one +with the same identifier. + +>>> def shouty(string): +... return string.upper() +... +>>> parse('{:shouty} world', 'hello world', dict(shouty=shouty)) + + +If the type converter has the optional ``pattern`` attribute, it is used as +regular expression for better pattern matching (instead of the default one). + +>>> def parse_number(text): +... return int(text) +>>> parse_number.pattern = r'\d+' +>>> parse('Answer: {number:Number}', 'Answer: 42', dict(Number=parse_number)) + +>>> _ = parse('Answer: {:Number}', 'Answer: Alice', dict(Number=parse_number)) +>>> assert _ is None, "MISMATCH" + +You can also use the ``with_pattern(pattern)`` decorator to add this +information to a type converter function: + +>>> from parse import with_pattern +>>> @with_pattern(r'\d+') +... def parse_number(text): +... return int(text) +>>> parse('Answer: {number:Number}', 'Answer: 42', dict(Number=parse_number)) + + +A more complete example of a custom type might be: + +>>> yesno_mapping = { +... "yes": True, "no": False, +... "on": True, "off": False, +... "true": True, "false": False, +... } +>>> @with_pattern(r"|".join(yesno_mapping)) +... def parse_yesno(text): +... return yesno_mapping[text.lower()] + + +---- + +**Version history (in brief)**: + +- 1.8.0 support manual control over result evaluation (thanks Timo Furrer) +- 1.7.0 parse dict fields (thanks Mark Visser) and adapted to allow + more than 100 re groups in Python 3.5+ (thanks David King) +- 1.6.6 parse Linux system log dates (thanks Alex Cowan) +- 1.6.5 handle precision in float format (thanks Levi Kilcher) +- 1.6.4 handle pipe "|" characters in parse string (thanks Martijn Pieters) +- 1.6.3 handle repeated instances of named fields, fix bug in PM time + overflow +- 1.6.2 fix logging to use local, not root logger (thanks Necku) +- 1.6.1 be more flexible regarding matched ISO datetimes and timezones in + general, fix bug in timezones without ":" and improve docs +- 1.6.0 add support for optional ``pattern`` attribute in user-defined types + (thanks Jens Engel) +- 1.5.3 fix handling of question marks +- 1.5.2 fix type conversion error with dotted names (thanks Sebastian Thiel) +- 1.5.1 implement handling of named datetime fields +- 1.5 add handling of dotted field names (thanks Sebastian Thiel) +- 1.4.1 fix parsing of "0" in int conversion (thanks James Rowe) +- 1.4 add __getitem__ convenience access on Result. +- 1.3.3 fix Python 2.5 setup.py issue. +- 1.3.2 fix Python 3.2 setup.py issue. +- 1.3.1 fix a couple of Python 3.2 compatibility issues. +- 1.3 added search() and findall(); removed compile() from ``import *`` + export as it overwrites builtin. +- 1.2 added ability for custom and override type conversions to be + provided; some cleanup +- 1.1.9 to keep things simpler number sign is handled automatically; + significant robustification in the face of edge-case input. +- 1.1.8 allow "d" fields to have number base "0x" etc. prefixes; + fix up some field type interactions after stress-testing the parser; + implement "%" type. +- 1.1.7 Python 3 compatibility tweaks (2.5 to 2.7 and 3.2 are supported). +- 1.1.6 add "e" and "g" field types; removed redundant "h" and "X"; + removed need for explicit "#". +- 1.1.5 accept textual dates in more places; Result now holds match span + positions. +- 1.1.4 fixes to some int type conversion; implemented "=" alignment; added + date/time parsing with a variety of formats handled. +- 1.1.3 type conversion is automatic based on specified field types. Also added + "f" and "n" types. +- 1.1.2 refactored, added compile() and limited ``from parse import *`` +- 1.1.1 documentation improvements +- 1.1.0 implemented more of the `Format Specification Mini-Language`_ + and removed the restriction on mixing fixed-position and named fields +- 1.0.0 initial release + +This code is copyright 2012-2017 Richard Jones +See the end of the source file for the license of use. +''' +__version__ = '1.8.0' + +# yes, I now have two problems +import re +import sys +from datetime import datetime, time, tzinfo, timedelta +from functools import partial +import logging + +__all__ = 'parse search findall with_pattern'.split() + +log = logging.getLogger(__name__) + + +def with_pattern(pattern): + """Attach a regular expression pattern matcher to a custom type converter + function. + + This annotates the type converter with the :attr:`pattern` attribute. + + EXAMPLE: + >>> import parse + >>> @parse.with_pattern(r"\d+") + ... def parse_number(text): + ... return int(text) + + is equivalent to: + + >>> def parse_number(text): + ... return int(text) + >>> parse_number.pattern = r"\d+" + + :param pattern: regular expression pattern (as text) + :return: wrapped function + """ + def decorator(func): + func.pattern = pattern + return func + return decorator + + +def int_convert(base): + '''Convert a string to an integer. + + The string may start with a sign. + + It may be of a base other than 10. + + It may also have other non-numeric characters that we can ignore. + ''' + CHARS = '0123456789abcdefghijklmnopqrstuvwxyz' + + def f(string, match, base=base): + if string[0] == '-': + sign = -1 + else: + sign = 1 + + if string[0] == '0' and len(string) > 1: + if string[1] in 'bB': + base = 2 + elif string[1] in 'oO': + base = 8 + elif string[1] in 'xX': + base = 16 + else: + # just go with the base specifed + pass + + chars = CHARS[:base] + string = re.sub('[^%s]' % chars, '', string.lower()) + return sign * int(string, base) + return f + + +def percentage(string, match): + return float(string[:-1]) / 100. + + +class FixedTzOffset(tzinfo): + """Fixed offset in minutes east from UTC. + """ + ZERO = timedelta(0) + + def __init__(self, offset, name): + self._offset = timedelta(minutes=offset) + self._name = name + + def __repr__(self): + return '<%s %s %s>' % (self.__class__.__name__, self._name, + self._offset) + + def utcoffset(self, dt): + return self._offset + + def tzname(self, dt): + return self._name + + def dst(self, dt): + return self.ZERO + + def __eq__(self, other): + return self._name == other._name and self._offset == other._offset + + +MONTHS_MAP = dict( + Jan=1, January=1, + Feb=2, February=2, + Mar=3, March=3, + Apr=4, April=4, + May=5, + Jun=6, June=6, + Jul=7, July=7, + Aug=8, August=8, + Sep=9, September=9, + Oct=10, October=10, + Nov=11, November=11, + Dec=12, December=12 +) +DAYS_PAT = '(Mon|Tue|Wed|Thu|Fri|Sat|Sun)' +MONTHS_PAT = '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)' +ALL_MONTHS_PAT = '(%s)' % '|'.join(MONTHS_MAP) +TIME_PAT = r'(\d{1,2}:\d{1,2}(:\d{1,2}(\.\d+)?)?)' +AM_PAT = r'(\s+[AP]M)' +TZ_PAT = r'(\s+[-+]\d\d?:?\d\d)' + + +def date_convert(string, match, ymd=None, mdy=None, dmy=None, + d_m_y=None, hms=None, am=None, tz=None, mm=None, dd=None): + '''Convert the incoming string containing some date / time info into a + datetime instance. + ''' + groups = match.groups() + time_only = False + if mm and dd: + y=datetime.today().year + m=groups[mm] + d=groups[dd] + elif ymd is not None: + y, m, d = re.split('[-/\s]', groups[ymd]) + elif mdy is not None: + m, d, y = re.split('[-/\s]', groups[mdy]) + elif dmy is not None: + d, m, y = re.split('[-/\s]', groups[dmy]) + elif d_m_y is not None: + d, m, y = d_m_y + d = groups[d] + m = groups[m] + y = groups[y] + else: + time_only = True + + H = M = S = u = 0 + if hms is not None and groups[hms]: + t = groups[hms].split(':') + if len(t) == 2: + H, M = t + else: + H, M, S = t + if '.' in S: + S, u = S.split('.') + u = int(float('.' + u) * 1000000) + S = int(S) + H = int(H) + M = int(M) + + day_incr = False + if am is not None: + am = groups[am] + if am and am.strip() == 'PM': + H += 12 + if H > 23: + day_incr = True + H -= 24 + + if tz is not None: + tz = groups[tz] + if tz == 'Z': + tz = FixedTzOffset(0, 'UTC') + elif tz: + tz = tz.strip() + if tz.isupper(): + # TODO use the awesome python TZ module? + pass + else: + sign = tz[0] + if ':' in tz: + tzh, tzm = tz[1:].split(':') + elif len(tz) == 4: # 'snnn' + tzh, tzm = tz[1], tz[2:4] + else: + tzh, tzm = tz[1:3], tz[3:5] + offset = int(tzm) + int(tzh) * 60 + if sign == '-': + offset = -offset + tz = FixedTzOffset(offset, tz) + + if time_only: + d = time(H, M, S, u, tzinfo=tz) + else: + y = int(y) + if m.isdigit(): + m = int(m) + else: + m = MONTHS_MAP[m] + d = int(d) + d = datetime(y, m, d, H, M, S, u, tzinfo=tz) + + if day_incr: + d = d + timedelta(days=1) + + return d + + +class TooManyFields(ValueError): + pass + + +class RepeatedNameError(ValueError): + pass + + +# note: {} are handled separately +# note: I don't use r'' here because Sublime Text 2 syntax highlight has a fit +REGEX_SAFETY = re.compile('([?\\\\.[\]()*+\^$!\|])') + +# allowed field types +ALLOWED_TYPES = set(list('nbox%fegwWdDsS') + + ['t' + c for c in 'ieahgcts']) + + +def extract_format(format, extra_types): + '''Pull apart the format [[fill]align][0][width][.precision][type] + ''' + fill = align = None + if format[0] in '<>=^': + align = format[0] + format = format[1:] + elif len(format) > 1 and format[1] in '<>=^': + fill = format[0] + align = format[1] + format = format[2:] + + zero = False + if format and format[0] == '0': + zero = True + format = format[1:] + + width = '' + while format: + if not format[0].isdigit(): + break + width += format[0] + format = format[1:] + + if format.startswith('.'): + # Precision isn't needed but we need to capture it so that + # the ValueError isn't raised. + format = format[1:] # drop the '.' + precision = '' + while format: + if not format[0].isdigit(): + break + precision += format[0] + format = format[1:] + + # the rest is the type, if present + type = format + if type and type not in ALLOWED_TYPES and type not in extra_types: + raise ValueError('type %r not recognised' % type) + + return locals() + + +PARSE_RE = re.compile(r"""({{|}}|{\w*(?:(?:\.\w+)|(?:\[[^\]]+\]))*(?::[^}]+)?})""") + + +class Parser(object): + '''Encapsulate a format string that may be used to parse other strings. + ''' + def __init__(self, format, extra_types={}): + # a mapping of a name as in {hello.world} to a regex-group compatible + # name, like hello__world Its used to prevent the transformation of + # name-to-group and group to name to fail subtly, such as in: + # hello_.world-> hello___world->hello._world + self._group_to_name_map = {} + # also store the original field name to group name mapping to allow + # multiple instances of a name in the format string + self._name_to_group_map = {} + # and to sanity check the repeated instances store away the first + # field type specification for the named field + self._name_types = {} + + self._format = format + self._extra_types = extra_types + self._fixed_fields = [] + self._named_fields = [] + self._group_index = 0 + self._type_conversions = {} + self._expression = self._generate_expression() + self.__search_re = None + self.__match_re = None + + log.debug('format %r -> %r' % (format, self._expression)) + + def __repr__(self): + if len(self._format) > 20: + return '<%s %r>' % (self.__class__.__name__, + self._format[:17] + '...') + return '<%s %r>' % (self.__class__.__name__, self._format) + + @property + def _search_re(self): + if self.__search_re is None: + try: + self.__search_re = re.compile(self._expression, + re.IGNORECASE | re.DOTALL) + except AssertionError: + # access error through sys to keep py3k and backward compat + e = str(sys.exc_info()[1]) + if e.endswith('this version only supports 100 named groups'): + raise TooManyFields('sorry, you are attempting to parse ' + 'too many complex fields') + return self.__search_re + + @property + def _match_re(self): + if self.__match_re is None: + expression = '^%s$' % self._expression + try: + self.__match_re = re.compile(expression, + re.IGNORECASE | re.DOTALL) + except AssertionError: + # access error through sys to keep py3k and backward compat + e = str(sys.exc_info()[1]) + if e.endswith('this version only supports 100 named groups'): + raise TooManyFields('sorry, you are attempting to parse ' + 'too many complex fields') + except re.error: + raise NotImplementedError("Group names (e.g. (?P) can " + "cause failure, as they are not escaped properly: '%s'" % + expression) + return self.__match_re + + def parse(self, string, evaluate_result=True): + '''Match my format to the string exactly. + + Return a Result or Match instance or None if there's no match. + ''' + m = self._match_re.match(string) + if m is None: + return None + + if evaluate_result: + return self.evaluate_result(m) + else: + return Match(self, m) + + def search(self, string, pos=0, endpos=None, evaluate_result=True): + '''Search the string for my format. + + Optionally start the search at "pos" character index and limit the + search to a maximum index of endpos - equivalent to + search(string[:endpos]). + + If the ``evaluate_result`` argument is set to ``False`` a + Match instance is returned instead of the actual Result instance. + + Return either a Result instance or None if there's no match. + ''' + if endpos is None: + endpos = len(string) + m = self._search_re.search(string, pos, endpos) + if m is None: + return None + + if evaluate_result: + return self.evaluate_result(m) + else: + return Match(self, m) + + def findall(self, string, pos=0, endpos=None, extra_types={}, evaluate_result=True): + '''Search "string" for the all occurrances of "format". + + Optionally start the search at "pos" character index and limit the + search to a maximum index of endpos - equivalent to + search(string[:endpos]). + + Returns an iterator that holds Result or Match instances for each format match + found. + ''' + if endpos is None: + endpos = len(string) + return ResultIterator(self, string, pos, endpos, evaluate_result=evaluate_result) + + def _expand_named_fields(self, named_fields): + result = {} + for field, value in named_fields.items(): + # split 'aaa[bbb][ccc]...' into 'aaa' and '[bbb][ccc]...' + basename, subkeys = re.match(r'([^\[]+)(.*)', field).groups() + + # create nested dictionaries {'aaa': {'bbb': {'ccc': ...}}} + d = result + k = basename + + if subkeys: + for subkey in re.findall(r'\[[^\]]+\]', subkeys): + d = d.setdefault(k,{}) + k = subkey[1:-1] + + # assign the value to the last key + d[k] = value + + return result + + def evaluate_result(self, m): + '''Generate a Result instance for the given regex match object''' + # ok, figure the fixed fields we've pulled out and type convert them + fixed_fields = list(m.groups()) + for n in self._fixed_fields: + if n in self._type_conversions: + fixed_fields[n] = self._type_conversions[n](fixed_fields[n], m) + fixed_fields = tuple(fixed_fields[n] for n in self._fixed_fields) + + # grab the named fields, converting where requested + groupdict = m.groupdict() + named_fields = {} + name_map = {} + for k in self._named_fields: + korig = self._group_to_name_map[k] + name_map[korig] = k + if k in self._type_conversions: + value = self._type_conversions[k](groupdict[k], m) + else: + value = groupdict[k] + + named_fields[korig] = value + + # now figure the match spans + spans = dict((n, m.span(name_map[n])) for n in named_fields) + spans.update((i, m.span(n + 1)) + for i, n in enumerate(self._fixed_fields)) + + # and that's our result + return Result(fixed_fields, self._expand_named_fields(named_fields), spans) + + def _regex_replace(self, match): + return '\\' + match.group(1) + + def _generate_expression(self): + # turn my _format attribute into the _expression attribute + e = [] + for part in PARSE_RE.split(self._format): + if not part: + continue + elif part == '{{': + e.append(r'\{') + elif part == '}}': + e.append(r'\}') + elif part[0] == '{': + # this will be a braces-delimited field to handle + e.append(self._handle_field(part)) + else: + # just some text to match + e.append(REGEX_SAFETY.sub(self._regex_replace, part)) + return ''.join(e) + + def _to_group_name(self, field): + # return a version of field which can be used as capture group, even + # though it might contain '.' + group = field.replace('.', '_').replace('[', '_').replace(']', '_') + + # make sure we don't collide ("a.b" colliding with "a_b") + n = 1 + while group in self._group_to_name_map: + n += 1 + if '.' in field: + group = field.replace('.', '_' * n) + elif '_' in field: + group = field.replace('_', '_' * n) + else: + raise KeyError('duplicated group name %r' % (field, )) + + # save off the mapping + self._group_to_name_map[group] = field + self._name_to_group_map[field] = group + return group + + def _handle_field(self, field): + # first: lose the braces + field = field[1:-1] + + # now figure whether this is an anonymous or named field, and whether + # there's any format specification + format = '' + if field and field[0].isalpha(): + if ':' in field: + name, format = field.split(':') + else: + name = field + if name in self._name_to_group_map: + if self._name_types[name] != format: + raise RepeatedNameError('field type %r for field "%s" ' + 'does not match previous seen type %r' % (format, + name, self._name_types[name])) + group = self._name_to_group_map[name] + # match previously-seen value + return '(?P=%s)' % group + else: + group = self._to_group_name(name) + self._name_types[name] = format + self._named_fields.append(group) + # this will become a group, which must not contain dots + wrap = '(?P<%s>%%s)' % group + else: + self._fixed_fields.append(self._group_index) + wrap = '(%s)' + if ':' in field: + format = field[1:] + group = self._group_index + + # simplest case: no type specifier ({} or {name}) + if not format: + self._group_index += 1 + return wrap % '.+?' + + # decode the format specification + format = extract_format(format, self._extra_types) + + # figure type conversions, if any + type = format['type'] + is_numeric = type and type in 'n%fegdobh' + if type in self._extra_types: + type_converter = self._extra_types[type] + s = getattr(type_converter, 'pattern', r'.+?') + + def f(string, m): + return type_converter(string) + self._type_conversions[group] = f + elif type == 'n': + s = '\d{1,3}([,.]\d{3})*' + self._group_index += 1 + self._type_conversions[group] = int_convert(10) + elif type == 'b': + s = '(0[bB])?[01]+' + self._type_conversions[group] = int_convert(2) + self._group_index += 1 + elif type == 'o': + s = '(0[oO])?[0-7]+' + self._type_conversions[group] = int_convert(8) + self._group_index += 1 + elif type == 'x': + s = '(0[xX])?[0-9a-fA-F]+' + self._type_conversions[group] = int_convert(16) + self._group_index += 1 + elif type == '%': + s = r'\d+(\.\d+)?%' + self._group_index += 1 + self._type_conversions[group] = percentage + elif type == 'f': + s = r'\d+\.\d+' + self._type_conversions[group] = lambda s, m: float(s) + elif type == 'e': + s = r'\d+\.\d+[eE][-+]?\d+|nan|NAN|[-+]?inf|[-+]?INF' + self._type_conversions[group] = lambda s, m: float(s) + elif type == 'g': + s = r'\d+(\.\d+)?([eE][-+]?\d+)?|nan|NAN|[-+]?inf|[-+]?INF' + self._group_index += 2 + self._type_conversions[group] = lambda s, m: float(s) + elif type == 'd': + s = r'\d+|0[xX][0-9a-fA-F]+|[0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+' + self._type_conversions[group] = int_convert(10) + elif type == 'ti': + s = r'(\d{4}-\d\d-\d\d)((\s+|T)%s)?(Z|\s*[-+]\d\d:?\d\d)?' % \ + TIME_PAT + n = self._group_index + self._type_conversions[group] = partial(date_convert, ymd=n + 1, + hms=n + 4, tz=n + 7) + self._group_index += 7 + elif type == 'tg': + s = r'(\d{1,2}[-/](\d{1,2}|%s)[-/]\d{4})(\s+%s)?%s?%s?' % ( + ALL_MONTHS_PAT, TIME_PAT, AM_PAT, TZ_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, dmy=n + 1, + hms=n + 5, am=n + 8, tz=n + 9) + self._group_index += 9 + elif type == 'ta': + s = r'((\d{1,2}|%s)[-/]\d{1,2}[-/]\d{4})(\s+%s)?%s?%s?' % ( + ALL_MONTHS_PAT, TIME_PAT, AM_PAT, TZ_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, mdy=n + 1, + hms=n + 5, am=n + 8, tz=n + 9) + self._group_index += 9 + elif type == 'te': + # this will allow microseconds through if they're present, but meh + s = r'(%s,\s+)?(\d{1,2}\s+%s\s+\d{4})\s+%s%s' % (DAYS_PAT, + MONTHS_PAT, TIME_PAT, TZ_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, dmy=n + 3, + hms=n + 5, tz=n + 8) + self._group_index += 8 + elif type == 'th': + # slight flexibility here from the stock Apache format + s = r'(\d{1,2}[-/]%s[-/]\d{4}):%s%s' % (MONTHS_PAT, TIME_PAT, + TZ_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, dmy=n + 1, + hms=n + 3, tz=n + 6) + self._group_index += 6 + elif type == 'tc': + s = r'(%s)\s+%s\s+(\d{1,2})\s+%s\s+(\d{4})' % ( + DAYS_PAT, MONTHS_PAT, TIME_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, + d_m_y=(n + 4, n + 3, n + 8), hms=n + 5) + self._group_index += 8 + elif type == 'tt': + s = r'%s?%s?%s?' % (TIME_PAT, AM_PAT, TZ_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, hms=n + 1, + am=n + 4, tz=n + 5) + self._group_index += 5 + elif type == 'ts': + s = r'%s(\s+)(\d+)(\s+)(\d{1,2}:\d{1,2}:\d{1,2})?' % (MONTHS_PAT) + n = self._group_index + self._type_conversions[group] = partial(date_convert, mm=n+1, dd=n+3, + hms=n + 5) + self._group_index += 5 + + elif type: + s = r'\%s+' % type + else: + s = '.+?' + + align = format['align'] + fill = format['fill'] + + # handle some numeric-specific things like fill and sign + if is_numeric: + # prefix with something (align "=" trumps zero) + if align == '=': + # special case - align "=" acts like the zero above but with + # configurable fill defaulting to "0" + if not fill: + fill = '0' + s = '%s*' % fill + s + elif format['zero']: + s = '0*' + s + + # allow numbers to be prefixed with a sign + s = r'[-+ ]?' + s + + if not fill: + fill = ' ' + + # Place into a group now - this captures the value we want to keep. + # Everything else from now is just padding to be stripped off + if wrap: + s = wrap % s + self._group_index += 1 + + if format['width']: + # all we really care about is that if the format originally + # specified a width then there will probably be padding - without + # an explicit alignment that'll mean right alignment with spaces + # padding + if not align: + align = '>' + + if fill in '.\+?*[](){}^$': + fill = '\\' + fill + + # align "=" has been handled + if align == '<': + s = '%s%s*' % (s, fill) + elif align == '>': + s = '%s*%s' % (fill, s) + elif align == '^': + s = '%s*%s%s*' % (fill, s, fill) + + return s + + +class Result(object): + '''The result of a parse() or search(). + + Fixed results may be looked up using result[index]. Named results may be + looked up using result['name']. + ''' + def __init__(self, fixed, named, spans): + self.fixed = fixed + self.named = named + self.spans = spans + + def __getitem__(self, item): + if isinstance(item, int): + return self.fixed[item] + return self.named[item] + + def __repr__(self): + return '<%s %r %r>' % (self.__class__.__name__, self.fixed, + self.named) + + +class Match(object): + '''The result of a parse() or search() if no results are generated. + + This class is only used to expose internal used regex match objects + to the user and use them for external Parser.evaluate_result calls. + ''' + def __init__(self, parser, match): + self.parser = parser + self.match = match + + def evaluate_result(self): + '''Generate results for this Match''' + return self.parser.evaluate_result(self.match) + + +class ResultIterator(object): + '''The result of a findall() operation. + + Each element is a Result instance. + ''' + def __init__(self, parser, string, pos, endpos, evaluate_result=True): + self.parser = parser + self.string = string + self.pos = pos + self.endpos = endpos + self.evaluate_result = evaluate_result + + def __iter__(self): + return self + + def __next__(self): + m = self.parser._search_re.search(self.string, self.pos, self.endpos) + if m is None: + raise StopIteration() + self.pos = m.end() + + if self.evaluate_result: + return self.parser.evaluate_result(m) + else: + return Match(self.parser, m) + + # pre-py3k compat + next = __next__ + + +def parse(format, string, extra_types={}, evaluate_result=True): + '''Using "format" attempt to pull values from "string". + + The format must match the string contents exactly. If the value + you're looking for is instead just a part of the string use + search(). + + If ``evaluate_result`` is True the return value will be an Result instance with two attributes: + + .fixed - tuple of fixed-position values from the string + .named - dict of named values from the string + + If ``evaluate_result`` is False the return value will be a Match instance with one method: + + .evaluate_result() - This will return a Result instance like you would get + with ``evaluate_result`` set to True + + If the format is invalid a ValueError will be raised. + + See the module documentation for the use of "extra_types". + + In the case there is no match parse() will return None. + ''' + return Parser(format, extra_types=extra_types).parse(string, evaluate_result=evaluate_result) + + +def search(format, string, pos=0, endpos=None, extra_types={}, evaluate_result=True): + '''Search "string" for the first occurance of "format". + + The format may occur anywhere within the string. If + instead you wish for the format to exactly match the string + use parse(). + + Optionally start the search at "pos" character index and limit the search + to a maximum index of endpos - equivalent to search(string[:endpos]). + + If ``evaluate_result`` is True the return value will be an Result instance with two attributes: + + .fixed - tuple of fixed-position values from the string + .named - dict of named values from the string + + If ``evaluate_result`` is False the return value will be a Match instance with one method: + + .evaluate_result() - This will return a Result instance like you would get + with ``evaluate_result`` set to True + + If the format is invalid a ValueError will be raised. + + See the module documentation for the use of "extra_types". + + In the case there is no match parse() will return None. + ''' + return Parser(format, extra_types=extra_types).search(string, pos, endpos, evaluate_result=evaluate_result) + + +def findall(format, string, pos=0, endpos=None, extra_types={}, evaluate_result=True): + '''Search "string" for the all occurrances of "format". + + You will be returned an iterator that holds Result instances + for each format match found. + + Optionally start the search at "pos" character index and limit the search + to a maximum index of endpos - equivalent to search(string[:endpos]). + + If ``evaluate_result`` is True each returned Result instance has two attributes: + + .fixed - tuple of fixed-position values from the string + .named - dict of named values from the string + + If ``evaluate_result`` is False each returned value is a Match instance with one method: + + .evaluate_result() - This will return a Result instance like you would get + with ``evaluate_result`` set to True + + If the format is invalid a ValueError will be raised. + + See the module documentation for the use of "extra_types". + ''' + return Parser(format, extra_types=extra_types).findall(string, pos, endpos, evaluate_result=evaluate_result) + + +def compile(format, extra_types={}): + '''Create a Parser instance to parse "format". + + The resultant Parser has a method .parse(string) which + behaves in the same manner as parse(format, string). + + Use this function if you intend to parse many strings + with the same format. + + See the module documentation for the use of "extra_types". + + Returns a Parser instance. + ''' + return Parser(format, extra_types=extra_types) + + +# Copyright (c) 2012-2013 Richard Jones +# +# 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. + +# vim: set filetype=python ts=4 sw=4 et si tw=75 diff --git a/pipenv/vendor/pathlib.py b/pipenv/vendor/pathlib.py new file mode 100644 index 00000000..9ab0e703 --- /dev/null +++ b/pipenv/vendor/pathlib.py @@ -0,0 +1,1280 @@ +import fnmatch +import functools +import io +import ntpath +import os +import posixpath +import re +import sys +import time +from collections import Sequence +from contextlib import contextmanager +from errno import EINVAL, ENOENT +from operator import attrgetter +from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO +try: + from urllib import quote as urlquote, quote as urlquote_from_bytes +except ImportError: + from urllib.parse import quote as urlquote, quote_from_bytes as urlquote_from_bytes + + +try: + intern = intern +except NameError: + intern = sys.intern +try: + basestring = basestring +except NameError: + basestring = str + +supports_symlinks = True +try: + import nt +except ImportError: + nt = None +else: + if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2): + from nt import _getfinalpathname + else: + supports_symlinks = False + _getfinalpathname = None + + +__all__ = [ + "PurePath", "PurePosixPath", "PureWindowsPath", + "Path", "PosixPath", "WindowsPath", + ] + +# +# Internals +# + +_py2 = sys.version_info < (3,) +_py2_fs_encoding = 'ascii' + +def _py2_fsencode(parts): + # py2 => minimal unicode support + return [part.encode(_py2_fs_encoding) if isinstance(part, unicode) + else part for part in parts] + +def _is_wildcard_pattern(pat): + # Whether this pattern needs actual matching using fnmatch, or can + # be looked up directly as a file. + return "*" in pat or "?" in pat or "[" in pat + + +class _Flavour(object): + """A flavour implements a particular (platform-specific) set of path + semantics.""" + + def __init__(self): + self.join = self.sep.join + + def parse_parts(self, parts): + if _py2: + parts = _py2_fsencode(parts) + parsed = [] + sep = self.sep + altsep = self.altsep + drv = root = '' + it = reversed(parts) + for part in it: + if not part: + continue + if altsep: + part = part.replace(altsep, sep) + drv, root, rel = self.splitroot(part) + if sep in rel: + for x in reversed(rel.split(sep)): + if x and x != '.': + parsed.append(intern(x)) + else: + if rel and rel != '.': + parsed.append(intern(rel)) + if drv or root: + if not drv: + # If no drive is present, try to find one in the previous + # parts. This makes the result of parsing e.g. + # ("C:", "/", "a") reasonably intuitive. + for part in it: + drv = self.splitroot(part)[0] + if drv: + break + break + if drv or root: + parsed.append(drv + root) + parsed.reverse() + return drv, root, parsed + + def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2): + """ + Join the two paths represented by the respective + (drive, root, parts) tuples. Return a new (drive, root, parts) tuple. + """ + if root2: + if not drv2 and drv: + return drv, root2, [drv + root2] + parts2[1:] + elif drv2: + if drv2 == drv or self.casefold(drv2) == self.casefold(drv): + # Same drive => second path is relative to the first + return drv, root, parts + parts2[1:] + else: + # Second path is non-anchored (common case) + return drv, root, parts + parts2 + return drv2, root2, parts2 + + +class _WindowsFlavour(_Flavour): + # Reference for Windows paths can be found at + # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + + sep = '\\' + altsep = '/' + has_drv = True + pathmod = ntpath + + is_supported = (nt is not None) + + drive_letters = ( + set(chr(x) for x in range(ord('a'), ord('z') + 1)) | + set(chr(x) for x in range(ord('A'), ord('Z') + 1)) + ) + ext_namespace_prefix = '\\\\?\\' + + reserved_names = ( + set(['CON', 'PRN', 'AUX', 'NUL']) | + set(['COM%d' % i for i in range(1, 10)]) | + set(['LPT%d' % i for i in range(1, 10)]) + ) + + # Interesting findings about extended paths: + # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported + # but '\\?\c:/a' is not + # - extended paths are always absolute; "relative" extended paths will + # fail. + + def splitroot(self, part, sep=sep): + first = part[0:1] + second = part[1:2] + if (second == sep and first == sep): + # XXX extended paths should also disable the collapsing of "." + # components (according to MSDN docs). + prefix, part = self._split_extended_path(part) + first = part[0:1] + second = part[1:2] + else: + prefix = '' + third = part[2:3] + if (second == sep and first == sep and third != sep): + # is a UNC path: + # vvvvvvvvvvvvvvvvvvvvv root + # \\machine\mountpoint\directory\etc\... + # directory ^^^^^^^^^^^^^^ + index = part.find(sep, 2) + if index != -1: + index2 = part.find(sep, index + 1) + # a UNC path can't have two slashes in a row + # (after the initial two) + if index2 != index + 1: + if index2 == -1: + index2 = len(part) + if prefix: + return prefix + part[1:index2], sep, part[index2+1:] + else: + return part[:index2], sep, part[index2+1:] + drv = root = '' + if second == ':' and first in self.drive_letters: + drv = part[:2] + part = part[2:] + first = third + if first == sep: + root = first + part = part.lstrip(sep) + return prefix + drv, root, part + + def casefold(self, s): + return s.lower() + + def casefold_parts(self, parts): + return [p.lower() for p in parts] + + def resolve(self, path): + s = str(path) + if not s: + return os.getcwd() + if _getfinalpathname is not None: + return self._ext_to_normal(_getfinalpathname(s)) + # Means fallback on absolute + return None + + def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix): + prefix = '' + if s.startswith(ext_prefix): + prefix = s[:4] + s = s[4:] + if s.startswith('UNC\\'): + prefix += s[:3] + s = '\\' + s[3:] + return prefix, s + + def _ext_to_normal(self, s): + # Turn back an extended path into a normal DOS-like path + return self._split_extended_path(s)[1] + + def is_reserved(self, parts): + # NOTE: the rules for reserved names seem somewhat complicated + # (e.g. r"..\NUL" is reserved but not r"foo\NUL"). + # We err on the side of caution and return True for paths which are + # not considered reserved by Windows. + if not parts: + return False + if parts[0].startswith('\\\\'): + # UNC paths are never reserved + return False + return parts[-1].partition('.')[0].upper() in self.reserved_names + + def make_uri(self, path): + # Under Windows, file URIs use the UTF-8 encoding. + drive = path.drive + if len(drive) == 2 and drive[1] == ':': + # It's a path on a local drive => 'file:///c:/a/b' + rest = path.as_posix()[2:].lstrip('/') + return 'file:///%s/%s' % ( + drive, urlquote_from_bytes(rest.encode('utf-8'))) + else: + # It's a path on a network drive => 'file://host/share/a/b' + return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8')) + + +class _PosixFlavour(_Flavour): + sep = '/' + altsep = '' + has_drv = False + pathmod = posixpath + + is_supported = (os.name != 'nt') + + def splitroot(self, part, sep=sep): + if part and part[0] == sep: + stripped_part = part.lstrip(sep) + # According to POSIX path resolution: + # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11 + # "A pathname that begins with two successive slashes may be + # interpreted in an implementation-defined manner, although more + # than two leading slashes shall be treated as a single slash". + if len(part) - len(stripped_part) == 2: + return '', sep * 2, stripped_part + else: + return '', sep, stripped_part + else: + return '', '', part + + def casefold(self, s): + return s + + def casefold_parts(self, parts): + return parts + + def resolve(self, path): + sep = self.sep + accessor = path._accessor + seen = {} + def _resolve(path, rest): + if rest.startswith(sep): + path = '' + + for name in rest.split(sep): + if not name or name == '.': + # current dir + continue + if name == '..': + # parent dir + path, _, _ = path.rpartition(sep) + continue + newpath = path + sep + name + if newpath in seen: + # Already seen this path + path = seen[newpath] + if path is not None: + # use cached value + continue + # The symlink is not resolved, so we must have a symlink loop. + raise RuntimeError("Symlink loop from %r" % newpath) + # Resolve the symbolic link + try: + target = accessor.readlink(newpath) + except OSError as e: + if e.errno != EINVAL: + raise + # Not a symlink + path = newpath + else: + seen[newpath] = None # not resolved symlink + path = _resolve(path, target) + seen[newpath] = path # resolved symlink + + return path + # NOTE: according to POSIX, getcwd() cannot contain path components + # which are symlinks. + base = '' if path.is_absolute() else os.getcwd() + return _resolve(base, str(path)) or sep + + def is_reserved(self, parts): + return False + + def make_uri(self, path): + # We represent the path using the local filesystem encoding, + # for portability to other applications. + bpath = bytes(path) + return 'file://' + urlquote_from_bytes(bpath) + + +_windows_flavour = _WindowsFlavour() +_posix_flavour = _PosixFlavour() + + +class _Accessor: + """An accessor implements a particular (system-specific or not) way of + accessing paths on the filesystem.""" + + +class _NormalAccessor(_Accessor): + + def _wrap_strfunc(strfunc): + @functools.wraps(strfunc) + def wrapped(pathobj, *args): + return strfunc(str(pathobj), *args) + return staticmethod(wrapped) + + def _wrap_binary_strfunc(strfunc): + @functools.wraps(strfunc) + def wrapped(pathobjA, pathobjB, *args): + return strfunc(str(pathobjA), str(pathobjB), *args) + return staticmethod(wrapped) + + stat = _wrap_strfunc(os.stat) + + lstat = _wrap_strfunc(os.lstat) + + open = _wrap_strfunc(os.open) + + listdir = _wrap_strfunc(os.listdir) + + chmod = _wrap_strfunc(os.chmod) + + if hasattr(os, "lchmod"): + lchmod = _wrap_strfunc(os.lchmod) + else: + def lchmod(self, pathobj, mode): + raise NotImplementedError("lchmod() not available on this system") + + mkdir = _wrap_strfunc(os.mkdir) + + unlink = _wrap_strfunc(os.unlink) + + rmdir = _wrap_strfunc(os.rmdir) + + rename = _wrap_binary_strfunc(os.rename) + + if sys.version_info >= (3, 3): + replace = _wrap_binary_strfunc(os.replace) + + if nt: + if supports_symlinks: + symlink = _wrap_binary_strfunc(os.symlink) + else: + def symlink(a, b, target_is_directory): + raise NotImplementedError("symlink() not available on this system") + else: + # Under POSIX, os.symlink() takes two args + @staticmethod + def symlink(a, b, target_is_directory): + return os.symlink(str(a), str(b)) + + utime = _wrap_strfunc(os.utime) + + # Helper for resolve() + def readlink(self, path): + return os.readlink(path) + + +_normal_accessor = _NormalAccessor() + + +# +# Globbing helpers +# + +@contextmanager +def _cached(func): + try: + func.__cached__ + yield func + except AttributeError: + cache = {} + def wrapper(*args): + try: + return cache[args] + except KeyError: + value = cache[args] = func(*args) + return value + wrapper.__cached__ = True + try: + yield wrapper + finally: + cache.clear() + +def _make_selector(pattern_parts): + pat = pattern_parts[0] + child_parts = pattern_parts[1:] + if pat == '**': + cls = _RecursiveWildcardSelector + elif '**' in pat: + raise ValueError("Invalid pattern: '**' can only be an entire path component") + elif _is_wildcard_pattern(pat): + cls = _WildcardSelector + else: + cls = _PreciseSelector + return cls(pat, child_parts) + +if hasattr(functools, "lru_cache"): + _make_selector = functools.lru_cache()(_make_selector) + + +class _Selector: + """A selector matches a specific glob pattern part against the children + of a given path.""" + + def __init__(self, child_parts): + self.child_parts = child_parts + if child_parts: + self.successor = _make_selector(child_parts) + else: + self.successor = _TerminatingSelector() + + def select_from(self, parent_path): + """Iterate over all child paths of `parent_path` matched by this + selector. This can contain parent_path itself.""" + path_cls = type(parent_path) + is_dir = path_cls.is_dir + exists = path_cls.exists + listdir = parent_path._accessor.listdir + return self._select_from(parent_path, is_dir, exists, listdir) + + +class _TerminatingSelector: + + def _select_from(self, parent_path, is_dir, exists, listdir): + yield parent_path + + +class _PreciseSelector(_Selector): + + def __init__(self, name, child_parts): + self.name = name + _Selector.__init__(self, child_parts) + + def _select_from(self, parent_path, is_dir, exists, listdir): + if not is_dir(parent_path): + return + path = parent_path._make_child_relpath(self.name) + if exists(path): + for p in self.successor._select_from(path, is_dir, exists, listdir): + yield p + + +class _WildcardSelector(_Selector): + + def __init__(self, pat, child_parts): + self.pat = re.compile(fnmatch.translate(pat)) + _Selector.__init__(self, child_parts) + + def _select_from(self, parent_path, is_dir, exists, listdir): + if not is_dir(parent_path): + return + cf = parent_path._flavour.casefold + for name in listdir(parent_path): + casefolded = cf(name) + if self.pat.match(casefolded): + path = parent_path._make_child_relpath(name) + for p in self.successor._select_from(path, is_dir, exists, listdir): + yield p + + +class _RecursiveWildcardSelector(_Selector): + + def __init__(self, pat, child_parts): + _Selector.__init__(self, child_parts) + + def _iterate_directories(self, parent_path, is_dir, listdir): + yield parent_path + for name in listdir(parent_path): + path = parent_path._make_child_relpath(name) + if is_dir(path): + for p in self._iterate_directories(path, is_dir, listdir): + yield p + + def _select_from(self, parent_path, is_dir, exists, listdir): + if not is_dir(parent_path): + return + with _cached(listdir) as listdir: + yielded = set() + try: + successor_select = self.successor._select_from + for starting_point in self._iterate_directories(parent_path, is_dir, listdir): + for p in successor_select(starting_point, is_dir, exists, listdir): + if p not in yielded: + yield p + yielded.add(p) + finally: + yielded.clear() + + +# +# Public API +# + +class _PathParents(Sequence): + """This object provides sequence-like access to the logical ancestors + of a path. Don't try to construct it yourself.""" + __slots__ = ('_pathcls', '_drv', '_root', '_parts') + + def __init__(self, path): + # We don't store the instance to avoid reference cycles + self._pathcls = type(path) + self._drv = path._drv + self._root = path._root + self._parts = path._parts + + def __len__(self): + if self._drv or self._root: + return len(self._parts) - 1 + else: + return len(self._parts) + + def __getitem__(self, idx): + if idx < 0 or idx >= len(self): + raise IndexError(idx) + return self._pathcls._from_parsed_parts(self._drv, self._root, + self._parts[:-idx - 1]) + + def __repr__(self): + return "<{0}.parents>".format(self._pathcls.__name__) + + +class PurePath(object): + """PurePath represents a filesystem path and offers operations which + don't imply any actual filesystem I/O. Depending on your system, + instantiating a PurePath will return either a PurePosixPath or a + PureWindowsPath object. You can also instantiate either of these classes + directly, regardless of your system. + """ + __slots__ = ( + '_drv', '_root', '_parts', + '_str', '_hash', '_pparts', '_cached_cparts', + ) + + def __new__(cls, *args): + """Construct a PurePath from one or several strings and or existing + PurePath objects. The strings and path objects are combined so as + to yield a canonicalized path, which is incorporated into the + new PurePath object. + """ + if cls is PurePath: + cls = PureWindowsPath if os.name == 'nt' else PurePosixPath + return cls._from_parts(args) + + def __reduce__(self): + # Using the parts tuple helps share interned path parts + # when pickling related paths. + return (self.__class__, tuple(self._parts)) + + @classmethod + def _parse_args(cls, args): + # This is useful when you don't want to create an instance, just + # canonicalize some constructor arguments. + parts = [] + for a in args: + if isinstance(a, PurePath): + parts += a._parts + elif isinstance(a, basestring): + parts.append(a) + else: + raise TypeError( + "argument should be a path or str object, not %r" + % type(a)) + return cls._flavour.parse_parts(parts) + + @classmethod + def _from_parts(cls, args, init=True): + # We need to call _parse_args on the instance, so as to get the + # right flavour. + self = object.__new__(cls) + drv, root, parts = self._parse_args(args) + self._drv = drv + self._root = root + self._parts = parts + if init: + self._init() + return self + + @classmethod + def _from_parsed_parts(cls, drv, root, parts, init=True): + self = object.__new__(cls) + self._drv = drv + self._root = root + self._parts = parts + if init: + self._init() + return self + + @classmethod + def _format_parsed_parts(cls, drv, root, parts): + if drv or root: + return drv + root + cls._flavour.join(parts[1:]) + else: + return cls._flavour.join(parts) + + def _init(self): + # Overriden in concrete Path + pass + + def _make_child(self, args): + drv, root, parts = self._parse_args(args) + drv, root, parts = self._flavour.join_parsed_parts( + self._drv, self._root, self._parts, drv, root, parts) + return self._from_parsed_parts(drv, root, parts) + + def __str__(self): + """Return the string representation of the path, suitable for + passing to system calls.""" + try: + return self._str + except AttributeError: + self._str = self._format_parsed_parts(self._drv, self._root, + self._parts) or '.' + return self._str + + def as_posix(self): + """Return the string representation of the path with forward (/) + slashes.""" + f = self._flavour + return str(self).replace(f.sep, '/') + + def __bytes__(self): + """Return the bytes representation of the path. This is only + recommended to use under Unix.""" + if sys.version_info < (3, 2): + raise NotImplementedError("needs Python 3.2 or later") + return os.fsencode(str(self)) + + def __repr__(self): + return "{0}({1!r})".format(self.__class__.__name__, self.as_posix()) + + def as_uri(self): + """Return the path as a 'file' URI.""" + if not self.is_absolute(): + raise ValueError("relative path can't be expressed as a file URI") + return self._flavour.make_uri(self) + + @property + def _cparts(self): + # Cached casefolded parts, for hashing and comparison + try: + return self._cached_cparts + except AttributeError: + self._cached_cparts = self._flavour.casefold_parts(self._parts) + return self._cached_cparts + + def __eq__(self, other): + if not isinstance(other, PurePath): + return NotImplemented + return self._cparts == other._cparts and self._flavour is other._flavour + + def __ne__(self, other): + return not self == other + + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(tuple(self._cparts)) + return self._hash + + def __lt__(self, other): + if not isinstance(other, PurePath) or self._flavour is not other._flavour: + return NotImplemented + return self._cparts < other._cparts + + def __le__(self, other): + if not isinstance(other, PurePath) or self._flavour is not other._flavour: + return NotImplemented + return self._cparts <= other._cparts + + def __gt__(self, other): + if not isinstance(other, PurePath) or self._flavour is not other._flavour: + return NotImplemented + return self._cparts > other._cparts + + def __ge__(self, other): + if not isinstance(other, PurePath) or self._flavour is not other._flavour: + return NotImplemented + return self._cparts >= other._cparts + + drive = property(attrgetter('_drv'), + doc="""The drive prefix (letter or UNC path), if any.""") + + root = property(attrgetter('_root'), + doc="""The root of the path, if any.""") + + @property + def anchor(self): + """The concatenation of the drive and root, or ''.""" + anchor = self._drv + self._root + return anchor + + @property + def name(self): + """The final path component, if any.""" + parts = self._parts + if len(parts) == (1 if (self._drv or self._root) else 0): + return '' + return parts[-1] + + @property + def suffix(self): + """The final component's last suffix, if any.""" + name = self.name + i = name.rfind('.') + if 0 < i < len(name) - 1: + return name[i:] + else: + return '' + + @property + def suffixes(self): + """A list of the final component's suffixes, if any.""" + name = self.name + if name.endswith('.'): + return [] + name = name.lstrip('.') + return ['.' + suffix for suffix in name.split('.')[1:]] + + @property + def stem(self): + """The final path component, minus its last suffix.""" + name = self.name + i = name.rfind('.') + if 0 < i < len(name) - 1: + return name[:i] + else: + return name + + def with_name(self, name): + """Return a new path with the file name changed.""" + if not self.name: + raise ValueError("%r has an empty name" % (self,)) + return self._from_parsed_parts(self._drv, self._root, + self._parts[:-1] + [name]) + + def with_suffix(self, suffix): + """Return a new path with the file suffix changed (or added, if none).""" + # XXX if suffix is None, should the current suffix be removed? + drv, root, parts = self._flavour.parse_parts((suffix,)) + if drv or root or len(parts) != 1: + raise ValueError("Invalid suffix %r" % (suffix)) + suffix = parts[0] + if not suffix.startswith('.'): + raise ValueError("Invalid suffix %r" % (suffix)) + name = self.name + if not name: + raise ValueError("%r has an empty name" % (self,)) + old_suffix = self.suffix + if not old_suffix: + name = name + suffix + else: + name = name[:-len(old_suffix)] + suffix + return self._from_parsed_parts(self._drv, self._root, + self._parts[:-1] + [name]) + + def relative_to(self, *other): + """Return the relative path to another path identified by the passed + arguments. If the operation is not possible (because this is not + a subpath of the other path), raise ValueError. + """ + # For the purpose of this method, drive and root are considered + # separate parts, i.e.: + # Path('c:/').relative_to('c:') gives Path('/') + # Path('c:/').relative_to('/') raise ValueError + if not other: + raise TypeError("need at least one argument") + parts = self._parts + drv = self._drv + root = self._root + if root: + abs_parts = [drv, root] + parts[1:] + else: + abs_parts = parts + to_drv, to_root, to_parts = self._parse_args(other) + if to_root: + to_abs_parts = [to_drv, to_root] + to_parts[1:] + else: + to_abs_parts = to_parts + n = len(to_abs_parts) + cf = self._flavour.casefold_parts + if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts): + formatted = self._format_parsed_parts(to_drv, to_root, to_parts) + raise ValueError("{!r} does not start with {!r}" + .format(str(self), str(formatted))) + return self._from_parsed_parts('', root if n == 1 else '', + abs_parts[n:]) + + @property + def parts(self): + """An object providing sequence-like access to the + components in the filesystem path.""" + # We cache the tuple to avoid building a new one each time .parts + # is accessed. XXX is this necessary? + try: + return self._pparts + except AttributeError: + self._pparts = tuple(self._parts) + return self._pparts + + def joinpath(self, *args): + """Combine this path with one or several arguments, and return a + new path representing either a subpath (if all arguments are relative + paths) or a totally different path (if one of the arguments is + anchored). + """ + return self._make_child(args) + + def __truediv__(self, key): + return self._make_child((key,)) + + def __rtruediv__(self, key): + return self._from_parts([key] + self._parts) + + if sys.version_info < (3,): + __div__ = __truediv__ + __rdiv__ = __rtruediv__ + + @property + def parent(self): + """The logical parent of the path.""" + drv = self._drv + root = self._root + parts = self._parts + if len(parts) == 1 and (drv or root): + return self + return self._from_parsed_parts(drv, root, parts[:-1]) + + @property + def parents(self): + """A sequence of this path's logical parents.""" + return _PathParents(self) + + def is_absolute(self): + """True if the path is absolute (has both a root and, if applicable, + a drive).""" + if not self._root: + return False + return not self._flavour.has_drv or bool(self._drv) + + def is_reserved(self): + """Return True if the path contains one of the special names reserved + by the system, if any.""" + return self._flavour.is_reserved(self._parts) + + def match(self, path_pattern): + """ + Return True if this path matches the given pattern. + """ + cf = self._flavour.casefold + path_pattern = cf(path_pattern) + drv, root, pat_parts = self._flavour.parse_parts((path_pattern,)) + if not pat_parts: + raise ValueError("empty pattern") + if drv and drv != cf(self._drv): + return False + if root and root != cf(self._root): + return False + parts = self._cparts + if drv or root: + if len(pat_parts) != len(parts): + return False + pat_parts = pat_parts[1:] + elif len(pat_parts) > len(parts): + return False + for part, pat in zip(reversed(parts), reversed(pat_parts)): + if not fnmatch.fnmatchcase(part, pat): + return False + return True + + +class PurePosixPath(PurePath): + _flavour = _posix_flavour + __slots__ = () + + +class PureWindowsPath(PurePath): + _flavour = _windows_flavour + __slots__ = () + + +# Filesystem-accessing classes + + +class Path(PurePath): + __slots__ = ( + '_accessor', + ) + + def __new__(cls, *args, **kwargs): + if cls is Path: + cls = WindowsPath if os.name == 'nt' else PosixPath + self = cls._from_parts(args, init=False) + if not self._flavour.is_supported: + raise NotImplementedError("cannot instantiate %r on your system" + % (cls.__name__,)) + self._init() + return self + + def _init(self, + # Private non-constructor arguments + template=None, + ): + if template is not None: + self._accessor = template._accessor + else: + self._accessor = _normal_accessor + + def _make_child_relpath(self, part): + # This is an optimization used for dir walking. `part` must be + # a single part relative to this path. + parts = self._parts + [part] + return self._from_parsed_parts(self._drv, self._root, parts) + + def _opener(self, name, flags, mode=0o666): + # A stub for the opener argument to built-in open() + return self._accessor.open(self, flags, mode) + + def _raw_open(self, flags, mode=0o777): + """ + Open the file pointed by this path and return a file descriptor, + as os.open() does. + """ + return self._accessor.open(self, flags, mode) + + # Public API + + @classmethod + def cwd(cls): + """Return a new path pointing to the current working directory + (as returned by os.getcwd()). + """ + return cls(os.getcwd()) + + def iterdir(self): + """Iterate over the files in this directory. Does not yield any + result for the special paths '.' and '..'. + """ + for name in self._accessor.listdir(self): + if name in ('.', '..'): + # Yielding a path object for these makes little sense + continue + yield self._make_child_relpath(name) + + def glob(self, pattern): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given pattern. + """ + pattern = self._flavour.casefold(pattern) + drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) + if drv or root: + raise NotImplementedError("Non-relative patterns are unsupported") + selector = _make_selector(tuple(pattern_parts)) + for p in selector.select_from(self): + yield p + + def rglob(self, pattern): + """Recursively yield all existing files (of any kind, including + directories) matching the given pattern, anywhere in this subtree. + """ + pattern = self._flavour.casefold(pattern) + drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) + if drv or root: + raise NotImplementedError("Non-relative patterns are unsupported") + selector = _make_selector(("**",) + tuple(pattern_parts)) + for p in selector.select_from(self): + yield p + + def absolute(self): + """Return an absolute version of this path. This function works + even if the path doesn't point to anything. + + No normalization is done, i.e. all '.' and '..' will be kept along. + Use resolve() to get the canonical path to a file. + """ + # XXX untested yet! + if self.is_absolute(): + return self + # FIXME this must defer to the specific flavour (and, under Windows, + # use nt._getfullpathname()) + obj = self._from_parts([os.getcwd()] + self._parts, init=False) + obj._init(template=self) + return obj + + def resolve(self): + """ + Make the path absolute, resolving all symlinks on the way and also + normalizing it (for example turning slashes into backslashes under + Windows). + """ + s = self._flavour.resolve(self) + if s is None: + # No symlink resolution => for consistency, raise an error if + # the path doesn't exist or is forbidden + self.stat() + s = str(self.absolute()) + # Now we have no symlinks in the path, it's safe to normalize it. + normed = self._flavour.pathmod.normpath(s) + obj = self._from_parts((normed,), init=False) + obj._init(template=self) + return obj + + def stat(self): + """ + Return the result of the stat() system call on this path, like + os.stat() does. + """ + return self._accessor.stat(self) + + def owner(self): + """ + Return the login name of the file owner. + """ + import pwd + return pwd.getpwuid(self.stat().st_uid).pw_name + + def group(self): + """ + Return the group name of the file gid. + """ + import grp + return grp.getgrgid(self.stat().st_gid).gr_name + + def open(self, mode='r', buffering=-1, encoding=None, + errors=None, newline=None): + """ + Open the file pointed by this path and return a file object, as + the built-in open() function does. + """ + if sys.version_info >= (3, 3): + return io.open(str(self), mode, buffering, encoding, errors, newline, + opener=self._opener) + else: + return io.open(str(self), mode, buffering, encoding, errors, newline) + + def touch(self, mode=0o666, exist_ok=True): + """ + Create this file with the given access mode, if it doesn't exist. + """ + if exist_ok: + # First try to bump modification time + # Implementation note: GNU touch uses the UTIME_NOW option of + # the utimensat() / futimens() functions. + t = time.time() + try: + self._accessor.utime(self, (t, t)) + except OSError: + # Avoid exception chaining + pass + else: + return + flags = os.O_CREAT | os.O_WRONLY + if not exist_ok: + flags |= os.O_EXCL + fd = self._raw_open(flags, mode) + os.close(fd) + + def mkdir(self, mode=0o777, parents=False): + if not parents: + self._accessor.mkdir(self, mode) + else: + try: + self._accessor.mkdir(self, mode) + except OSError as e: + if e.errno != ENOENT: + raise + self.parent.mkdir(parents=True) + self._accessor.mkdir(self, mode) + + def chmod(self, mode): + """ + Change the permissions of the path, like os.chmod(). + """ + self._accessor.chmod(self, mode) + + def lchmod(self, mode): + """ + Like chmod(), except if the path points to a symlink, the symlink's + permissions are changed, rather than its target's. + """ + self._accessor.lchmod(self, mode) + + def unlink(self): + """ + Remove this file or link. + If the path is a directory, use rmdir() instead. + """ + self._accessor.unlink(self) + + def rmdir(self): + """ + Remove this directory. The directory must be empty. + """ + self._accessor.rmdir(self) + + def lstat(self): + """ + Like stat(), except if the path points to a symlink, the symlink's + status information is returned, rather than its target's. + """ + return self._accessor.lstat(self) + + def rename(self, target): + """ + Rename this path to the given path. + """ + self._accessor.rename(self, target) + + def replace(self, target): + """ + Rename this path to the given path, clobbering the existing + destination if it exists. + """ + if sys.version_info < (3, 3): + raise NotImplementedError("replace() is only available " + "with Python 3.3 and later") + self._accessor.replace(self, target) + + def symlink_to(self, target, target_is_directory=False): + """ + Make this path a symlink pointing to the given path. + Note the order of arguments (self, target) is the reverse of os.symlink's. + """ + self._accessor.symlink(target, self, target_is_directory) + + # Convenience functions for querying the stat results + + def exists(self): + """ + Whether this path exists. + """ + try: + self.stat() + except OSError as e: + if e.errno != ENOENT: + raise + return False + return True + + def is_dir(self): + """ + Whether this path is a directory. + """ + try: + return S_ISDIR(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + def is_file(self): + """ + Whether this path is a regular file (also True for symlinks pointing + to regular files). + """ + try: + return S_ISREG(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + def is_symlink(self): + """ + Whether this path is a symbolic link. + """ + try: + return S_ISLNK(self.lstat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist + return False + + def is_block_device(self): + """ + Whether this path is a block device. + """ + try: + return S_ISBLK(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + def is_char_device(self): + """ + Whether this path is a character device. + """ + try: + return S_ISCHR(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + def is_fifo(self): + """ + Whether this path is a FIFO. + """ + try: + return S_ISFIFO(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + def is_socket(self): + """ + Whether this path is a socket. + """ + try: + return S_ISSOCK(self.stat().st_mode) + except OSError as e: + if e.errno != ENOENT: + raise + # Path doesn't exist or is a broken symlink + # (see https://bitbucket.org/pitrou/pathlib/issue/12/) + return False + + +class PosixPath(Path, PurePosixPath): + __slots__ = () + +class WindowsPath(Path, PureWindowsPath): + __slots__ = () + diff --git a/pipenv/vendor/pexpect/ANSI.py b/pipenv/vendor/pexpect/ANSI.py new file mode 100644 index 00000000..1cd2e90e --- /dev/null +++ b/pipenv/vendor/pexpect/ANSI.py @@ -0,0 +1,351 @@ +'''This implements an ANSI (VT100) terminal emulator as a subclass of screen. + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +# references: +# http://en.wikipedia.org/wiki/ANSI_escape_code +# http://www.retards.org/terminals/vt102.html +# http://vt100.net/docs/vt102-ug/contents.html +# http://vt100.net/docs/vt220-rm/ +# http://www.termsys.demon.co.uk/vtansi.htm + +from . import screen +from . import FSM +import string + +# +# The 'Do.*' functions are helper functions for the ANSI class. +# +def DoEmit (fsm): + + screen = fsm.memory[0] + screen.write_ch(fsm.input_symbol) + +def DoStartNumber (fsm): + + fsm.memory.append (fsm.input_symbol) + +def DoBuildNumber (fsm): + + ns = fsm.memory.pop() + ns = ns + fsm.input_symbol + fsm.memory.append (ns) + +def DoBackOne (fsm): + + screen = fsm.memory[0] + screen.cursor_back () + +def DoBack (fsm): + + count = int(fsm.memory.pop()) + screen = fsm.memory[0] + screen.cursor_back (count) + +def DoDownOne (fsm): + + screen = fsm.memory[0] + screen.cursor_down () + +def DoDown (fsm): + + count = int(fsm.memory.pop()) + screen = fsm.memory[0] + screen.cursor_down (count) + +def DoForwardOne (fsm): + + screen = fsm.memory[0] + screen.cursor_forward () + +def DoForward (fsm): + + count = int(fsm.memory.pop()) + screen = fsm.memory[0] + screen.cursor_forward (count) + +def DoUpReverse (fsm): + + screen = fsm.memory[0] + screen.cursor_up_reverse() + +def DoUpOne (fsm): + + screen = fsm.memory[0] + screen.cursor_up () + +def DoUp (fsm): + + count = int(fsm.memory.pop()) + screen = fsm.memory[0] + screen.cursor_up (count) + +def DoHome (fsm): + + c = int(fsm.memory.pop()) + r = int(fsm.memory.pop()) + screen = fsm.memory[0] + screen.cursor_home (r,c) + +def DoHomeOrigin (fsm): + + c = 1 + r = 1 + screen = fsm.memory[0] + screen.cursor_home (r,c) + +def DoEraseDown (fsm): + + screen = fsm.memory[0] + screen.erase_down() + +def DoErase (fsm): + + arg = int(fsm.memory.pop()) + screen = fsm.memory[0] + if arg == 0: + screen.erase_down() + elif arg == 1: + screen.erase_up() + elif arg == 2: + screen.erase_screen() + +def DoEraseEndOfLine (fsm): + + screen = fsm.memory[0] + screen.erase_end_of_line() + +def DoEraseLine (fsm): + + arg = int(fsm.memory.pop()) + screen = fsm.memory[0] + if arg == 0: + screen.erase_end_of_line() + elif arg == 1: + screen.erase_start_of_line() + elif arg == 2: + screen.erase_line() + +def DoEnableScroll (fsm): + + screen = fsm.memory[0] + screen.scroll_screen() + +def DoCursorSave (fsm): + + screen = fsm.memory[0] + screen.cursor_save_attrs() + +def DoCursorRestore (fsm): + + screen = fsm.memory[0] + screen.cursor_restore_attrs() + +def DoScrollRegion (fsm): + + screen = fsm.memory[0] + r2 = int(fsm.memory.pop()) + r1 = int(fsm.memory.pop()) + screen.scroll_screen_rows (r1,r2) + +def DoMode (fsm): + + screen = fsm.memory[0] + mode = fsm.memory.pop() # Should be 4 + # screen.setReplaceMode () + +def DoLog (fsm): + + screen = fsm.memory[0] + fsm.memory = [screen] + fout = open ('log', 'a') + fout.write (fsm.input_symbol + ',' + fsm.current_state + '\n') + fout.close() + +class term (screen.screen): + + '''This class is an abstract, generic terminal. + This does nothing. This is a placeholder that + provides a common base class for other terminals + such as an ANSI terminal. ''' + + def __init__ (self, r=24, c=80, *args, **kwargs): + + screen.screen.__init__(self, r,c,*args,**kwargs) + +class ANSI (term): + '''This class implements an ANSI (VT100) terminal. + It is a stream filter that recognizes ANSI terminal + escape sequences and maintains the state of a screen object. ''' + + def __init__ (self, r=24,c=80,*args,**kwargs): + + term.__init__(self,r,c,*args,**kwargs) + + #self.screen = screen (24,80) + self.state = FSM.FSM ('INIT',[self]) + self.state.set_default_transition (DoLog, 'INIT') + self.state.add_transition_any ('INIT', DoEmit, 'INIT') + self.state.add_transition ('\x1b', 'INIT', None, 'ESC') + self.state.add_transition_any ('ESC', DoLog, 'INIT') + self.state.add_transition ('(', 'ESC', None, 'G0SCS') + self.state.add_transition (')', 'ESC', None, 'G1SCS') + self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT') + self.state.add_transition_list ('AB012', 'G1SCS', None, 'INIT') + self.state.add_transition ('7', 'ESC', DoCursorSave, 'INIT') + self.state.add_transition ('8', 'ESC', DoCursorRestore, 'INIT') + self.state.add_transition ('M', 'ESC', DoUpReverse, 'INIT') + self.state.add_transition ('>', 'ESC', DoUpReverse, 'INIT') + self.state.add_transition ('<', 'ESC', DoUpReverse, 'INIT') + self.state.add_transition ('=', 'ESC', None, 'INIT') # Selects application keypad. + self.state.add_transition ('#', 'ESC', None, 'GRAPHICS_POUND') + self.state.add_transition_any ('GRAPHICS_POUND', None, 'INIT') + self.state.add_transition ('[', 'ESC', None, 'ELB') + # ELB means Escape Left Bracket. That is ^[[ + self.state.add_transition ('H', 'ELB', DoHomeOrigin, 'INIT') + self.state.add_transition ('D', 'ELB', DoBackOne, 'INIT') + self.state.add_transition ('B', 'ELB', DoDownOne, 'INIT') + self.state.add_transition ('C', 'ELB', DoForwardOne, 'INIT') + self.state.add_transition ('A', 'ELB', DoUpOne, 'INIT') + self.state.add_transition ('J', 'ELB', DoEraseDown, 'INIT') + self.state.add_transition ('K', 'ELB', DoEraseEndOfLine, 'INIT') + self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT') + self.state.add_transition ('m', 'ELB', self.do_sgr, 'INIT') + self.state.add_transition ('?', 'ELB', None, 'MODECRAP') + self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1') + self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1') + self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT') + self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT') + self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT') + self.state.add_transition ('A', 'NUMBER_1', DoUp, 'INIT') + self.state.add_transition ('J', 'NUMBER_1', DoErase, 'INIT') + self.state.add_transition ('K', 'NUMBER_1', DoEraseLine, 'INIT') + self.state.add_transition ('l', 'NUMBER_1', DoMode, 'INIT') + ### It gets worse... the 'm' code can have infinite number of + ### number;number;number before it. I've never seen more than two, + ### but the specs say it's allowed. crap! + self.state.add_transition ('m', 'NUMBER_1', self.do_sgr, 'INIT') + ### LED control. Same implementation problem as 'm' code. + self.state.add_transition ('q', 'NUMBER_1', self.do_decsca, 'INIT') + + # \E[?47h switch to alternate screen + # \E[?47l restores to normal screen from alternate screen. + self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM') + self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM') + self.state.add_transition ('l', 'MODECRAP_NUM', self.do_modecrap, 'INIT') + self.state.add_transition ('h', 'MODECRAP_NUM', self.do_modecrap, 'INIT') + +#RM Reset Mode Esc [ Ps l none + self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON') + self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT') + self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2') + self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2') + self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT') + self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT') + self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT') + self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT') + ### It gets worse... the 'm' code can have infinite number of + ### number;number;number before it. I've never seen more than two, + ### but the specs say it's allowed. crap! + self.state.add_transition ('m', 'NUMBER_2', self.do_sgr, 'INIT') + ### LED control. Same problem as 'm' code. + self.state.add_transition ('q', 'NUMBER_2', self.do_decsca, 'INIT') + self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X') + + # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers + self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT') + self.state.add_transition_list (string.digits, 'SEMICOLON_X', DoStartNumber, 'NUMBER_X') + self.state.add_transition_list (string.digits, 'NUMBER_X', DoBuildNumber, 'NUMBER_X') + self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT') + self.state.add_transition ('m', 'NUMBER_X', self.do_sgr, 'INIT') + self.state.add_transition ('q', 'NUMBER_X', self.do_decsca, 'INIT') + self.state.add_transition (';', 'NUMBER_X', None, 'SEMICOLON_X') + + def process (self, c): + """Process a single character. Called by :meth:`write`.""" + if isinstance(c, bytes): + c = self._decode(c) + self.state.process(c) + + def process_list (self, l): + + self.write(l) + + def write (self, s): + """Process text, writing it to the virtual screen while handling + ANSI escape codes. + """ + if isinstance(s, bytes): + s = self._decode(s) + for c in s: + self.process(c) + + def flush (self): + pass + + def write_ch (self, ch): + '''This puts a character at the current cursor position. The cursor + position is moved forward with wrap-around, but no scrolling is done if + the cursor hits the lower-right corner of the screen. ''' + + if isinstance(ch, bytes): + ch = self._decode(ch) + + #\r and \n both produce a call to cr() and lf(), respectively. + ch = ch[0] + + if ch == u'\r': + self.cr() + return + if ch == u'\n': + self.crlf() + return + if ch == chr(screen.BS): + self.cursor_back() + return + self.put_abs(self.cur_r, self.cur_c, ch) + old_r = self.cur_r + old_c = self.cur_c + self.cursor_forward() + if old_c == self.cur_c: + self.cursor_down() + if old_r != self.cur_r: + self.cursor_home (self.cur_r, 1) + else: + self.scroll_up () + self.cursor_home (self.cur_r, 1) + self.erase_line() + + def do_sgr (self, fsm): + '''Select Graphic Rendition, e.g. color. ''' + screen = fsm.memory[0] + fsm.memory = [screen] + + def do_decsca (self, fsm): + '''Select character protection attribute. ''' + screen = fsm.memory[0] + fsm.memory = [screen] + + def do_modecrap (self, fsm): + '''Handler for \x1b[?h and \x1b[?l. If anyone + wanted to actually use these, they'd need to add more states to the + FSM rather than just improve or override this method. ''' + screen = fsm.memory[0] + fsm.memory = [screen] diff --git a/pipenv/vendor/pexpect/FSM.py b/pipenv/vendor/pexpect/FSM.py new file mode 100644 index 00000000..46b392ea --- /dev/null +++ b/pipenv/vendor/pexpect/FSM.py @@ -0,0 +1,334 @@ +#!/usr/bin/env python + +'''This module implements a Finite State Machine (FSM). In addition to state +this FSM also maintains a user defined "memory". So this FSM can be used as a +Push-down Automata (PDA) since a PDA is a FSM + memory. + +The following describes how the FSM works, but you will probably also need to +see the example function to understand how the FSM is used in practice. + +You define an FSM by building tables of transitions. For a given input symbol +the process() method uses these tables to decide what action to call and what +the next state will be. The FSM has a table of transitions that associate: + + (input_symbol, current_state) --> (action, next_state) + +Where "action" is a function you define. The symbols and states can be any +objects. You use the add_transition() and add_transition_list() methods to add +to the transition table. The FSM also has a table of transitions that +associate: + + (current_state) --> (action, next_state) + +You use the add_transition_any() method to add to this transition table. The +FSM also has one default transition that is not associated with any specific +input_symbol or state. You use the set_default_transition() method to set the +default transition. + +When an action function is called it is passed a reference to the FSM. The +action function may then access attributes of the FSM such as input_symbol, +current_state, or "memory". The "memory" attribute can be any object that you +want to pass along to the action functions. It is not used by the FSM itself. +For parsing you would typically pass a list to be used as a stack. + +The processing sequence is as follows. The process() method is given an +input_symbol to process. The FSM will search the table of transitions that +associate: + + (input_symbol, current_state) --> (action, next_state) + +If the pair (input_symbol, current_state) is found then process() will call the +associated action function and then set the current state to the next_state. + +If the FSM cannot find a match for (input_symbol, current_state) it will then +search the table of transitions that associate: + + (current_state) --> (action, next_state) + +If the current_state is found then the process() method will call the +associated action function and then set the current state to the next_state. +Notice that this table lacks an input_symbol. It lets you define transitions +for a current_state and ANY input_symbol. Hence, it is called the "any" table. +Remember, it is always checked after first searching the table for a specific +(input_symbol, current_state). + +For the case where the FSM did not match either of the previous two cases the +FSM will try to use the default transition. If the default transition is +defined then the process() method will call the associated action function and +then set the current state to the next_state. This lets you define a default +transition as a catch-all case. You can think of it as an exception handler. +There can be only one default transition. + +Finally, if none of the previous cases are defined for an input_symbol and +current_state then the FSM will raise an exception. This may be desirable, but +you can always prevent this just by defining a default transition. + +Noah Spurrier 20020822 + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +class ExceptionFSM(Exception): + + '''This is the FSM Exception class.''' + + def __init__(self, value): + self.value = value + + def __str__(self): + return 'ExceptionFSM: ' + str(self.value) + +class FSM: + + '''This is a Finite State Machine (FSM). + ''' + + def __init__(self, initial_state, memory=None): + + '''This creates the FSM. You set the initial state here. The "memory" + attribute is any object that you want to pass along to the action + functions. It is not used by the FSM. For parsing you would typically + pass a list to be used as a stack. ''' + + # Map (input_symbol, current_state) --> (action, next_state). + self.state_transitions = {} + # Map (current_state) --> (action, next_state). + self.state_transitions_any = {} + self.default_transition = None + + self.input_symbol = None + self.initial_state = initial_state + self.current_state = self.initial_state + self.next_state = None + self.action = None + self.memory = memory + + def reset (self): + + '''This sets the current_state to the initial_state and sets + input_symbol to None. The initial state was set by the constructor + __init__(). ''' + + self.current_state = self.initial_state + self.input_symbol = None + + def add_transition (self, input_symbol, state, action=None, next_state=None): + + '''This adds a transition that associates: + + (input_symbol, current_state) --> (action, next_state) + + The action may be set to None in which case the process() method will + ignore the action and only set the next_state. The next_state may be + set to None in which case the current state will be unchanged. + + You can also set transitions for a list of symbols by using + add_transition_list(). ''' + + if next_state is None: + next_state = state + self.state_transitions[(input_symbol, state)] = (action, next_state) + + def add_transition_list (self, list_input_symbols, state, action=None, next_state=None): + + '''This adds the same transition for a list of input symbols. + You can pass a list or a string. Note that it is handy to use + string.digits, string.whitespace, string.letters, etc. to add + transitions that match character classes. + + The action may be set to None in which case the process() method will + ignore the action and only set the next_state. The next_state may be + set to None in which case the current state will be unchanged. ''' + + if next_state is None: + next_state = state + for input_symbol in list_input_symbols: + self.add_transition (input_symbol, state, action, next_state) + + def add_transition_any (self, state, action=None, next_state=None): + + '''This adds a transition that associates: + + (current_state) --> (action, next_state) + + That is, any input symbol will match the current state. + The process() method checks the "any" state associations after it first + checks for an exact match of (input_symbol, current_state). + + The action may be set to None in which case the process() method will + ignore the action and only set the next_state. The next_state may be + set to None in which case the current state will be unchanged. ''' + + if next_state is None: + next_state = state + self.state_transitions_any [state] = (action, next_state) + + def set_default_transition (self, action, next_state): + + '''This sets the default transition. This defines an action and + next_state if the FSM cannot find the input symbol and the current + state in the transition list and if the FSM cannot find the + current_state in the transition_any list. This is useful as a final + fall-through state for catching errors and undefined states. + + The default transition can be removed by setting the attribute + default_transition to None. ''' + + self.default_transition = (action, next_state) + + def get_transition (self, input_symbol, state): + + '''This returns (action, next state) given an input_symbol and state. + This does not modify the FSM state, so calling this method has no side + effects. Normally you do not call this method directly. It is called by + process(). + + The sequence of steps to check for a defined transition goes from the + most specific to the least specific. + + 1. Check state_transitions[] that match exactly the tuple, + (input_symbol, state) + + 2. Check state_transitions_any[] that match (state) + In other words, match a specific state and ANY input_symbol. + + 3. Check if the default_transition is defined. + This catches any input_symbol and any state. + This is a handler for errors, undefined states, or defaults. + + 4. No transition was defined. If we get here then raise an exception. + ''' + + if (input_symbol, state) in self.state_transitions: + return self.state_transitions[(input_symbol, state)] + elif state in self.state_transitions_any: + return self.state_transitions_any[state] + elif self.default_transition is not None: + return self.default_transition + else: + raise ExceptionFSM ('Transition is undefined: (%s, %s).' % + (str(input_symbol), str(state)) ) + + def process (self, input_symbol): + + '''This is the main method that you call to process input. This may + cause the FSM to change state and call an action. This method calls + get_transition() to find the action and next_state associated with the + input_symbol and current_state. If the action is None then the action + is not called and only the current state is changed. This method + processes one complete input symbol. You can process a list of symbols + (or a string) by calling process_list(). ''' + + self.input_symbol = input_symbol + (self.action, self.next_state) = self.get_transition (self.input_symbol, self.current_state) + if self.action is not None: + self.action (self) + self.current_state = self.next_state + self.next_state = None + + def process_list (self, input_symbols): + + '''This takes a list and sends each element to process(). The list may + be a string or any iterable object. ''' + + for s in input_symbols: + self.process (s) + +############################################################################## +# The following is an example that demonstrates the use of the FSM class to +# process an RPN expression. Run this module from the command line. You will +# get a prompt > for input. Enter an RPN Expression. Numbers may be integers. +# Operators are * / + - Use the = sign to evaluate and print the expression. +# For example: +# +# 167 3 2 2 * * * 1 - = +# +# will print: +# +# 2003 +############################################################################## + +import sys +import string + +PY3 = (sys.version_info[0] >= 3) + +# +# These define the actions. +# Note that "memory" is a list being used as a stack. +# + +def BeginBuildNumber (fsm): + fsm.memory.append (fsm.input_symbol) + +def BuildNumber (fsm): + s = fsm.memory.pop () + s = s + fsm.input_symbol + fsm.memory.append (s) + +def EndBuildNumber (fsm): + s = fsm.memory.pop () + fsm.memory.append (int(s)) + +def DoOperator (fsm): + ar = fsm.memory.pop() + al = fsm.memory.pop() + if fsm.input_symbol == '+': + fsm.memory.append (al + ar) + elif fsm.input_symbol == '-': + fsm.memory.append (al - ar) + elif fsm.input_symbol == '*': + fsm.memory.append (al * ar) + elif fsm.input_symbol == '/': + fsm.memory.append (al / ar) + +def DoEqual (fsm): + print(str(fsm.memory.pop())) + +def Error (fsm): + print('That does not compute.') + print(str(fsm.input_symbol)) + +def main(): + + '''This is where the example starts and the FSM state transitions are + defined. Note that states are strings (such as 'INIT'). This is not + necessary, but it makes the example easier to read. ''' + + f = FSM ('INIT', []) + f.set_default_transition (Error, 'INIT') + f.add_transition_any ('INIT', None, 'INIT') + f.add_transition ('=', 'INIT', DoEqual, 'INIT') + f.add_transition_list (string.digits, 'INIT', BeginBuildNumber, 'BUILDING_NUMBER') + f.add_transition_list (string.digits, 'BUILDING_NUMBER', BuildNumber, 'BUILDING_NUMBER') + f.add_transition_list (string.whitespace, 'BUILDING_NUMBER', EndBuildNumber, 'INIT') + f.add_transition_list ('+-*/', 'INIT', DoOperator, 'INIT') + + print() + print('Enter an RPN Expression.') + print('Numbers may be integers. Operators are * / + -') + print('Use the = sign to evaluate and print the expression.') + print('For example: ') + print(' 167 3 2 2 * * * 1 - =') + inputstr = (input if PY3 else raw_input)('> ') # analysis:ignore + f.process_list(inputstr) + + +if __name__ == '__main__': + main() diff --git a/pipenv/vendor/pexpect/__init__.py b/pipenv/vendor/pexpect/__init__.py new file mode 100644 index 00000000..6c509e69 --- /dev/null +++ b/pipenv/vendor/pexpect/__init__.py @@ -0,0 +1,85 @@ +'''Pexpect is a Python module for spawning child applications and controlling +them automatically. Pexpect can be used for automating interactive applications +such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup +scripts for duplicating software package installations on different servers. It +can be used for automated software testing. Pexpect is in the spirit of Don +Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python +require TCL and Expect or require C extensions to be compiled. Pexpect does not +use C, Expect, or TCL extensions. It should work on any platform that supports +the standard Python pty module. The Pexpect interface focuses on ease of use so +that simple tasks are easy. + +There are two main interfaces to the Pexpect system; these are the function, +run() and the class, spawn. The spawn class is more powerful. The run() +function is simpler than spawn, and is good for quickly calling program. When +you call the run() function it executes a given program and then returns the +output. This is a handy replacement for os.system(). + +For example:: + + pexpect.run('ls -la') + +The spawn class is the more powerful interface to the Pexpect system. You can +use this to spawn a child program then interact with it by sending input and +expecting responses (waiting for patterns in the child's output). + +For example:: + + child = pexpect.spawn('scp foo user@example.com:.') + child.expect('Password:') + child.sendline(mypassword) + +This works even for commands that ask for passwords or other input outside of +the normal stdio streams. For example, ssh reads input directly from the TTY +device which bypasses stdin. + +Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett, +Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids +vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin, +Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey, +Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume +Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John +Spiegel, Jan Grant, and Shane Kerr. Let me know if I forgot anyone. + +Pexpect is free, open source, and all that good stuff. +http://pexpect.sourceforge.net/ + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import sys +PY3 = (sys.version_info[0] >= 3) + +from .exceptions import ExceptionPexpect, EOF, TIMEOUT +from .utils import split_command_line, which, is_executable_file +from .expect import Expecter, searcher_re, searcher_string + +if sys.platform != 'win32': + # On Unix, these are available at the top level for backwards compatibility + from .pty_spawn import spawn, spawnu + from .run import run, runu + +__version__ = '4.2.1' +__revision__ = '' +__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnu', 'run', 'runu', + 'which', 'split_command_line', '__version__', '__revision__'] + + + +# vim: set shiftround expandtab tabstop=4 shiftwidth=4 ft=python autoindent : diff --git a/pipenv/vendor/pexpect/async.py b/pipenv/vendor/pexpect/async.py new file mode 100644 index 00000000..136fc0e2 --- /dev/null +++ b/pipenv/vendor/pexpect/async.py @@ -0,0 +1,78 @@ +import asyncio +import errno + +from pexpect import EOF + +@asyncio.coroutine +def expect_async(expecter, timeout=None): + # First process data that was previously read - if it maches, we don't need + # async stuff. + previously_read = expecter.spawn.buffer + expecter.spawn.buffer = expecter.spawn.string_type() + idx = expecter.new_data(previously_read) + if idx is not None: + return idx + + transport, pw = yield from asyncio.get_event_loop()\ + .connect_read_pipe(lambda: PatternWaiter(expecter), expecter.spawn) + + try: + return (yield from asyncio.wait_for(pw.fut, timeout)) + except asyncio.TimeoutError as e: + transport.pause_reading() + return expecter.timeout(e) + +class PatternWaiter(asyncio.Protocol): + transport = None + def __init__(self, expecter): + self.expecter = expecter + self.fut = asyncio.Future() + + def found(self, result): + if not self.fut.done(): + self.fut.set_result(result) + self.transport.pause_reading() + + def error(self, exc): + if not self.fut.done(): + self.fut.set_exception(exc) + self.transport.pause_reading() + + def connection_made(self, transport): + self.transport = transport + + def data_received(self, data): + spawn = self.expecter.spawn + s = spawn._decoder.decode(data) + spawn._log(s, 'read') + + if self.fut.done(): + spawn.buffer += s + return + + try: + index = self.expecter.new_data(s) + if index is not None: + # Found a match + self.found(index) + except Exception as e: + self.expecter.errored() + self.error(e) + + def eof_received(self): + # N.B. If this gets called, async will close the pipe (the spawn object) + # for us + try: + self.expecter.spawn.flag_eof = True + index = self.expecter.eof() + except EOF as e: + self.error(e) + else: + self.found(index) + + def connection_lost(self, exc): + if isinstance(exc, OSError) and exc.errno == errno.EIO: + # We may get here without eof_received being called, e.g on Linux + self.eof_received() + elif exc is not None: + self.error(exc) diff --git a/pipenv/vendor/pexpect/bashrc.sh b/pipenv/vendor/pexpect/bashrc.sh new file mode 100644 index 00000000..99a3ac2f --- /dev/null +++ b/pipenv/vendor/pexpect/bashrc.sh @@ -0,0 +1,5 @@ +source /etc/bash.bashrc +source ~/.bashrc + +# Reset PS1 so pexpect can find it +PS1="$" diff --git a/pipenv/vendor/pexpect/exceptions.py b/pipenv/vendor/pexpect/exceptions.py new file mode 100644 index 00000000..cb360f02 --- /dev/null +++ b/pipenv/vendor/pexpect/exceptions.py @@ -0,0 +1,35 @@ +"""Exception classes used by Pexpect""" + +import traceback +import sys + +class ExceptionPexpect(Exception): + '''Base class for all exceptions raised by this module. + ''' + + def __init__(self, value): + super(ExceptionPexpect, self).__init__(value) + self.value = value + + def __str__(self): + return str(self.value) + + def get_trace(self): + '''This returns an abbreviated stack trace with lines that only concern + the caller. In other words, the stack trace inside the Pexpect module + is not included. ''' + + tblist = traceback.extract_tb(sys.exc_info()[2]) + tblist = [item for item in tblist if ('pexpect/__init__' not in item[0]) + and ('pexpect/expect' not in item[0])] + tblist = traceback.format_list(tblist) + return ''.join(tblist) + + +class EOF(ExceptionPexpect): + '''Raised when EOF is read from a child. + This usually means the child has exited.''' + + +class TIMEOUT(ExceptionPexpect): + '''Raised when a read time exceeds the timeout. ''' diff --git a/pipenv/vendor/pexpect/expect.py b/pipenv/vendor/pexpect/expect.py new file mode 100644 index 00000000..660cfb53 --- /dev/null +++ b/pipenv/vendor/pexpect/expect.py @@ -0,0 +1,300 @@ +import time + +from .exceptions import EOF, TIMEOUT + +class Expecter(object): + def __init__(self, spawn, searcher, searchwindowsize=-1): + self.spawn = spawn + self.searcher = searcher + if searchwindowsize == -1: + searchwindowsize = spawn.searchwindowsize + self.searchwindowsize = searchwindowsize + + def new_data(self, data): + spawn = self.spawn + searcher = self.searcher + + incoming = spawn.buffer + data + freshlen = len(data) + index = searcher.search(incoming, freshlen, self.searchwindowsize) + if index >= 0: + spawn.buffer = incoming[searcher.end:] + spawn.before = incoming[: searcher.start] + spawn.after = incoming[searcher.start: searcher.end] + spawn.match = searcher.match + spawn.match_index = index + # Found a match + return index + + spawn.buffer = incoming + + def eof(self, err=None): + spawn = self.spawn + from . import EOF + + spawn.before = spawn.buffer + spawn.buffer = spawn.string_type() + spawn.after = EOF + index = self.searcher.eof_index + if index >= 0: + spawn.match = EOF + spawn.match_index = index + return index + else: + spawn.match = None + spawn.match_index = None + msg = str(spawn) + msg += '\nsearcher: %s' % self.searcher + if err is not None: + msg = str(err) + '\n' + msg + raise EOF(msg) + + def timeout(self, err=None): + spawn = self.spawn + from . import TIMEOUT + + spawn.before = spawn.buffer + spawn.after = TIMEOUT + index = self.searcher.timeout_index + if index >= 0: + spawn.match = TIMEOUT + spawn.match_index = index + return index + else: + spawn.match = None + spawn.match_index = None + msg = str(spawn) + msg += '\nsearcher: %s' % self.searcher + if err is not None: + msg = str(err) + '\n' + msg + raise TIMEOUT(msg) + + def errored(self): + spawn = self.spawn + spawn.before = spawn.buffer + spawn.after = None + spawn.match = None + spawn.match_index = None + + def expect_loop(self, timeout=-1): + """Blocking expect""" + spawn = self.spawn + from . import EOF, TIMEOUT + + if timeout is not None: + end_time = time.time() + timeout + + try: + incoming = spawn.buffer + spawn.buffer = spawn.string_type() # Treat buffer as new data + while True: + idx = self.new_data(incoming) + # Keep reading until exception or return. + if idx is not None: + return idx + # No match at this point + if (timeout is not None) and (timeout < 0): + return self.timeout() + # Still have time left, so read more data + incoming = spawn.read_nonblocking(spawn.maxread, timeout) + if self.spawn.delayafterread is not None: + time.sleep(self.spawn.delayafterread) + if timeout is not None: + timeout = end_time - time.time() + except EOF as e: + return self.eof(e) + except TIMEOUT as e: + return self.timeout(e) + except: + self.errored() + raise + + +class searcher_string(object): + '''This is a plain string search helper for the spawn.expect_any() method. + This helper class is for speed. For more powerful regex patterns + see the helper class, searcher_re. + + Attributes: + + eof_index - index of EOF, or -1 + timeout_index - index of TIMEOUT, or -1 + + After a successful match by the search() method the following attributes + are available: + + start - index into the buffer, first byte of match + end - index into the buffer, first byte after match + match - the matching string itself + + ''' + + def __init__(self, strings): + '''This creates an instance of searcher_string. This argument 'strings' + may be a list; a sequence of strings; or the EOF or TIMEOUT types. ''' + + self.eof_index = -1 + self.timeout_index = -1 + self._strings = [] + for n, s in enumerate(strings): + if s is EOF: + self.eof_index = n + continue + if s is TIMEOUT: + self.timeout_index = n + continue + self._strings.append((n, s)) + + def __str__(self): + '''This returns a human-readable string that represents the state of + the object.''' + + ss = [(ns[0], ' %d: "%s"' % ns) for ns in self._strings] + ss.append((-1, 'searcher_string:')) + if self.eof_index >= 0: + ss.append((self.eof_index, ' %d: EOF' % self.eof_index)) + if self.timeout_index >= 0: + ss.append((self.timeout_index, + ' %d: TIMEOUT' % self.timeout_index)) + ss.sort() + ss = list(zip(*ss))[1] + return '\n'.join(ss) + + def search(self, buffer, freshlen, searchwindowsize=None): + '''This searches 'buffer' for the first occurence of one of the search + strings. 'freshlen' must indicate the number of bytes at the end of + 'buffer' which have not been searched before. It helps to avoid + searching the same, possibly big, buffer over and over again. + + See class spawn for the 'searchwindowsize' argument. + + If there is a match this returns the index of that string, and sets + 'start', 'end' and 'match'. Otherwise, this returns -1. ''' + + first_match = None + + # 'freshlen' helps a lot here. Further optimizations could + # possibly include: + # + # using something like the Boyer-Moore Fast String Searching + # Algorithm; pre-compiling the search through a list of + # strings into something that can scan the input once to + # search for all N strings; realize that if we search for + # ['bar', 'baz'] and the input is '...foo' we need not bother + # rescanning until we've read three more bytes. + # + # Sadly, I don't know enough about this interesting topic. /grahn + + for index, s in self._strings: + if searchwindowsize is None: + # the match, if any, can only be in the fresh data, + # or at the very end of the old data + offset = -(freshlen + len(s)) + else: + # better obey searchwindowsize + offset = -searchwindowsize + n = buffer.find(s, offset) + if n >= 0 and (first_match is None or n < first_match): + first_match = n + best_index, best_match = index, s + if first_match is None: + return -1 + self.match = best_match + self.start = first_match + self.end = self.start + len(self.match) + return best_index + + +class searcher_re(object): + '''This is regular expression string search helper for the + spawn.expect_any() method. This helper class is for powerful + pattern matching. For speed, see the helper class, searcher_string. + + Attributes: + + eof_index - index of EOF, or -1 + timeout_index - index of TIMEOUT, or -1 + + After a successful match by the search() method the following attributes + are available: + + start - index into the buffer, first byte of match + end - index into the buffer, first byte after match + match - the re.match object returned by a succesful re.search + + ''' + + def __init__(self, patterns): + '''This creates an instance that searches for 'patterns' Where + 'patterns' may be a list or other sequence of compiled regular + expressions, or the EOF or TIMEOUT types.''' + + self.eof_index = -1 + self.timeout_index = -1 + self._searches = [] + for n, s in zip(list(range(len(patterns))), patterns): + if s is EOF: + self.eof_index = n + continue + if s is TIMEOUT: + self.timeout_index = n + continue + self._searches.append((n, s)) + + def __str__(self): + '''This returns a human-readable string that represents the state of + the object.''' + + #ss = [(n, ' %d: re.compile("%s")' % + # (n, repr(s.pattern))) for n, s in self._searches] + ss = list() + for n, s in self._searches: + try: + ss.append((n, ' %d: re.compile("%s")' % (n, s.pattern))) + except UnicodeEncodeError: + # for test cases that display __str__ of searches, dont throw + # another exception just because stdout is ascii-only, using + # repr() + ss.append((n, ' %d: re.compile(%r)' % (n, s.pattern))) + ss.append((-1, 'searcher_re:')) + if self.eof_index >= 0: + ss.append((self.eof_index, ' %d: EOF' % self.eof_index)) + if self.timeout_index >= 0: + ss.append((self.timeout_index, ' %d: TIMEOUT' % + self.timeout_index)) + ss.sort() + ss = list(zip(*ss))[1] + return '\n'.join(ss) + + def search(self, buffer, freshlen, searchwindowsize=None): + '''This searches 'buffer' for the first occurence of one of the regular + expressions. 'freshlen' must indicate the number of bytes at the end of + 'buffer' which have not been searched before. + + See class spawn for the 'searchwindowsize' argument. + + If there is a match this returns the index of that string, and sets + 'start', 'end' and 'match'. Otherwise, returns -1.''' + + first_match = None + # 'freshlen' doesn't help here -- we cannot predict the + # length of a match, and the re module provides no help. + if searchwindowsize is None: + searchstart = 0 + else: + searchstart = max(0, len(buffer) - searchwindowsize) + for index, s in self._searches: + match = s.search(buffer, searchstart) + if match is None: + continue + n = match.start() + if first_match is None or n < first_match: + first_match = n + the_match = match + best_index = index + if first_match is None: + return -1 + self.start = first_match + self.match = the_match + self.end = self.match.end() + return best_index diff --git a/pipenv/vendor/pexpect/fdpexpect.py b/pipenv/vendor/pexpect/fdpexpect.py new file mode 100644 index 00000000..ac7443e5 --- /dev/null +++ b/pipenv/vendor/pexpect/fdpexpect.py @@ -0,0 +1,142 @@ +'''This is like pexpect, but it will work with any file descriptor that you +pass it. You are reponsible for opening and close the file descriptor. +This allows you to use Pexpect with sockets and named pipes (FIFOs). + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +from .spawnbase import SpawnBase +from .exceptions import ExceptionPexpect, TIMEOUT +from .utils import select_ignore_interrupts +import os + +__all__ = ['fdspawn'] + +class fdspawn(SpawnBase): + '''This is like pexpect.spawn but allows you to supply your own open file + descriptor. For example, you could use it to read through a file looking + for patterns, or to control a modem or serial device. ''' + + def __init__ (self, fd, args=None, timeout=30, maxread=2000, searchwindowsize=None, + logfile=None, encoding=None, codec_errors='strict'): + '''This takes a file descriptor (an int) or an object that support the + fileno() method (returning an int). All Python file-like objects + support fileno(). ''' + + if type(fd) != type(0) and hasattr(fd, 'fileno'): + fd = fd.fileno() + + if type(fd) != type(0): + raise ExceptionPexpect('The fd argument is not an int. If this is a command string then maybe you want to use pexpect.spawn.') + + try: # make sure fd is a valid file descriptor + os.fstat(fd) + except OSError: + raise ExceptionPexpect('The fd argument is not a valid file descriptor.') + + self.args = None + self.command = None + SpawnBase.__init__(self, timeout, maxread, searchwindowsize, logfile, + encoding=encoding, codec_errors=codec_errors) + self.child_fd = fd + self.own_fd = False + self.closed = False + self.name = '' % fd + + def close (self): + """Close the file descriptor. + + Calling this method a second time does nothing, but if the file + descriptor was closed elsewhere, :class:`OSError` will be raised. + """ + if self.child_fd == -1: + return + + self.flush() + os.close(self.child_fd) + self.child_fd = -1 + self.closed = True + + def isalive (self): + '''This checks if the file descriptor is still valid. If :func:`os.fstat` + does not raise an exception then we assume it is alive. ''' + + if self.child_fd == -1: + return False + try: + os.fstat(self.child_fd) + return True + except: + return False + + def terminate (self, force=False): # pragma: no cover + '''Deprecated and invalid. Just raises an exception.''' + raise ExceptionPexpect('This method is not valid for file descriptors.') + + # These four methods are left around for backwards compatibility, but not + # documented as part of fdpexpect. You're encouraged to use os.write + # directly. + def send(self, s): + "Write to fd, return number of bytes written" + s = self._coerce_send_string(s) + self._log(s, 'send') + + b = self._encoder.encode(s, final=False) + return os.write(self.child_fd, b) + + def sendline(self, s): + "Write to fd with trailing newline, return number of bytes written" + s = self._coerce_send_string(s) + return self.send(s + self.linesep) + + def write(self, s): + "Write to fd, return None" + self.send(s) + + def writelines(self, sequence): + "Call self.write() for each item in sequence" + for s in sequence: + self.write(s) + + def read_nonblocking(self, size=1, timeout=-1): + """ + Read from the file descriptor and return the result as a string. + + The read_nonblocking method of :class:`SpawnBase` assumes that a call + to os.read will not block (timeout parameter is ignored). This is not + the case for POSIX file-like objects such as sockets and serial ports. + + Use :func:`select.select`, timeout is implemented conditionally for + POSIX systems. + + :param int size: Read at most *size* bytes. + :param int timeout: Wait timeout seconds for file descriptor to be + ready to read. When -1 (default), use self.timeout. When 0, poll. + :return: String containing the bytes read + """ + if os.name == 'posix': + if timeout == -1: + timeout = self.timeout + rlist = [self.child_fd] + wlist = [] + xlist = [] + rlist, wlist, xlist = select_ignore_interrupts(rlist, wlist, xlist, timeout) + if self.child_fd not in rlist: + raise TIMEOUT('Timeout exceeded.') + return super(fdspawn, self).read_nonblocking(size) diff --git a/pipenv/vendor/pexpect/popen_spawn.py b/pipenv/vendor/pexpect/popen_spawn.py new file mode 100644 index 00000000..680dd8a2 --- /dev/null +++ b/pipenv/vendor/pexpect/popen_spawn.py @@ -0,0 +1,179 @@ +"""Provides an interface like pexpect.spawn interface using subprocess.Popen +""" +import os +import threading +import subprocess +import sys +import time +import signal +import shlex + +try: + from queue import Queue, Empty # Python 3 +except ImportError: + from Queue import Queue, Empty # Python 2 + +from .spawnbase import SpawnBase, PY3 +from .exceptions import EOF + +class PopenSpawn(SpawnBase): + if PY3: + crlf = '\n'.encode('ascii') + else: + crlf = '\n' + + def __init__(self, cmd, timeout=30, maxread=2000, searchwindowsize=None, + logfile=None, cwd=None, env=None, encoding=None, + codec_errors='strict'): + super(PopenSpawn, self).__init__(timeout=timeout, maxread=maxread, + searchwindowsize=searchwindowsize, logfile=logfile, + encoding=encoding, codec_errors=codec_errors) + + kwargs = dict(bufsize=0, stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, stdout=subprocess.PIPE, + cwd=cwd, env=env) + + if sys.platform == 'win32': + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + kwargs['startupinfo'] = startupinfo + kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP + + if not isinstance(cmd, (list, tuple)): + cmd = shlex.split(cmd) + + self.proc = subprocess.Popen(cmd, **kwargs) + self.closed = False + self._buf = self.string_type() + + self._read_queue = Queue() + self._read_thread = threading.Thread(target=self._read_incoming) + self._read_thread.setDaemon(True) + self._read_thread.start() + + _read_reached_eof = False + + def read_nonblocking(self, size, timeout): + buf = self._buf + if self._read_reached_eof: + # We have already finished reading. Use up any buffered data, + # then raise EOF + if buf: + self._buf = buf[size:] + return buf[:size] + else: + self.flag_eof = True + raise EOF('End Of File (EOF).') + + if timeout == -1: + timeout = self.timeout + elif timeout is None: + timeout = 1e6 + + t0 = time.time() + while (time.time() - t0) < timeout and size and len(buf) < size: + try: + incoming = self._read_queue.get_nowait() + except Empty: + break + else: + if incoming is None: + self._read_reached_eof = True + break + + buf += self._decoder.decode(incoming, final=False) + + r, self._buf = buf[:size], buf[size:] + + self._log(r, 'read') + return r + + def _read_incoming(self): + """Run in a thread to move output from a pipe to a queue.""" + fileno = self.proc.stdout.fileno() + while 1: + buf = b'' + try: + buf = os.read(fileno, 1024) + except OSError as e: + self._log(e, 'read') + + if not buf: + # This indicates we have reached EOF + self._read_queue.put(None) + return + + self._read_queue.put(buf) + + def write(self, s): + '''This is similar to send() except that there is no return value. + ''' + self.send(s) + + def writelines(self, sequence): + '''This calls write() for each element in the sequence. + + The sequence can be any iterable object producing strings, typically a + list of strings. This does not add line separators. There is no return + value. + ''' + for s in sequence: + self.send(s) + + def send(self, s): + '''Send data to the subprocess' stdin. + + Returns the number of bytes written. + ''' + s = self._coerce_send_string(s) + self._log(s, 'send') + + b = self._encoder.encode(s, final=False) + if PY3: + return self.proc.stdin.write(b) + else: + # On Python 2, .write() returns None, so we return the length of + # bytes written ourselves. This assumes they all got written. + self.proc.stdin.write(b) + return len(b) + + def sendline(self, s=''): + '''Wraps send(), sending string ``s`` to child process, with os.linesep + automatically appended. Returns number of bytes written. ''' + + n = self.send(s) + return n + self.send(self.linesep) + + def wait(self): + '''Wait for the subprocess to finish. + + Returns the exit code. + ''' + status = self.proc.wait() + if status >= 0: + self.exitstatus = status + self.signalstatus = None + else: + self.exitstatus = None + self.signalstatus = -status + self.terminated = True + return status + + def kill(self, sig): + '''Sends a Unix signal to the subprocess. + + Use constants from the :mod:`signal` module to specify which signal. + ''' + if sys.platform == 'win32': + if sig in [signal.SIGINT, signal.CTRL_C_EVENT]: + sig = signal.CTRL_C_EVENT + elif sig in [signal.SIGBREAK, signal.CTRL_BREAK_EVENT]: + sig = signal.CTRL_BREAK_EVENT + else: + sig = signal.SIGTERM + + os.kill(self.proc.pid, sig) + + def sendeof(self): + '''Closes the stdin pipe from the writing end.''' + self.proc.stdin.close() diff --git a/pipenv/vendor/pexpect/pty_spawn.py b/pipenv/vendor/pexpect/pty_spawn.py new file mode 100644 index 00000000..d1c6df7b --- /dev/null +++ b/pipenv/vendor/pexpect/pty_spawn.py @@ -0,0 +1,806 @@ +import os +import sys +import time +import pty +import tty +import errno +import signal +from contextlib import contextmanager + +import ptyprocess +from ptyprocess.ptyprocess import use_native_pty_fork + +from .exceptions import ExceptionPexpect, EOF, TIMEOUT +from .spawnbase import SpawnBase +from .utils import which, split_command_line, select_ignore_interrupts + +@contextmanager +def _wrap_ptyprocess_err(): + """Turn ptyprocess errors into our own ExceptionPexpect errors""" + try: + yield + except ptyprocess.PtyProcessError as e: + raise ExceptionPexpect(*e.args) + +PY3 = (sys.version_info[0] >= 3) + +class spawn(SpawnBase): + '''This is the main class interface for Pexpect. Use this class to start + and control child applications. ''' + + # This is purely informational now - changing it has no effect + use_native_pty_fork = use_native_pty_fork + + def __init__(self, command, args=[], timeout=30, maxread=2000, + searchwindowsize=None, logfile=None, cwd=None, env=None, + ignore_sighup=False, echo=True, preexec_fn=None, + encoding=None, codec_errors='strict', dimensions=None): + '''This is the constructor. The command parameter may be a string that + includes a command and any arguments to the command. For example:: + + child = pexpect.spawn('/usr/bin/ftp') + child = pexpect.spawn('/usr/bin/ssh user@example.com') + child = pexpect.spawn('ls -latr /tmp') + + You may also construct it with a list of arguments like so:: + + child = pexpect.spawn('/usr/bin/ftp', []) + child = pexpect.spawn('/usr/bin/ssh', ['user@example.com']) + child = pexpect.spawn('ls', ['-latr', '/tmp']) + + After this the child application will be created and will be ready to + talk to. For normal use, see expect() and send() and sendline(). + + Remember that Pexpect does NOT interpret shell meta characters such as + redirect, pipe, or wild cards (``>``, ``|``, or ``*``). This is a + common mistake. If you want to run a command and pipe it through + another command then you must also start a shell. For example:: + + child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"') + child.expect(pexpect.EOF) + + The second form of spawn (where you pass a list of arguments) is useful + in situations where you wish to spawn a command and pass it its own + argument list. This can make syntax more clear. For example, the + following is equivalent to the previous example:: + + shell_cmd = 'ls -l | grep LOG > logs.txt' + child = pexpect.spawn('/bin/bash', ['-c', shell_cmd]) + child.expect(pexpect.EOF) + + The maxread attribute sets the read buffer size. This is maximum number + of bytes that Pexpect will try to read from a TTY at one time. Setting + the maxread size to 1 will turn off buffering. Setting the maxread + value higher may help performance in cases where large amounts of + output are read back from the child. This feature is useful in + conjunction with searchwindowsize. + + When the keyword argument *searchwindowsize* is None (default), the + full buffer is searched at each iteration of receiving incoming data. + The default number of bytes scanned at each iteration is very large + and may be reduced to collaterally reduce search cost. After + :meth:`~.expect` returns, the full buffer attribute remains up to + size *maxread* irrespective of *searchwindowsize* value. + + When the keyword argument ``timeout`` is specified as a number, + (default: *30*), then :class:`TIMEOUT` will be raised after the value + specified has elapsed, in seconds, for any of the :meth:`~.expect` + family of method calls. When None, TIMEOUT will not be raised, and + :meth:`~.expect` may block indefinitely until match. + + + The logfile member turns on or off logging. All input and output will + be copied to the given file object. Set logfile to None to stop + logging. This is the default. Set logfile to sys.stdout to echo + everything to standard output. The logfile is flushed after each write. + + Example log input and output to a file:: + + child = pexpect.spawn('some_command') + fout = open('mylog.txt','wb') + child.logfile = fout + + Example log to stdout:: + + # In Python 2: + child = pexpect.spawn('some_command') + child.logfile = sys.stdout + + # In Python 3, spawnu should be used to give str to stdout: + child = pexpect.spawnu('some_command') + child.logfile = sys.stdout + + The logfile_read and logfile_send members can be used to separately log + the input from the child and output sent to the child. Sometimes you + don't want to see everything you write to the child. You only want to + log what the child sends back. For example:: + + child = pexpect.spawn('some_command') + child.logfile_read = sys.stdout + + You will need to pass an encoding to spawn in the above code if you are + using Python 3. + + To separately log output sent to the child use logfile_send:: + + child.logfile_send = fout + + If ``ignore_sighup`` is True, the child process will ignore SIGHUP + signals. The default is False from Pexpect 4.0, meaning that SIGHUP + will be handled normally by the child. + + The delaybeforesend helps overcome a weird behavior that many users + were experiencing. The typical problem was that a user would expect() a + "Password:" prompt and then immediately call sendline() to send the + password. The user would then see that their password was echoed back + to them. Passwords don't normally echo. The problem is caused by the + fact that most applications print out the "Password" prompt and then + turn off stdin echo, but if you send your password before the + application turned off echo, then you get your password echoed. + Normally this wouldn't be a problem when interacting with a human at a + real keyboard. If you introduce a slight delay just before writing then + this seems to clear up the problem. This was such a common problem for + many users that I decided that the default pexpect behavior should be + to sleep just before writing to the child application. 1/20th of a + second (50 ms) seems to be enough to clear up the problem. You can set + delaybeforesend to None to return to the old behavior. + + Note that spawn is clever about finding commands on your path. + It uses the same logic that "which" uses to find executables. + + If you wish to get the exit status of the child you must call the + close() method. The exit or signal status of the child will be stored + in self.exitstatus or self.signalstatus. If the child exited normally + then exitstatus will store the exit return code and signalstatus will + be None. If the child was terminated abnormally with a signal then + signalstatus will store the signal value and exitstatus will be None:: + + child = pexpect.spawn('some_command') + child.close() + print(child.exitstatus, child.signalstatus) + + If you need more detail you can also read the self.status member which + stores the status returned by os.waitpid. You can interpret this using + os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. + + The echo attribute may be set to False to disable echoing of input. + As a pseudo-terminal, all input echoed by the "keyboard" (send() + or sendline()) will be repeated to output. For many cases, it is + not desirable to have echo enabled, and it may be later disabled + using setecho(False) followed by waitnoecho(). However, for some + platforms such as Solaris, this is not possible, and should be + disabled immediately on spawn. + + If preexec_fn is given, it will be called in the child process before + launching the given command. This is useful to e.g. reset inherited + signal handlers. + + The dimensions attribute specifies the size of the pseudo-terminal as + seen by the subprocess, and is specified as a two-entry tuple (rows, + columns). If this is unspecified, the defaults in ptyprocess will apply. + ''' + super(spawn, self).__init__(timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, + logfile=logfile, encoding=encoding, codec_errors=codec_errors) + self.STDIN_FILENO = pty.STDIN_FILENO + self.STDOUT_FILENO = pty.STDOUT_FILENO + self.STDERR_FILENO = pty.STDERR_FILENO + self.cwd = cwd + self.env = env + self.echo = echo + self.ignore_sighup = ignore_sighup + self.__irix_hack = sys.platform.lower().startswith('irix') + if command is None: + self.command = None + self.args = None + self.name = '' + else: + self._spawn(command, args, preexec_fn, dimensions) + + def __str__(self): + '''This returns a human-readable string that represents the state of + the object. ''' + + s = [] + s.append(repr(self)) + s.append('command: ' + str(self.command)) + s.append('args: %r' % (self.args,)) + s.append('buffer (last 100 chars): %r' % ( + self.buffer[-100:] if self.buffer else self.buffer,)) + s.append('before (last 100 chars): %r' % ( + self.before[-100:] if self.before else self.before,)) + s.append('after: %r' % (self.after,)) + s.append('match: %r' % (self.match,)) + s.append('match_index: ' + str(self.match_index)) + s.append('exitstatus: ' + str(self.exitstatus)) + if hasattr(self, 'ptyproc'): + s.append('flag_eof: ' + str(self.flag_eof)) + s.append('pid: ' + str(self.pid)) + s.append('child_fd: ' + str(self.child_fd)) + s.append('closed: ' + str(self.closed)) + s.append('timeout: ' + str(self.timeout)) + s.append('delimiter: ' + str(self.delimiter)) + s.append('logfile: ' + str(self.logfile)) + s.append('logfile_read: ' + str(self.logfile_read)) + s.append('logfile_send: ' + str(self.logfile_send)) + s.append('maxread: ' + str(self.maxread)) + s.append('ignorecase: ' + str(self.ignorecase)) + s.append('searchwindowsize: ' + str(self.searchwindowsize)) + s.append('delaybeforesend: ' + str(self.delaybeforesend)) + s.append('delayafterclose: ' + str(self.delayafterclose)) + s.append('delayafterterminate: ' + str(self.delayafterterminate)) + return '\n'.join(s) + + def _spawn(self, command, args=[], preexec_fn=None, dimensions=None): + '''This starts the given command in a child process. This does all the + fork/exec type of stuff for a pty. This is called by __init__. If args + is empty then command will be parsed (split on spaces) and args will be + set to parsed arguments. ''' + + # The pid and child_fd of this object get set by this method. + # Note that it is difficult for this method to fail. + # You cannot detect if the child process cannot start. + # So the only way you can tell if the child process started + # or not is to try to read from the file descriptor. If you get + # EOF immediately then it means that the child is already dead. + # That may not necessarily be bad because you may have spawned a child + # that performs some task; creates no stdout output; and then dies. + + # If command is an int type then it may represent a file descriptor. + if isinstance(command, type(0)): + raise ExceptionPexpect('Command is an int type. ' + + 'If this is a file descriptor then maybe you want to ' + + 'use fdpexpect.fdspawn which takes an existing ' + + 'file descriptor instead of a command string.') + + if not isinstance(args, type([])): + raise TypeError('The argument, args, must be a list.') + + if args == []: + self.args = split_command_line(command) + self.command = self.args[0] + else: + # Make a shallow copy of the args list. + self.args = args[:] + self.args.insert(0, command) + self.command = command + + command_with_path = which(self.command, env=self.env) + if command_with_path is None: + raise ExceptionPexpect('The command was not found or was not ' + + 'executable: %s.' % self.command) + self.command = command_with_path + self.args[0] = self.command + + self.name = '<' + ' '.join(self.args) + '>' + + assert self.pid is None, 'The pid member must be None.' + assert self.command is not None, 'The command member must not be None.' + + kwargs = {'echo': self.echo, 'preexec_fn': preexec_fn} + if self.ignore_sighup: + def preexec_wrapper(): + "Set SIGHUP to be ignored, then call the real preexec_fn" + signal.signal(signal.SIGHUP, signal.SIG_IGN) + if preexec_fn is not None: + preexec_fn() + kwargs['preexec_fn'] = preexec_wrapper + + if dimensions is not None: + kwargs['dimensions'] = dimensions + + if self.encoding is not None: + # Encode command line using the specified encoding + self.args = [a if isinstance(a, bytes) else a.encode(self.encoding) + for a in self.args] + + self.ptyproc = self._spawnpty(self.args, env=self.env, + cwd=self.cwd, **kwargs) + + self.pid = self.ptyproc.pid + self.child_fd = self.ptyproc.fd + + + self.terminated = False + self.closed = False + + def _spawnpty(self, args, **kwargs): + '''Spawn a pty and return an instance of PtyProcess.''' + return ptyprocess.PtyProcess.spawn(args, **kwargs) + + def close(self, force=True): + '''This closes the connection with the child application. Note that + calling close() more than once is valid. This emulates standard Python + behavior with files. Set force to True if you want to make sure that + the child is terminated (SIGKILL is sent if the child ignores SIGHUP + and SIGINT). ''' + + self.flush() + self.ptyproc.close(force=force) + self.isalive() # Update exit status from ptyproc + self.child_fd = -1 + + def isatty(self): + '''This returns True if the file descriptor is open and connected to a + tty(-like) device, else False. + + On SVR4-style platforms implementing streams, such as SunOS and HP-UX, + the child pty may not appear as a terminal device. This means + methods such as setecho(), setwinsize(), getwinsize() may raise an + IOError. ''' + + return os.isatty(self.child_fd) + + def waitnoecho(self, timeout=-1): + '''This waits until the terminal ECHO flag is set False. This returns + True if the echo mode is off. This returns False if the ECHO flag was + not set False before the timeout. This can be used to detect when the + child is waiting for a password. Usually a child application will turn + off echo mode when it is waiting for the user to enter a password. For + example, instead of expecting the "password:" prompt you can wait for + the child to set ECHO off:: + + p = pexpect.spawn('ssh user@example.com') + p.waitnoecho() + p.sendline(mypassword) + + If timeout==-1 then this method will use the value in self.timeout. + If timeout==None then this method to block until ECHO flag is False. + ''' + + if timeout == -1: + timeout = self.timeout + if timeout is not None: + end_time = time.time() + timeout + while True: + if not self.getecho(): + return True + if timeout < 0 and timeout is not None: + return False + if timeout is not None: + timeout = end_time - time.time() + time.sleep(0.1) + + def getecho(self): + '''This returns the terminal echo mode. This returns True if echo is + on or False if echo is off. Child applications that are expecting you + to enter a password often set ECHO False. See waitnoecho(). + + Not supported on platforms where ``isatty()`` returns False. ''' + return self.ptyproc.getecho() + + def setecho(self, state): + '''This sets the terminal echo mode on or off. Note that anything the + child sent before the echo will be lost, so you should be sure that + your input buffer is empty before you call setecho(). For example, the + following will work as expected:: + + p = pexpect.spawn('cat') # Echo is on by default. + p.sendline('1234') # We expect see this twice from the child... + p.expect(['1234']) # ... once from the tty echo... + p.expect(['1234']) # ... and again from cat itself. + p.setecho(False) # Turn off tty echo + p.sendline('abcd') # We will set this only once (echoed by cat). + p.sendline('wxyz') # We will set this only once (echoed by cat) + p.expect(['abcd']) + p.expect(['wxyz']) + + The following WILL NOT WORK because the lines sent before the setecho + will be lost:: + + p = pexpect.spawn('cat') + p.sendline('1234') + p.setecho(False) # Turn off tty echo + p.sendline('abcd') # We will set this only once (echoed by cat). + p.sendline('wxyz') # We will set this only once (echoed by cat) + p.expect(['1234']) + p.expect(['1234']) + p.expect(['abcd']) + p.expect(['wxyz']) + + + Not supported on platforms where ``isatty()`` returns False. + ''' + return self.ptyproc.setecho(state) + + def read_nonblocking(self, size=1, timeout=-1): + '''This reads at most size characters from the child application. It + includes a timeout. If the read does not complete within the timeout + period then a TIMEOUT exception is raised. If the end of file is read + then an EOF exception will be raised. If a logfile is specified, a + copy is written to that log. + + If timeout is None then the read may block indefinitely. + If timeout is -1 then the self.timeout value is used. If timeout is 0 + then the child is polled and if there is no data immediately ready + then this will raise a TIMEOUT exception. + + The timeout refers only to the amount of time to read at least one + character. This is not affected by the 'size' parameter, so if you call + read_nonblocking(size=100, timeout=30) and only one character is + available right away then one character will be returned immediately. + It will not wait for 30 seconds for another 99 characters to come in. + + This is a wrapper around os.read(). It uses select.select() to + implement the timeout. ''' + + if self.closed: + raise ValueError('I/O operation on closed file.') + + if timeout == -1: + timeout = self.timeout + + # Note that some systems such as Solaris do not give an EOF when + # the child dies. In fact, you can still try to read + # from the child_fd -- it will block forever or until TIMEOUT. + # For this case, I test isalive() before doing any reading. + # If isalive() is false, then I pretend that this is the same as EOF. + if not self.isalive(): + # timeout of 0 means "poll" + r, w, e = select_ignore_interrupts([self.child_fd], [], [], 0) + if not r: + self.flag_eof = True + raise EOF('End Of File (EOF). Braindead platform.') + elif self.__irix_hack: + # Irix takes a long time before it realizes a child was terminated. + # FIXME So does this mean Irix systems are forced to always have + # FIXME a 2 second delay when calling read_nonblocking? That sucks. + r, w, e = select_ignore_interrupts([self.child_fd], [], [], 2) + if not r and not self.isalive(): + self.flag_eof = True + raise EOF('End Of File (EOF). Slow platform.') + + r, w, e = select_ignore_interrupts([self.child_fd], [], [], timeout) + + if not r: + if not self.isalive(): + # Some platforms, such as Irix, will claim that their + # processes are alive; timeout on the select; and + # then finally admit that they are not alive. + self.flag_eof = True + raise EOF('End of File (EOF). Very slow platform.') + else: + raise TIMEOUT('Timeout exceeded.') + + if self.child_fd in r: + return super(spawn, self).read_nonblocking(size) + + raise ExceptionPexpect('Reached an unexpected state.') # pragma: no cover + + def write(self, s): + '''This is similar to send() except that there is no return value. + ''' + + self.send(s) + + def writelines(self, sequence): + '''This calls write() for each element in the sequence. The sequence + can be any iterable object producing strings, typically a list of + strings. This does not add line separators. There is no return value. + ''' + + for s in sequence: + self.write(s) + + def send(self, s): + '''Sends string ``s`` to the child process, returning the number of + bytes written. If a logfile is specified, a copy is written to that + log. + + The default terminal input mode is canonical processing unless set + otherwise by the child process. This allows backspace and other line + processing to be performed prior to transmitting to the receiving + program. As this is buffered, there is a limited size of such buffer. + + On Linux systems, this is 4096 (defined by N_TTY_BUF_SIZE). All + other systems honor the POSIX.1 definition PC_MAX_CANON -- 1024 + on OSX, 256 on OpenSolaris, and 1920 on FreeBSD. + + This value may be discovered using fpathconf(3):: + + >>> from os import fpathconf + >>> print(fpathconf(0, 'PC_MAX_CANON')) + 256 + + On such a system, only 256 bytes may be received per line. Any + subsequent bytes received will be discarded. BEL (``'\a'``) is then + sent to output if IMAXBEL (termios.h) is set by the tty driver. + This is usually enabled by default. Linux does not honor this as + an option -- it behaves as though it is always set on. + + Canonical input processing may be disabled altogether by executing + a shell, then stty(1), before executing the final program:: + + >>> bash = pexpect.spawn('/bin/bash', echo=False) + >>> bash.sendline('stty -icanon') + >>> bash.sendline('base64') + >>> bash.sendline('x' * 5000) + ''' + + if self.delaybeforesend is not None: + time.sleep(self.delaybeforesend) + + s = self._coerce_send_string(s) + self._log(s, 'send') + + b = self._encoder.encode(s, final=False) + return os.write(self.child_fd, b) + + def sendline(self, s=''): + '''Wraps send(), sending string ``s`` to child process, with + ``os.linesep`` automatically appended. Returns number of bytes + written. Only a limited number of bytes may be sent for each + line in the default terminal mode, see docstring of :meth:`send`. + ''' + s = self._coerce_send_string(s) + return self.send(s + self.linesep) + + def _log_control(self, s): + """Write control characters to the appropriate log files""" + if self.encoding is not None: + s = s.decode(self.encoding, 'replace') + self._log(s, 'send') + + def sendcontrol(self, char): + '''Helper method that wraps send() with mnemonic access for sending control + character to the child (such as Ctrl-C or Ctrl-D). For example, to send + Ctrl-G (ASCII 7, bell, '\a'):: + + child.sendcontrol('g') + + See also, sendintr() and sendeof(). + ''' + n, byte = self.ptyproc.sendcontrol(char) + self._log_control(byte) + return n + + def sendeof(self): + '''This sends an EOF to the child. This sends a character which causes + the pending parent output buffer to be sent to the waiting child + program without waiting for end-of-line. If it is the first character + of the line, the read() in the user program returns 0, which signifies + end-of-file. This means to work as expected a sendeof() has to be + called at the beginning of a line. This method does not send a newline. + It is the responsibility of the caller to ensure the eof is sent at the + beginning of a line. ''' + + n, byte = self.ptyproc.sendeof() + self._log_control(byte) + + def sendintr(self): + '''This sends a SIGINT to the child. It does not require + the SIGINT to be the first character on a line. ''' + + n, byte = self.ptyproc.sendintr() + self._log_control(byte) + + @property + def flag_eof(self): + return self.ptyproc.flag_eof + + @flag_eof.setter + def flag_eof(self, value): + self.ptyproc.flag_eof = value + + def eof(self): + '''This returns True if the EOF exception was ever raised. + ''' + return self.flag_eof + + def terminate(self, force=False): + '''This forces a child process to terminate. It starts nicely with + SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This + returns True if the child was terminated. This returns False if the + child could not be terminated. ''' + + if not self.isalive(): + return True + try: + self.kill(signal.SIGHUP) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + self.kill(signal.SIGCONT) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + self.kill(signal.SIGINT) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + if force: + self.kill(signal.SIGKILL) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + else: + return False + return False + except OSError: + # I think there are kernel timing issues that sometimes cause + # this to happen. I think isalive() reports True, but the + # process is dead to the kernel. + # Make one last attempt to see if the kernel is up to date. + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + else: + return False + + def wait(self): + '''This waits until the child exits. This is a blocking call. This will + not read any data from the child, so this will block forever if the + child has unread output and has terminated. In other words, the child + may have printed output then called exit(), but, the child is + technically still alive until its output is read by the parent. + + This method is non-blocking if :meth:`wait` has already been called + previously or :meth:`isalive` method returns False. It simply returns + the previously determined exit status. + ''' + + ptyproc = self.ptyproc + with _wrap_ptyprocess_err(): + # exception may occur if "Is some other process attempting + # "job control with our child pid?" + exitstatus = ptyproc.wait() + self.status = ptyproc.status + self.exitstatus = ptyproc.exitstatus + self.signalstatus = ptyproc.signalstatus + self.terminated = True + + return exitstatus + + def isalive(self): + '''This tests if the child process is running or not. This is + non-blocking. If the child was terminated then this will read the + exitstatus or signalstatus of the child. This returns True if the child + process appears to be running or False if not. It can take literally + SECONDS for Solaris to return the right status. ''' + + ptyproc = self.ptyproc + with _wrap_ptyprocess_err(): + alive = ptyproc.isalive() + + if not alive: + self.status = ptyproc.status + self.exitstatus = ptyproc.exitstatus + self.signalstatus = ptyproc.signalstatus + self.terminated = True + + return alive + + def kill(self, sig): + + '''This sends the given signal to the child application. In keeping + with UNIX tradition it has a misleading name. It does not necessarily + kill the child unless you send the right signal. ''' + + # Same as os.kill, but the pid is given for you. + if self.isalive(): + os.kill(self.pid, sig) + + def getwinsize(self): + '''This returns the terminal window size of the child tty. The return + value is a tuple of (rows, cols). ''' + return self.ptyproc.getwinsize() + + def setwinsize(self, rows, cols): + '''This sets the terminal window size of the child tty. This will cause + a SIGWINCH signal to be sent to the child. This does not change the + physical window size. It changes the size reported to TTY-aware + applications like vi or curses -- applications that respond to the + SIGWINCH signal. ''' + return self.ptyproc.setwinsize(rows, cols) + + + def interact(self, escape_character=chr(29), + input_filter=None, output_filter=None): + + '''This gives control of the child process to the interactive user (the + human at the keyboard). Keystrokes are sent to the child process, and + the stdout and stderr output of the child process is printed. This + simply echos the child stdout and child stderr to the real stdout and + it echos the real stdin to the child stdin. When the user types the + escape_character this method will return None. The escape_character + will not be transmitted. The default for escape_character is + entered as ``Ctrl - ]``, the very same as BSD telnet. To prevent + escaping, escape_character may be set to None. + + If a logfile is specified, then the data sent and received from the + child process in interact mode is duplicated to the given log. + + You may pass in optional input and output filter functions. These + functions should take a string and return a string. The output_filter + will be passed all the output from the child process. The input_filter + will be passed all the keyboard input from the user. The input_filter + is run BEFORE the check for the escape_character. + + Note that if you change the window size of the parent the SIGWINCH + signal will not be passed through to the child. If you want the child + window size to change when the parent's window size changes then do + something like the following example:: + + import pexpect, struct, fcntl, termios, signal, sys + def sigwinch_passthrough (sig, data): + s = struct.pack("HHHH", 0, 0, 0, 0) + a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), + termios.TIOCGWINSZ , s)) + global p + p.setwinsize(a[0],a[1]) + # Note this 'p' global and used in sigwinch_passthrough. + p = pexpect.spawn('/bin/bash') + signal.signal(signal.SIGWINCH, sigwinch_passthrough) + p.interact() + ''' + + # Flush the buffer. + self.write_to_stdout(self.buffer) + self.stdout.flush() + self.buffer = self.string_type() + mode = tty.tcgetattr(self.STDIN_FILENO) + tty.setraw(self.STDIN_FILENO) + if escape_character is not None and PY3: + escape_character = escape_character.encode('latin-1') + try: + self.__interact_copy(escape_character, input_filter, output_filter) + finally: + tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode) + + def __interact_writen(self, fd, data): + '''This is used by the interact() method. + ''' + + while data != b'' and self.isalive(): + n = os.write(fd, data) + data = data[n:] + + def __interact_read(self, fd): + '''This is used by the interact() method. + ''' + + return os.read(fd, 1000) + + def __interact_copy(self, escape_character=None, + input_filter=None, output_filter=None): + + '''This is used by the interact() method. + ''' + + while self.isalive(): + r, w, e = select_ignore_interrupts([self.child_fd, self.STDIN_FILENO], [], []) + if self.child_fd in r: + try: + data = self.__interact_read(self.child_fd) + except OSError as err: + if err.args[0] == errno.EIO: + # Linux-style EOF + break + raise + if data == b'': + # BSD-style EOF + break + if output_filter: + data = output_filter(data) + self._log(data, 'read') + os.write(self.STDOUT_FILENO, data) + if self.STDIN_FILENO in r: + data = self.__interact_read(self.STDIN_FILENO) + if input_filter: + data = input_filter(data) + i = -1 + if escape_character is not None: + i = data.rfind(escape_character) + if i != -1: + data = data[:i] + if data: + self._log(data, 'send') + self.__interact_writen(self.child_fd, data) + break + self._log(data, 'send') + self.__interact_writen(self.child_fd, data) + + +def spawnu(*args, **kwargs): + """Deprecated: pass encoding to spawn() instead.""" + kwargs.setdefault('encoding', 'utf-8') + return spawn(*args, **kwargs) diff --git a/pipenv/vendor/pexpect/pxssh.py b/pipenv/vendor/pexpect/pxssh.py new file mode 100644 index 00000000..a9c01d53 --- /dev/null +++ b/pipenv/vendor/pexpect/pxssh.py @@ -0,0 +1,409 @@ +'''This class extends pexpect.spawn to specialize setting up SSH connections. +This adds methods for login, logout, and expecting the shell prompt. + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +from pexpect import ExceptionPexpect, TIMEOUT, EOF, spawn +import time +import os + +__all__ = ['ExceptionPxssh', 'pxssh'] + +# Exception classes used by this module. +class ExceptionPxssh(ExceptionPexpect): + '''Raised for pxssh exceptions. + ''' + +class pxssh (spawn): + '''This class extends pexpect.spawn to specialize setting up SSH + connections. This adds methods for login, logout, and expecting the shell + prompt. It does various tricky things to handle many situations in the SSH + login process. For example, if the session is your first login, then pxssh + automatically accepts the remote certificate; or if you have public key + authentication setup then pxssh won't wait for the password prompt. + + pxssh uses the shell prompt to synchronize output from the remote host. In + order to make this more robust it sets the shell prompt to something more + unique than just $ or #. This should work on most Borne/Bash or Csh style + shells. + + Example that runs a few commands on a remote server and prints the result:: + + from pexpect import pxssh + import getpass + try: + s = pxssh.pxssh() + hostname = raw_input('hostname: ') + username = raw_input('username: ') + password = getpass.getpass('password: ') + s.login(hostname, username, password) + s.sendline('uptime') # run a command + s.prompt() # match the prompt + print(s.before) # print everything before the prompt. + s.sendline('ls -l') + s.prompt() + print(s.before) + s.sendline('df') + s.prompt() + print(s.before) + s.logout() + except pxssh.ExceptionPxssh as e: + print("pxssh failed on login.") + print(e) + + Example showing how to specify SSH options:: + + from pexpect import pxssh + s = pxssh.pxssh(options={ + "StrictHostKeyChecking": "no", + "UserKnownHostsFile": "/dev/null"}) + ... + + Note that if you have ssh-agent running while doing development with pxssh + then this can lead to a lot of confusion. Many X display managers (xdm, + gdm, kdm, etc.) will automatically start a GUI agent. You may see a GUI + dialog box popup asking for a password during development. You should turn + off any key agents during testing. The 'force_password' attribute will turn + off public key authentication. This will only work if the remote SSH server + is configured to allow password logins. Example of using 'force_password' + attribute:: + + s = pxssh.pxssh() + s.force_password = True + hostname = raw_input('hostname: ') + username = raw_input('username: ') + password = getpass.getpass('password: ') + s.login (hostname, username, password) + ''' + + def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None, + logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True, + options={}, encoding=None, codec_errors='strict'): + + spawn.__init__(self, None, timeout=timeout, maxread=maxread, + searchwindowsize=searchwindowsize, logfile=logfile, + cwd=cwd, env=env, ignore_sighup=ignore_sighup, echo=echo, + encoding=encoding, codec_errors=codec_errors) + + self.name = '' + + #SUBTLE HACK ALERT! Note that the command that SETS the prompt uses a + #slightly different string than the regular expression to match it. This + #is because when you set the prompt the command will echo back, but we + #don't want to match the echoed command. So if we make the set command + #slightly different than the regex we eliminate the problem. To make the + #set command different we add a backslash in front of $. The $ doesn't + #need to be escaped, but it doesn't hurt and serves to make the set + #prompt command different than the regex. + + # used to match the command-line prompt + self.UNIQUE_PROMPT = "\[PEXPECT\][\$\#] " + self.PROMPT = self.UNIQUE_PROMPT + + # used to set shell command-line prompt to UNIQUE_PROMPT. + self.PROMPT_SET_SH = "PS1='[PEXPECT]\$ '" + self.PROMPT_SET_CSH = "set prompt='[PEXPECT]\$ '" + self.SSH_OPTS = ("-o'RSAAuthentication=no'" + + " -o 'PubkeyAuthentication=no'") +# Disabling host key checking, makes you vulnerable to MITM attacks. +# + " -o 'StrictHostKeyChecking=no'" +# + " -o 'UserKnownHostsFile /dev/null' ") + # Disabling X11 forwarding gets rid of the annoying SSH_ASKPASS from + # displaying a GUI password dialog. I have not figured out how to + # disable only SSH_ASKPASS without also disabling X11 forwarding. + # Unsetting SSH_ASKPASS on the remote side doesn't disable it! Annoying! + #self.SSH_OPTS = "-x -o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'" + self.force_password = False + + # User defined SSH options, eg, + # ssh.otions = dict(StrictHostKeyChecking="no",UserKnownHostsFile="/dev/null") + self.options = options + + def levenshtein_distance(self, a, b): + '''This calculates the Levenshtein distance between a and b. + ''' + + n, m = len(a), len(b) + if n > m: + a,b = b,a + n,m = m,n + current = range(n+1) + for i in range(1,m+1): + previous, current = current, [i]+[0]*n + for j in range(1,n+1): + add, delete = previous[j]+1, current[j-1]+1 + change = previous[j-1] + if a[j-1] != b[i-1]: + change = change + 1 + current[j] = min(add, delete, change) + return current[n] + + def try_read_prompt(self, timeout_multiplier): + '''This facilitates using communication timeouts to perform + synchronization as quickly as possible, while supporting high latency + connections with a tunable worst case performance. Fast connections + should be read almost immediately. Worst case performance for this + method is timeout_multiplier * 3 seconds. + ''' + + # maximum time allowed to read the first response + first_char_timeout = timeout_multiplier * 0.5 + + # maximum time allowed between subsequent characters + inter_char_timeout = timeout_multiplier * 0.1 + + # maximum time for reading the entire prompt + total_timeout = timeout_multiplier * 3.0 + + prompt = self.string_type() + begin = time.time() + expired = 0.0 + timeout = first_char_timeout + + while expired < total_timeout: + try: + prompt += self.read_nonblocking(size=1, timeout=timeout) + expired = time.time() - begin # updated total time expired + timeout = inter_char_timeout + except TIMEOUT: + break + + return prompt + + def sync_original_prompt (self, sync_multiplier=1.0): + '''This attempts to find the prompt. Basically, press enter and record + the response; press enter again and record the response; if the two + responses are similar then assume we are at the original prompt. + This can be a slow function. Worst case with the default sync_multiplier + can take 12 seconds. Low latency connections are more likely to fail + with a low sync_multiplier. Best case sync time gets worse with a + high sync multiplier (500 ms with default). ''' + + # All of these timing pace values are magic. + # I came up with these based on what seemed reliable for + # connecting to a heavily loaded machine I have. + self.sendline() + time.sleep(0.1) + + try: + # Clear the buffer before getting the prompt. + self.try_read_prompt(sync_multiplier) + except TIMEOUT: + pass + + self.sendline() + x = self.try_read_prompt(sync_multiplier) + + self.sendline() + a = self.try_read_prompt(sync_multiplier) + + self.sendline() + b = self.try_read_prompt(sync_multiplier) + + ld = self.levenshtein_distance(a,b) + len_a = len(a) + if len_a == 0: + return False + if float(ld)/len_a < 0.4: + return True + return False + + ### TODO: This is getting messy and I'm pretty sure this isn't perfect. + ### TODO: I need to draw a flow chart for this. + def login (self, server, username, password='', terminal_type='ansi', + original_prompt=r"[#$]", login_timeout=10, port=None, + auto_prompt_reset=True, ssh_key=None, quiet=True, + sync_multiplier=1, check_local_ip=True): + '''This logs the user into the given server. + + It uses + 'original_prompt' to try to find the prompt right after login. When it + finds the prompt it immediately tries to reset the prompt to something + more easily matched. The default 'original_prompt' is very optimistic + and is easily fooled. It's more reliable to try to match the original + prompt as exactly as possible to prevent false matches by server + strings such as the "Message Of The Day". On many systems you can + disable the MOTD on the remote server by creating a zero-length file + called :file:`~/.hushlogin` on the remote server. If a prompt cannot be found + then this will not necessarily cause the login to fail. In the case of + a timeout when looking for the prompt we assume that the original + prompt was so weird that we could not match it, so we use a few tricks + to guess when we have reached the prompt. Then we hope for the best and + blindly try to reset the prompt to something more unique. If that fails + then login() raises an :class:`ExceptionPxssh` exception. + + In some situations it is not possible or desirable to reset the + original prompt. In this case, pass ``auto_prompt_reset=False`` to + inhibit setting the prompt to the UNIQUE_PROMPT. Remember that pxssh + uses a unique prompt in the :meth:`prompt` method. If the original prompt is + not reset then this will disable the :meth:`prompt` method unless you + manually set the :attr:`PROMPT` attribute. + ''' + + ssh_options = ''.join([" -o '%s=%s'" % (o, v) for (o, v) in self.options.items()]) + if quiet: + ssh_options = ssh_options + ' -q' + if not check_local_ip: + ssh_options = ssh_options + " -o'NoHostAuthenticationForLocalhost=yes'" + if self.force_password: + ssh_options = ssh_options + ' ' + self.SSH_OPTS + if port is not None: + ssh_options = ssh_options + ' -p %s'%(str(port)) + if ssh_key is not None: + try: + os.path.isfile(ssh_key) + except: + raise ExceptionPxssh('private ssh key does not exist') + ssh_options = ssh_options + ' -i %s' % (ssh_key) + cmd = "ssh %s -l %s %s" % (ssh_options, username, server) + + # This does not distinguish between a remote server 'password' prompt + # and a local ssh 'passphrase' prompt (for unlocking a private key). + spawn._spawn(self, cmd) + i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT, "(?i)connection closed by remote host", EOF], timeout=login_timeout) + + # First phase + if i==0: + # New certificate -- always accept it. + # This is what you get if SSH does not have the remote host's + # public key stored in the 'known_hosts' cache. + self.sendline("yes") + i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT]) + if i==2: # password or passphrase + self.sendline(password) + i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT]) + if i==4: + self.sendline(terminal_type) + i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT]) + if i==7: + self.close() + raise ExceptionPxssh('Could not establish connection to host') + + # Second phase + if i==0: + # This is weird. This should not happen twice in a row. + self.close() + raise ExceptionPxssh('Weird error. Got "are you sure" prompt twice.') + elif i==1: # can occur if you have a public key pair set to authenticate. + ### TODO: May NOT be OK if expect() got tricked and matched a false prompt. + pass + elif i==2: # password prompt again + # For incorrect passwords, some ssh servers will + # ask for the password again, others return 'denied' right away. + # If we get the password prompt again then this means + # we didn't get the password right the first time. + self.close() + raise ExceptionPxssh('password refused') + elif i==3: # permission denied -- password was bad. + self.close() + raise ExceptionPxssh('permission denied') + elif i==4: # terminal type again? WTF? + self.close() + raise ExceptionPxssh('Weird error. Got "terminal type" prompt twice.') + elif i==5: # Timeout + #This is tricky... I presume that we are at the command-line prompt. + #It may be that the shell prompt was so weird that we couldn't match + #it. Or it may be that we couldn't log in for some other reason. I + #can't be sure, but it's safe to guess that we did login because if + #I presume wrong and we are not logged in then this should be caught + #later when I try to set the shell prompt. + pass + elif i==6: # Connection closed by remote host + self.close() + raise ExceptionPxssh('connection closed') + else: # Unexpected + self.close() + raise ExceptionPxssh('unexpected login response') + if not self.sync_original_prompt(sync_multiplier): + self.close() + raise ExceptionPxssh('could not synchronize with original prompt') + # We appear to be in. + # set shell prompt to something unique. + if auto_prompt_reset: + if not self.set_unique_prompt(): + self.close() + raise ExceptionPxssh('could not set shell prompt ' + '(received: %r, expected: %r).' % ( + self.before, self.PROMPT,)) + return True + + def logout (self): + '''Sends exit to the remote shell. + + If there are stopped jobs then this automatically sends exit twice. + ''' + self.sendline("exit") + index = self.expect([EOF, "(?i)there are stopped jobs"]) + if index==1: + self.sendline("exit") + self.expect(EOF) + self.close() + + def prompt(self, timeout=-1): + '''Match the next shell prompt. + + This is little more than a short-cut to the :meth:`~pexpect.spawn.expect` + method. Note that if you called :meth:`login` with + ``auto_prompt_reset=False``, then before calling :meth:`prompt` you must + set the :attr:`PROMPT` attribute to a regex that it will use for + matching the prompt. + + Calling :meth:`prompt` will erase the contents of the :attr:`before` + attribute even if no prompt is ever matched. If timeout is not given or + it is set to -1 then self.timeout is used. + + :return: True if the shell prompt was matched, False if the timeout was + reached. + ''' + + if timeout == -1: + timeout = self.timeout + i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout) + if i==1: + return False + return True + + def set_unique_prompt(self): + '''This sets the remote prompt to something more unique than ``#`` or ``$``. + This makes it easier for the :meth:`prompt` method to match the shell prompt + unambiguously. This method is called automatically by the :meth:`login` + method, but you may want to call it manually if you somehow reset the + shell prompt. For example, if you 'su' to a different user then you + will need to manually reset the prompt. This sends shell commands to + the remote host to set the prompt, so this assumes the remote host is + ready to receive commands. + + Alternatively, you may use your own prompt pattern. In this case you + should call :meth:`login` with ``auto_prompt_reset=False``; then set the + :attr:`PROMPT` attribute to a regular expression. After that, the + :meth:`prompt` method will try to match your prompt pattern. + ''' + + self.sendline("unset PROMPT_COMMAND") + self.sendline(self.PROMPT_SET_SH) # sh-style + i = self.expect ([TIMEOUT, self.PROMPT], timeout=10) + if i == 0: # csh-style + self.sendline(self.PROMPT_SET_CSH) + i = self.expect([TIMEOUT, self.PROMPT], timeout=10) + if i == 0: + return False + return True + +# vi:ts=4:sw=4:expandtab:ft=python: diff --git a/pipenv/vendor/pexpect/replwrap.py b/pipenv/vendor/pexpect/replwrap.py new file mode 100644 index 00000000..118aa9f2 --- /dev/null +++ b/pipenv/vendor/pexpect/replwrap.py @@ -0,0 +1,122 @@ +"""Generic wrapper for read-eval-print-loops, a.k.a. interactive shells +""" +import os.path +import signal +import sys + +import pexpect + +PY3 = (sys.version_info[0] >= 3) + +if PY3: + basestring = str + +PEXPECT_PROMPT = u'[PEXPECT_PROMPT>' +PEXPECT_CONTINUATION_PROMPT = u'[PEXPECT_PROMPT+' + +class REPLWrapper(object): + """Wrapper for a REPL. + + :param cmd_or_spawn: This can either be an instance of :class:`pexpect.spawn` + in which a REPL has already been started, or a str command to start a new + REPL process. + :param str orig_prompt: The prompt to expect at first. + :param str prompt_change: A command to change the prompt to something more + unique. If this is ``None``, the prompt will not be changed. This will + be formatted with the new and continuation prompts as positional + parameters, so you can use ``{}`` style formatting to insert them into + the command. + :param str new_prompt: The more unique prompt to expect after the change. + :param str extra_init_cmd: Commands to do extra initialisation, such as + disabling pagers. + """ + def __init__(self, cmd_or_spawn, orig_prompt, prompt_change, + new_prompt=PEXPECT_PROMPT, + continuation_prompt=PEXPECT_CONTINUATION_PROMPT, + extra_init_cmd=None): + if isinstance(cmd_or_spawn, basestring): + self.child = pexpect.spawn(cmd_or_spawn, echo=False, encoding='utf-8') + else: + self.child = cmd_or_spawn + if self.child.echo: + # Existing spawn instance has echo enabled, disable it + # to prevent our input from being repeated to output. + self.child.setecho(False) + self.child.waitnoecho() + + if prompt_change is None: + self.prompt = orig_prompt + else: + self.set_prompt(orig_prompt, + prompt_change.format(new_prompt, continuation_prompt)) + self.prompt = new_prompt + self.continuation_prompt = continuation_prompt + + self._expect_prompt() + + if extra_init_cmd is not None: + self.run_command(extra_init_cmd) + + def set_prompt(self, orig_prompt, prompt_change): + self.child.expect(orig_prompt) + self.child.sendline(prompt_change) + + def _expect_prompt(self, timeout=-1): + return self.child.expect_exact([self.prompt, self.continuation_prompt], + timeout=timeout) + + def run_command(self, command, timeout=-1): + """Send a command to the REPL, wait for and return output. + + :param str command: The command to send. Trailing newlines are not needed. + This should be a complete block of input that will trigger execution; + if a continuation prompt is found after sending input, :exc:`ValueError` + will be raised. + :param int timeout: How long to wait for the next prompt. -1 means the + default from the :class:`pexpect.spawn` object (default 30 seconds). + None means to wait indefinitely. + """ + # Split up multiline commands and feed them in bit-by-bit + cmdlines = command.splitlines() + # splitlines ignores trailing newlines - add it back in manually + if command.endswith('\n'): + cmdlines.append('') + if not cmdlines: + raise ValueError("No command was given") + + res = [] + self.child.sendline(cmdlines[0]) + for line in cmdlines[1:]: + self._expect_prompt(timeout=timeout) + res.append(self.child.before) + self.child.sendline(line) + + # Command was fully submitted, now wait for the next prompt + if self._expect_prompt(timeout=timeout) == 1: + # We got the continuation prompt - command was incomplete + self.child.kill(signal.SIGINT) + self._expect_prompt(timeout=1) + raise ValueError("Continuation prompt found - input was incomplete:\n" + + command) + return u''.join(res + [self.child.before]) + +def python(command="python"): + """Start a Python shell and return a :class:`REPLWrapper` object.""" + return REPLWrapper(command, u">>> ", u"import sys; sys.ps1={0!r}; sys.ps2={1!r}") + +def bash(command="bash"): + """Start a bash shell and return a :class:`REPLWrapper` object.""" + bashrc = os.path.join(os.path.dirname(__file__), 'bashrc.sh') + child = pexpect.spawn(command, ['--rcfile', bashrc], echo=False, + encoding='utf-8') + + # If the user runs 'env', the value of PS1 will be in the output. To avoid + # replwrap seeing that as the next prompt, we'll embed the marker characters + # for invisible characters in the prompt; these show up when inspecting the + # environment variable, but not when bash displays the prompt. + ps1 = PEXPECT_PROMPT[:5] + u'\[\]' + PEXPECT_PROMPT[5:] + ps2 = PEXPECT_CONTINUATION_PROMPT[:5] + u'\[\]' + PEXPECT_CONTINUATION_PROMPT[5:] + prompt_change = u"PS1='{0}' PS2='{1}' PROMPT_COMMAND=''".format(ps1, ps2) + + return REPLWrapper(child, u'\$', prompt_change, + extra_init_cmd="export PAGER=cat") diff --git a/pipenv/vendor/pexpect/run.py b/pipenv/vendor/pexpect/run.py new file mode 100644 index 00000000..d9dfe76b --- /dev/null +++ b/pipenv/vendor/pexpect/run.py @@ -0,0 +1,157 @@ +import sys +import types + +from .exceptions import EOF, TIMEOUT +from .pty_spawn import spawn + +def run(command, timeout=30, withexitstatus=False, events=None, + extra_args=None, logfile=None, cwd=None, env=None, **kwargs): + + ''' + This function runs the given command; waits for it to finish; then + returns all output as a string. STDERR is included in output. If the full + path to the command is not given then the path is searched. + + Note that lines are terminated by CR/LF (\\r\\n) combination even on + UNIX-like systems because this is the standard for pseudottys. If you set + 'withexitstatus' to true, then run will return a tuple of (command_output, + exitstatus). If 'withexitstatus' is false then this returns just + command_output. + + The run() function can often be used instead of creating a spawn instance. + For example, the following code uses spawn:: + + from pexpect import * + child = spawn('scp foo user@example.com:.') + child.expect('(?i)password') + child.sendline(mypassword) + + The previous code can be replace with the following:: + + from pexpect import * + run('scp foo user@example.com:.', events={'(?i)password': mypassword}) + + **Examples** + + Start the apache daemon on the local machine:: + + from pexpect import * + run("/usr/local/apache/bin/apachectl start") + + Check in a file using SVN:: + + from pexpect import * + run("svn ci -m 'automatic commit' my_file.py") + + Run a command and capture exit status:: + + from pexpect import * + (command_output, exitstatus) = run('ls -l /bin', withexitstatus=1) + + The following will run SSH and execute 'ls -l' on the remote machine. The + password 'secret' will be sent if the '(?i)password' pattern is ever seen:: + + run("ssh username@machine.example.com 'ls -l'", + events={'(?i)password':'secret\\n'}) + + This will start mencoder to rip a video from DVD. This will also display + progress ticks every 5 seconds as it runs. For example:: + + from pexpect import * + def print_ticks(d): + print d['event_count'], + run("mencoder dvd://1 -o video.avi -oac copy -ovc copy", + events={TIMEOUT:print_ticks}, timeout=5) + + The 'events' argument should be either a dictionary or a tuple list that + contains patterns and responses. Whenever one of the patterns is seen + in the command output, run() will send the associated response string. + So, run() in the above example can be also written as: + + run("mencoder dvd://1 -o video.avi -oac copy -ovc copy", + events=[(TIMEOUT,print_ticks)], timeout=5) + + Use a tuple list for events if the command output requires a delicate + control over what pattern should be matched, since the tuple list is passed + to pexpect() as its pattern list, with the order of patterns preserved. + + Note that you should put newlines in your string if Enter is necessary. + + Like the example above, the responses may also contain a callback, either + a function or method. It should accept a dictionary value as an argument. + The dictionary contains all the locals from the run() function, so you can + access the child spawn object or any other variable defined in run() + (event_count, child, and extra_args are the most useful). A callback may + return True to stop the current run process. Otherwise run() continues + until the next event. A callback may also return a string which will be + sent to the child. 'extra_args' is not used by directly run(). It provides + a way to pass data to a callback function through run() through the locals + dictionary passed to a callback. + + Like :class:`spawn`, passing *encoding* will make it work with unicode + instead of bytes. You can pass *codec_errors* to control how errors in + encoding and decoding are handled. + ''' + if timeout == -1: + child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env, + **kwargs) + else: + child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile, + cwd=cwd, env=env, **kwargs) + if isinstance(events, list): + patterns= [x for x,y in events] + responses = [y for x,y in events] + elif isinstance(events, dict): + patterns = list(events.keys()) + responses = list(events.values()) + else: + # This assumes EOF or TIMEOUT will eventually cause run to terminate. + patterns = None + responses = None + child_result_list = [] + event_count = 0 + while True: + try: + index = child.expect(patterns) + if isinstance(child.after, child.allowed_string_types): + child_result_list.append(child.before + child.after) + else: + # child.after may have been a TIMEOUT or EOF, + # which we don't want appended to the list. + child_result_list.append(child.before) + if isinstance(responses[index], child.allowed_string_types): + child.send(responses[index]) + elif (isinstance(responses[index], types.FunctionType) or + isinstance(responses[index], types.MethodType)): + callback_result = responses[index](locals()) + sys.stdout.flush() + if isinstance(callback_result, child.allowed_string_types): + child.send(callback_result) + elif callback_result: + break + else: + raise TypeError("parameter `event' at index {index} must be " + "a string, method, or function: {value!r}" + .format(index=index, value=responses[index])) + event_count = event_count + 1 + except TIMEOUT: + child_result_list.append(child.before) + break + except EOF: + child_result_list.append(child.before) + break + child_result = child.string_type().join(child_result_list) + if withexitstatus: + child.close() + return (child_result, child.exitstatus) + else: + return child_result + +def runu(command, timeout=30, withexitstatus=False, events=None, + extra_args=None, logfile=None, cwd=None, env=None, **kwargs): + """Deprecated: pass encoding to run() instead. + """ + kwargs.setdefault('encoding', 'utf-8') + return run(command, timeout=timeout, withexitstatus=withexitstatus, + events=events, extra_args=extra_args, logfile=logfile, cwd=cwd, + env=env, **kwargs) diff --git a/pipenv/vendor/pexpect/screen.py b/pipenv/vendor/pexpect/screen.py new file mode 100644 index 00000000..0bced89d --- /dev/null +++ b/pipenv/vendor/pexpect/screen.py @@ -0,0 +1,431 @@ +'''This implements a virtual screen. This is used to support ANSI terminal +emulation. The screen representation and state is implemented in this class. +Most of the methods are inspired by ANSI screen control codes. The +:class:`~pexpect.ANSI.ANSI` class extends this class to add parsing of ANSI +escape codes. + +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import codecs +import copy +import sys + +import warnings + +warnings.warn(("pexpect.screen and pexpect.ANSI are deprecated. " + "We recommend using pyte to emulate a terminal screen: " + "https://pypi.python.org/pypi/pyte"), + stacklevel=2) + +NUL = 0 # Fill character; ignored on input. +ENQ = 5 # Transmit answerback message. +BEL = 7 # Ring the bell. +BS = 8 # Move cursor left. +HT = 9 # Move cursor to next tab stop. +LF = 10 # Line feed. +VT = 11 # Same as LF. +FF = 12 # Same as LF. +CR = 13 # Move cursor to left margin or newline. +SO = 14 # Invoke G1 character set. +SI = 15 # Invoke G0 character set. +XON = 17 # Resume transmission. +XOFF = 19 # Halt transmission. +CAN = 24 # Cancel escape sequence. +SUB = 26 # Same as CAN. +ESC = 27 # Introduce a control sequence. +DEL = 127 # Fill character; ignored on input. +SPACE = u' ' # Space or blank character. + +PY3 = (sys.version_info[0] >= 3) +if PY3: + unicode = str + +def constrain (n, min, max): + + '''This returns a number, n constrained to the min and max bounds. ''' + + if n < min: + return min + if n > max: + return max + return n + +class screen: + '''This object maintains the state of a virtual text screen as a + rectangluar array. This maintains a virtual cursor position and handles + scrolling as characters are added. This supports most of the methods needed + by an ANSI text screen. Row and column indexes are 1-based (not zero-based, + like arrays). + + Characters are represented internally using unicode. Methods that accept + input characters, when passed 'bytes' (which in Python 2 is equivalent to + 'str'), convert them from the encoding specified in the 'encoding' + parameter to the constructor. Methods that return screen contents return + unicode strings, with the exception of __str__() under Python 2. Passing + ``encoding=None`` limits the API to only accept unicode input, so passing + bytes in will raise :exc:`TypeError`. + ''' + def __init__(self, r=24, c=80, encoding='latin-1', encoding_errors='replace'): + '''This initializes a blank screen of the given dimensions.''' + + self.rows = r + self.cols = c + self.encoding = encoding + self.encoding_errors = encoding_errors + if encoding is not None: + self.decoder = codecs.getincrementaldecoder(encoding)(encoding_errors) + else: + self.decoder = None + self.cur_r = 1 + self.cur_c = 1 + self.cur_saved_r = 1 + self.cur_saved_c = 1 + self.scroll_row_start = 1 + self.scroll_row_end = self.rows + self.w = [ [SPACE] * self.cols for _ in range(self.rows)] + + def _decode(self, s): + '''This converts from the external coding system (as passed to + the constructor) to the internal one (unicode). ''' + if self.decoder is not None: + return self.decoder.decode(s) + else: + raise TypeError("This screen was constructed with encoding=None, " + "so it does not handle bytes.") + + def _unicode(self): + '''This returns a printable representation of the screen as a unicode + string (which, under Python 3.x, is the same as 'str'). The end of each + screen line is terminated by a newline.''' + + return u'\n'.join ([ u''.join(c) for c in self.w ]) + + if PY3: + __str__ = _unicode + else: + __unicode__ = _unicode + + def __str__(self): + '''This returns a printable representation of the screen. The end of + each screen line is terminated by a newline. ''' + encoding = self.encoding or 'ascii' + return self._unicode().encode(encoding, 'replace') + + def dump (self): + '''This returns a copy of the screen as a unicode string. This is similar to + __str__/__unicode__ except that lines are not terminated with line + feeds.''' + + return u''.join ([ u''.join(c) for c in self.w ]) + + def pretty (self): + '''This returns a copy of the screen as a unicode string with an ASCII + text box around the screen border. This is similar to + __str__/__unicode__ except that it adds a box.''' + + top_bot = u'+' + u'-'*self.cols + u'+\n' + return top_bot + u'\n'.join([u'|'+line+u'|' for line in unicode(self).split(u'\n')]) + u'\n' + top_bot + + def fill (self, ch=SPACE): + + if isinstance(ch, bytes): + ch = self._decode(ch) + + self.fill_region (1,1,self.rows,self.cols, ch) + + def fill_region (self, rs,cs, re,ce, ch=SPACE): + + if isinstance(ch, bytes): + ch = self._decode(ch) + + rs = constrain (rs, 1, self.rows) + re = constrain (re, 1, self.rows) + cs = constrain (cs, 1, self.cols) + ce = constrain (ce, 1, self.cols) + if rs > re: + rs, re = re, rs + if cs > ce: + cs, ce = ce, cs + for r in range (rs, re+1): + for c in range (cs, ce + 1): + self.put_abs (r,c,ch) + + def cr (self): + '''This moves the cursor to the beginning (col 1) of the current row. + ''' + + self.cursor_home (self.cur_r, 1) + + def lf (self): + '''This moves the cursor down with scrolling. + ''' + + old_r = self.cur_r + self.cursor_down() + if old_r == self.cur_r: + self.scroll_up () + self.erase_line() + + def crlf (self): + '''This advances the cursor with CRLF properties. + The cursor will line wrap and the screen may scroll. + ''' + + self.cr () + self.lf () + + def newline (self): + '''This is an alias for crlf(). + ''' + + self.crlf() + + def put_abs (self, r, c, ch): + '''Screen array starts at 1 index.''' + + r = constrain (r, 1, self.rows) + c = constrain (c, 1, self.cols) + if isinstance(ch, bytes): + ch = self._decode(ch)[0] + else: + ch = ch[0] + self.w[r-1][c-1] = ch + + def put (self, ch): + '''This puts a characters at the current cursor position. + ''' + + if isinstance(ch, bytes): + ch = self._decode(ch) + + self.put_abs (self.cur_r, self.cur_c, ch) + + def insert_abs (self, r, c, ch): + '''This inserts a character at (r,c). Everything under + and to the right is shifted right one character. + The last character of the line is lost. + ''' + + if isinstance(ch, bytes): + ch = self._decode(ch) + + r = constrain (r, 1, self.rows) + c = constrain (c, 1, self.cols) + for ci in range (self.cols, c, -1): + self.put_abs (r,ci, self.get_abs(r,ci-1)) + self.put_abs (r,c,ch) + + def insert (self, ch): + + if isinstance(ch, bytes): + ch = self._decode(ch) + + self.insert_abs (self.cur_r, self.cur_c, ch) + + def get_abs (self, r, c): + + r = constrain (r, 1, self.rows) + c = constrain (c, 1, self.cols) + return self.w[r-1][c-1] + + def get (self): + + self.get_abs (self.cur_r, self.cur_c) + + def get_region (self, rs,cs, re,ce): + '''This returns a list of lines representing the region. + ''' + + rs = constrain (rs, 1, self.rows) + re = constrain (re, 1, self.rows) + cs = constrain (cs, 1, self.cols) + ce = constrain (ce, 1, self.cols) + if rs > re: + rs, re = re, rs + if cs > ce: + cs, ce = ce, cs + sc = [] + for r in range (rs, re+1): + line = u'' + for c in range (cs, ce + 1): + ch = self.get_abs (r,c) + line = line + ch + sc.append (line) + return sc + + def cursor_constrain (self): + '''This keeps the cursor within the screen area. + ''' + + self.cur_r = constrain (self.cur_r, 1, self.rows) + self.cur_c = constrain (self.cur_c, 1, self.cols) + + def cursor_home (self, r=1, c=1): # [{ROW};{COLUMN}H + + self.cur_r = r + self.cur_c = c + self.cursor_constrain () + + def cursor_back (self,count=1): # [{COUNT}D (not confused with down) + + self.cur_c = self.cur_c - count + self.cursor_constrain () + + def cursor_down (self,count=1): # [{COUNT}B (not confused with back) + + self.cur_r = self.cur_r + count + self.cursor_constrain () + + def cursor_forward (self,count=1): # [{COUNT}C + + self.cur_c = self.cur_c + count + self.cursor_constrain () + + def cursor_up (self,count=1): # [{COUNT}A + + self.cur_r = self.cur_r - count + self.cursor_constrain () + + def cursor_up_reverse (self): # M (called RI -- Reverse Index) + + old_r = self.cur_r + self.cursor_up() + if old_r == self.cur_r: + self.scroll_up() + + def cursor_force_position (self, r, c): # [{ROW};{COLUMN}f + '''Identical to Cursor Home.''' + + self.cursor_home (r, c) + + def cursor_save (self): # [s + '''Save current cursor position.''' + + self.cursor_save_attrs() + + def cursor_unsave (self): # [u + '''Restores cursor position after a Save Cursor.''' + + self.cursor_restore_attrs() + + def cursor_save_attrs (self): # 7 + '''Save current cursor position.''' + + self.cur_saved_r = self.cur_r + self.cur_saved_c = self.cur_c + + def cursor_restore_attrs (self): # 8 + '''Restores cursor position after a Save Cursor.''' + + self.cursor_home (self.cur_saved_r, self.cur_saved_c) + + def scroll_constrain (self): + '''This keeps the scroll region within the screen region.''' + + if self.scroll_row_start <= 0: + self.scroll_row_start = 1 + if self.scroll_row_end > self.rows: + self.scroll_row_end = self.rows + + def scroll_screen (self): # [r + '''Enable scrolling for entire display.''' + + self.scroll_row_start = 1 + self.scroll_row_end = self.rows + + def scroll_screen_rows (self, rs, re): # [{start};{end}r + '''Enable scrolling from row {start} to row {end}.''' + + self.scroll_row_start = rs + self.scroll_row_end = re + self.scroll_constrain() + + def scroll_down (self): # D + '''Scroll display down one line.''' + + # Screen is indexed from 1, but arrays are indexed from 0. + s = self.scroll_row_start - 1 + e = self.scroll_row_end - 1 + self.w[s+1:e+1] = copy.deepcopy(self.w[s:e]) + + def scroll_up (self): # M + '''Scroll display up one line.''' + + # Screen is indexed from 1, but arrays are indexed from 0. + s = self.scroll_row_start - 1 + e = self.scroll_row_end - 1 + self.w[s:e] = copy.deepcopy(self.w[s+1:e+1]) + + def erase_end_of_line (self): # [0K -or- [K + '''Erases from the current cursor position to the end of the current + line.''' + + self.fill_region (self.cur_r, self.cur_c, self.cur_r, self.cols) + + def erase_start_of_line (self): # [1K + '''Erases from the current cursor position to the start of the current + line.''' + + self.fill_region (self.cur_r, 1, self.cur_r, self.cur_c) + + def erase_line (self): # [2K + '''Erases the entire current line.''' + + self.fill_region (self.cur_r, 1, self.cur_r, self.cols) + + def erase_down (self): # [0J -or- [J + '''Erases the screen from the current line down to the bottom of the + screen.''' + + self.erase_end_of_line () + self.fill_region (self.cur_r + 1, 1, self.rows, self.cols) + + def erase_up (self): # [1J + '''Erases the screen from the current line up to the top of the + screen.''' + + self.erase_start_of_line () + self.fill_region (self.cur_r-1, 1, 1, self.cols) + + def erase_screen (self): # [2J + '''Erases the screen with the background color.''' + + self.fill () + + def set_tab (self): # H + '''Sets a tab at the current position.''' + + pass + + def clear_tab (self): # [g + '''Clears tab at the current position.''' + + pass + + def clear_all_tabs (self): # [3g + '''Clears all tabs.''' + + pass + +# Insert line Esc [ Pn L +# Delete line Esc [ Pn M +# Delete character Esc [ Pn P +# Scrolling region Esc [ Pn(top);Pn(bot) r + diff --git a/pipenv/vendor/pexpect/spawnbase.py b/pipenv/vendor/pexpect/spawnbase.py new file mode 100644 index 00000000..5dd24b56 --- /dev/null +++ b/pipenv/vendor/pexpect/spawnbase.py @@ -0,0 +1,494 @@ +import codecs +import os +import sys +import re +import errno +from .exceptions import ExceptionPexpect, EOF, TIMEOUT +from .expect import Expecter, searcher_string, searcher_re + +PY3 = (sys.version_info[0] >= 3) +text_type = str if PY3 else unicode + +class _NullCoder(object): + """Pass bytes through unchanged.""" + @staticmethod + def encode(b, final=False): + return b + + @staticmethod + def decode(b, final=False): + return b + +class SpawnBase(object): + """A base class providing the backwards-compatible spawn API for Pexpect. + + This should not be instantiated directly: use :class:`pexpect.spawn` or + :class:`pexpect.fdpexpect.fdspawn`. + """ + encoding = None + pid = None + flag_eof = False + + def __init__(self, timeout=30, maxread=2000, searchwindowsize=None, + logfile=None, encoding=None, codec_errors='strict'): + self.stdin = sys.stdin + self.stdout = sys.stdout + self.stderr = sys.stderr + + self.searcher = None + self.ignorecase = False + self.before = None + self.after = None + self.match = None + self.match_index = None + self.terminated = True + self.exitstatus = None + self.signalstatus = None + # status returned by os.waitpid + self.status = None + # the child file descriptor is initially closed + self.child_fd = -1 + self.timeout = timeout + self.delimiter = EOF + self.logfile = logfile + # input from child (read_nonblocking) + self.logfile_read = None + # output to send (send, sendline) + self.logfile_send = None + # max bytes to read at one time into buffer + self.maxread = maxread + # This is the read buffer. See maxread. + self.buffer = bytes() if (encoding is None) else text_type() + # Data before searchwindowsize point is preserved, but not searched. + self.searchwindowsize = searchwindowsize + # Delay used before sending data to child. Time in seconds. + # Set this to None to skip the time.sleep() call completely. + self.delaybeforesend = 0.05 + # Used by close() to give kernel time to update process status. + # Time in seconds. + self.delayafterclose = 0.1 + # Used by terminate() to give kernel time to update process status. + # Time in seconds. + self.delayafterterminate = 0.1 + # Delay in seconds to sleep after each call to read_nonblocking(). + # Set this to None to skip the time.sleep() call completely: that + # would restore the behavior from pexpect-2.0 (for performance + # reasons or because you don't want to release Python's global + # interpreter lock). + self.delayafterread = 0.0001 + self.softspace = False + self.name = '<' + repr(self) + '>' + self.closed = True + + # Unicode interface + self.encoding = encoding + self.codec_errors = codec_errors + if encoding is None: + # bytes mode (accepts some unicode for backwards compatibility) + self._encoder = self._decoder = _NullCoder() + self.string_type = bytes + self.crlf = b'\r\n' + if PY3: + self.allowed_string_types = (bytes, str) + self.linesep = os.linesep.encode('ascii') + def write_to_stdout(b): + try: + return sys.stdout.buffer.write(b) + except AttributeError: + # If stdout has been replaced, it may not have .buffer + return sys.stdout.write(b.decode('ascii', 'replace')) + self.write_to_stdout = write_to_stdout + else: + self.allowed_string_types = (basestring,) # analysis:ignore + self.linesep = os.linesep + self.write_to_stdout = sys.stdout.write + else: + # unicode mode + self._encoder = codecs.getincrementalencoder(encoding)(codec_errors) + self._decoder = codecs.getincrementaldecoder(encoding)(codec_errors) + self.string_type = text_type + self.crlf = u'\r\n' + self.allowed_string_types = (text_type, ) + if PY3: + self.linesep = os.linesep + else: + self.linesep = os.linesep.decode('ascii') + # This can handle unicode in both Python 2 and 3 + self.write_to_stdout = sys.stdout.write + + def _log(self, s, direction): + if self.logfile is not None: + self.logfile.write(s) + self.logfile.flush() + second_log = self.logfile_send if (direction=='send') else self.logfile_read + if second_log is not None: + second_log.write(s) + second_log.flush() + + # For backwards compatibility, in bytes mode (when encoding is None) + # unicode is accepted for send and expect. Unicode mode is strictly unicode + # only. + def _coerce_expect_string(self, s): + if self.encoding is None and not isinstance(s, bytes): + return s.encode('ascii') + return s + + def _coerce_send_string(self, s): + if self.encoding is None and not isinstance(s, bytes): + return s.encode('utf-8') + return s + + def read_nonblocking(self, size=1, timeout=None): + """This reads data from the file descriptor. + + This is a simple implementation suitable for a regular file. Subclasses using ptys or pipes should override it. + + The timeout parameter is ignored. + """ + + try: + s = os.read(self.child_fd, size) + except OSError as err: + if err.args[0] == errno.EIO: + # Linux-style EOF + self.flag_eof = True + raise EOF('End Of File (EOF). Exception style platform.') + raise + if s == b'': + # BSD-style EOF + self.flag_eof = True + raise EOF('End Of File (EOF). Empty string style platform.') + + s = self._decoder.decode(s, final=False) + self._log(s, 'read') + return s + + def _pattern_type_err(self, pattern): + raise TypeError('got {badtype} ({badobj!r}) as pattern, must be one' + ' of: {goodtypes}, pexpect.EOF, pexpect.TIMEOUT'\ + .format(badtype=type(pattern), + badobj=pattern, + goodtypes=', '.join([str(ast)\ + for ast in self.allowed_string_types]) + ) + ) + + def compile_pattern_list(self, patterns): + '''This compiles a pattern-string or a list of pattern-strings. + Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of + those. Patterns may also be None which results in an empty list (you + might do this if waiting for an EOF or TIMEOUT condition without + expecting any pattern). + + This is used by expect() when calling expect_list(). Thus expect() is + nothing more than:: + + cpl = self.compile_pattern_list(pl) + return self.expect_list(cpl, timeout) + + If you are using expect() within a loop it may be more + efficient to compile the patterns first and then call expect_list(). + This avoid calls in a loop to compile_pattern_list():: + + cpl = self.compile_pattern_list(my_pattern) + while some_condition: + ... + i = self.expect_list(cpl, timeout) + ... + ''' + + if patterns is None: + return [] + if not isinstance(patterns, list): + patterns = [patterns] + + # Allow dot to match \n + compile_flags = re.DOTALL + if self.ignorecase: + compile_flags = compile_flags | re.IGNORECASE + compiled_pattern_list = [] + for idx, p in enumerate(patterns): + if isinstance(p, self.allowed_string_types): + p = self._coerce_expect_string(p) + compiled_pattern_list.append(re.compile(p, compile_flags)) + elif p is EOF: + compiled_pattern_list.append(EOF) + elif p is TIMEOUT: + compiled_pattern_list.append(TIMEOUT) + elif isinstance(p, type(re.compile(''))): + compiled_pattern_list.append(p) + else: + self._pattern_type_err(p) + return compiled_pattern_list + + def expect(self, pattern, timeout=-1, searchwindowsize=-1, async=False): + '''This seeks through the stream until a pattern is matched. The + pattern is overloaded and may take several types. The pattern can be a + StringType, EOF, a compiled re, or a list of any of those types. + Strings will be compiled to re types. This returns the index into the + pattern list. If the pattern was not a list this returns index 0 on a + successful match. This may raise exceptions for EOF or TIMEOUT. To + avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern + list. That will cause expect to match an EOF or TIMEOUT condition + instead of raising an exception. + + If you pass a list of patterns and more than one matches, the first + match in the stream is chosen. If more than one pattern matches at that + point, the leftmost in the pattern list is chosen. For example:: + + # the input is 'foobar' + index = p.expect(['bar', 'foo', 'foobar']) + # returns 1('foo') even though 'foobar' is a "better" match + + Please note, however, that buffering can affect this behavior, since + input arrives in unpredictable chunks. For example:: + + # the input is 'foobar' + index = p.expect(['foobar', 'foo']) + # returns 0('foobar') if all input is available at once, + # but returs 1('foo') if parts of the final 'bar' arrive late + + When a match is found for the given pattern, the class instance + attribute *match* becomes an re.MatchObject result. Should an EOF + or TIMEOUT pattern match, then the match attribute will be an instance + of that exception class. The pairing before and after class + instance attributes are views of the data preceding and following + the matching pattern. On general exception, class attribute + *before* is all data received up to the exception, while *match* and + *after* attributes are value None. + + When the keyword argument timeout is -1 (default), then TIMEOUT will + raise after the default value specified by the class timeout + attribute. When None, TIMEOUT will not be raised and may block + indefinitely until match. + + When the keyword argument searchwindowsize is -1 (default), then the + value specified by the class maxread attribute is used. + + A list entry may be EOF or TIMEOUT instead of a string. This will + catch these exceptions and return the index of the list entry instead + of raising the exception. The attribute 'after' will be set to the + exception type. The attribute 'match' will be None. This allows you to + write code like this:: + + index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT]) + if index == 0: + do_something() + elif index == 1: + do_something_else() + elif index == 2: + do_some_other_thing() + elif index == 3: + do_something_completely_different() + + instead of code like this:: + + try: + index = p.expect(['good', 'bad']) + if index == 0: + do_something() + elif index == 1: + do_something_else() + except EOF: + do_some_other_thing() + except TIMEOUT: + do_something_completely_different() + + These two forms are equivalent. It all depends on what you want. You + can also just expect the EOF if you are waiting for all output of a + child to finish. For example:: + + p = pexpect.spawn('/bin/ls') + p.expect(pexpect.EOF) + print p.before + + If you are trying to optimize for speed then see expect_list(). + + On Python 3.4, or Python 3.3 with asyncio installed, passing + ``async=True`` will make this return an :mod:`asyncio` coroutine, + which you can yield from to get the same result that this method would + normally give directly. So, inside a coroutine, you can replace this code:: + + index = p.expect(patterns) + + With this non-blocking form:: + + index = yield from p.expect(patterns, async=True) + ''' + + compiled_pattern_list = self.compile_pattern_list(pattern) + return self.expect_list(compiled_pattern_list, + timeout, searchwindowsize, async) + + def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1, + async=False): + '''This takes a list of compiled regular expressions and returns the + index into the pattern_list that matched the child output. The list may + also contain EOF or TIMEOUT(which are not compiled regular + expressions). This method is similar to the expect() method except that + expect_list() does not recompile the pattern list on every call. This + may help if you are trying to optimize for speed, otherwise just use + the expect() method. This is called by expect(). + + + Like :meth:`expect`, passing ``async=True`` will make this return an + asyncio coroutine. + ''' + if timeout == -1: + timeout = self.timeout + + exp = Expecter(self, searcher_re(pattern_list), searchwindowsize) + if async: + from .async import expect_async + return expect_async(exp, timeout) + else: + return exp.expect_loop(timeout) + + def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1, + async=False): + + '''This is similar to expect(), but uses plain string matching instead + of compiled regular expressions in 'pattern_list'. The 'pattern_list' + may be a string; a list or other sequence of strings; or TIMEOUT and + EOF. + + This call might be faster than expect() for two reasons: string + searching is faster than RE matching and it is possible to limit the + search to just the end of the input buffer. + + This method is also useful when you don't want to have to worry about + escaping regular expression characters that you want to match. + + Like :meth:`expect`, passing ``async=True`` will make this return an + asyncio coroutine. + ''' + if timeout == -1: + timeout = self.timeout + + if (isinstance(pattern_list, self.allowed_string_types) or + pattern_list in (TIMEOUT, EOF)): + pattern_list = [pattern_list] + + def prepare_pattern(pattern): + if pattern in (TIMEOUT, EOF): + return pattern + if isinstance(pattern, self.allowed_string_types): + return self._coerce_expect_string(pattern) + self._pattern_type_err(pattern) + + try: + pattern_list = iter(pattern_list) + except TypeError: + self._pattern_type_err(pattern_list) + pattern_list = [prepare_pattern(p) for p in pattern_list] + + exp = Expecter(self, searcher_string(pattern_list), searchwindowsize) + if async: + from .async import expect_async + return expect_async(exp, timeout) + else: + return exp.expect_loop(timeout) + + def expect_loop(self, searcher, timeout=-1, searchwindowsize=-1): + '''This is the common loop used inside expect. The 'searcher' should be + an instance of searcher_re or searcher_string, which describes how and + what to search for in the input. + + See expect() for other arguments, return value and exceptions. ''' + + exp = Expecter(self, searcher, searchwindowsize) + return exp.expect_loop(timeout) + + def read(self, size=-1): + '''This reads at most "size" bytes from the file (less if the read hits + EOF before obtaining size bytes). If the size argument is negative or + omitted, read all data until EOF is reached. The bytes are returned as + a string object. An empty string is returned when EOF is encountered + immediately. ''' + + if size == 0: + return self.string_type() + if size < 0: + # delimiter default is EOF + self.expect(self.delimiter) + return self.before + + # I could have done this more directly by not using expect(), but + # I deliberately decided to couple read() to expect() so that + # I would catch any bugs early and ensure consistant behavior. + # It's a little less efficient, but there is less for me to + # worry about if I have to later modify read() or expect(). + # Note, it's OK if size==-1 in the regex. That just means it + # will never match anything in which case we stop only on EOF. + cre = re.compile(self._coerce_expect_string('.{%d}' % size), re.DOTALL) + # delimiter default is EOF + index = self.expect([cre, self.delimiter]) + if index == 0: + ### FIXME self.before should be ''. Should I assert this? + return self.after + return self.before + + def readline(self, size=-1): + '''This reads and returns one entire line. The newline at the end of + line is returned as part of the string, unless the file ends without a + newline. An empty string is returned if EOF is encountered immediately. + This looks for a newline as a CR/LF pair (\\r\\n) even on UNIX because + this is what the pseudotty device returns. So contrary to what you may + expect you will receive newlines as \\r\\n. + + If the size argument is 0 then an empty string is returned. In all + other cases the size argument is ignored, which is not standard + behavior for a file-like object. ''' + + if size == 0: + return self.string_type() + # delimiter default is EOF + index = self.expect([self.crlf, self.delimiter]) + if index == 0: + return self.before + self.crlf + else: + return self.before + + def __iter__(self): + '''This is to support iterators over a file-like object. + ''' + return iter(self.readline, self.string_type()) + + def readlines(self, sizehint=-1): + '''This reads until EOF using readline() and returns a list containing + the lines thus read. The optional 'sizehint' argument is ignored. + Remember, because this reads until EOF that means the child + process should have closed its stdout. If you run this method on + a child that is still running with its stdout open then this + method will block until it timesout.''' + + lines = [] + while True: + line = self.readline() + if not line: + break + lines.append(line) + return lines + + def fileno(self): + '''Expose file descriptor for a file-like interface + ''' + return self.child_fd + + def flush(self): + '''This does nothing. It is here to support the interface for a + File-like object. ''' + pass + + def isatty(self): + """Overridden in subclass using tty""" + return False + + # For 'with spawn(...) as child:' + def __enter__(self): + return self + + def __exit__(self, etype, evalue, tb): + # We rely on subclasses to implement close(). If they don't, it's not + # clear what a context manager should do. + self.close() diff --git a/pipenv/vendor/pexpect/utils.py b/pipenv/vendor/pexpect/utils.py new file mode 100644 index 00000000..ae0fe9dc --- /dev/null +++ b/pipenv/vendor/pexpect/utils.py @@ -0,0 +1,151 @@ +import os +import sys +import stat +import select +import time +import errno + +try: + InterruptedError +except NameError: + # Alias Python2 exception to Python3 + InterruptedError = select.error + + +def is_executable_file(path): + """Checks that path is an executable regular file, or a symlink towards one. + + This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``. + """ + # follow symlinks, + fpath = os.path.realpath(path) + + if not os.path.isfile(fpath): + # non-files (directories, fifo, etc.) + return False + + mode = os.stat(fpath).st_mode + + if (sys.platform.startswith('sunos') + and os.getuid() == 0): + # When root on Solaris, os.X_OK is True for *all* files, irregardless + # of their executability -- instead, any permission bit of any user, + # group, or other is fine enough. + # + # (This may be true for other "Unix98" OS's such as HP-UX and AIX) + return bool(mode & (stat.S_IXUSR | + stat.S_IXGRP | + stat.S_IXOTH)) + + return os.access(fpath, os.X_OK) + + +def which(filename, env=None): + '''This takes a given filename; tries to find it in the environment path; + then checks if it is executable. This returns the full path to the filename + if found and executable. Otherwise this returns None.''' + + # Special case where filename contains an explicit path. + if os.path.dirname(filename) != '' and is_executable_file(filename): + return filename + if env is None: + env = os.environ + p = env.get('PATH') + if not p: + p = os.defpath + pathlist = p.split(os.pathsep) + for path in pathlist: + ff = os.path.join(path, filename) + if is_executable_file(ff): + return ff + return None + + +def split_command_line(command_line): + + '''This splits a command line into a list of arguments. It splits arguments + on spaces, but handles embedded quotes, doublequotes, and escaped + characters. It's impossible to do this with a regular expression, so I + wrote a little state machine to parse the command line. ''' + + arg_list = [] + arg = '' + + # Constants to name the states we can be in. + state_basic = 0 + state_esc = 1 + state_singlequote = 2 + state_doublequote = 3 + # The state when consuming whitespace between commands. + state_whitespace = 4 + state = state_basic + + for c in command_line: + if state == state_basic or state == state_whitespace: + if c == '\\': + # Escape the next character + state = state_esc + elif c == r"'": + # Handle single quote + state = state_singlequote + elif c == r'"': + # Handle double quote + state = state_doublequote + elif c.isspace(): + # Add arg to arg_list if we aren't in the middle of whitespace. + if state == state_whitespace: + # Do nothing. + None + else: + arg_list.append(arg) + arg = '' + state = state_whitespace + else: + arg = arg + c + state = state_basic + elif state == state_esc: + arg = arg + c + state = state_basic + elif state == state_singlequote: + if c == r"'": + state = state_basic + else: + arg = arg + c + elif state == state_doublequote: + if c == r'"': + state = state_basic + else: + arg = arg + c + + if arg != '': + arg_list.append(arg) + return arg_list + + +def select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None): + + '''This is a wrapper around select.select() that ignores signals. If + select.select raises a select.error exception and errno is an EINTR + error then it is ignored. Mainly this is used to ignore sigwinch + (terminal resize). ''' + + # if select() is interrupted by a signal (errno==EINTR) then + # we loop back and enter the select() again. + if timeout is not None: + end_time = time.time() + timeout + while True: + try: + return select.select(iwtd, owtd, ewtd, timeout) + except InterruptedError: + err = sys.exc_info()[1] + if err.args[0] == errno.EINTR: + # if we loop back we have to subtract the + # amount of time we already waited. + if timeout is not None: + timeout = end_time - time.time() + if timeout < 0: + return([], [], []) + else: + # something else caused the select.error, so + # this actually is an exception. + raise diff --git a/pipenv/vendor/pipfile/__about__.py b/pipenv/vendor/pipfile/__about__.py new file mode 100644 index 00000000..3ba72191 --- /dev/null +++ b/pipenv/vendor/pipfile/__about__.py @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "pipfile" +__summary__ = "" +__uri__ = "https://github.com/pypa/pipfile" + +__version__ = "0.0.2" + +__author__ = "Kenneth Reitz and individual contributors" +__email__ = "me@kennethreitz.org" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2017 %s" % __author__ diff --git a/pipenv/vendor/pipfile/__init__.py b/pipenv/vendor/pipfile/__init__.py new file mode 100644 index 00000000..fddd4f90 --- /dev/null +++ b/pipenv/vendor/pipfile/__init__.py @@ -0,0 +1,11 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + +from .api import load, Pipfile diff --git a/pipenv/vendor/pipfile/api.py b/pipenv/vendor/pipfile/api.py new file mode 100644 index 00000000..8a2a6a30 --- /dev/null +++ b/pipenv/vendor/pipfile/api.py @@ -0,0 +1,195 @@ +import toml + +import codecs +import json +import hashlib +import platform +import sys +import os + + +def format_full_version(info): + version = '{0.major}.{0.minor}.{0.micro}'.format(info) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + +def walk_up(bottom): + """mimic os.walk, but walk 'up' instead of down the directory tree. + From: https://gist.github.com/zdavkeos/1098474 + """ + + bottom = os.path.realpath(bottom) + + # get files in current dir + try: + names = os.listdir(bottom) + except Exception as e: + return + + dirs, nondirs = [], [] + for name in names: + if os.path.isdir(os.path.join(bottom, name)): + dirs.append(name) + else: + nondirs.append(name) + + yield bottom, dirs, nondirs + + new_path = os.path.realpath(os.path.join(bottom, '..')) + + # see if we are at the top + if new_path == bottom: + return + + for x in walk_up(new_path): + yield x + + +class PipfileParser(object): + def __init__(self, filename='Pipfile'): + self.filename = filename + self.sources = [] + self.groups = { + 'default': [], + 'develop': [] + } + self.group_stack = ['default'] + self.requirements = [] + + def __repr__(self): + return '= 2.6.36 + if _psplatform.HAS_PRLIMIT: + from ._psutil_linux import RLIM_INFINITY # NOQA + from ._psutil_linux import RLIMIT_AS # NOQA + from ._psutil_linux import RLIMIT_CORE # NOQA + from ._psutil_linux import RLIMIT_CPU # NOQA + from ._psutil_linux import RLIMIT_DATA # NOQA + from ._psutil_linux import RLIMIT_FSIZE # NOQA + from ._psutil_linux import RLIMIT_LOCKS # NOQA + from ._psutil_linux import RLIMIT_MEMLOCK # NOQA + from ._psutil_linux import RLIMIT_NOFILE # NOQA + from ._psutil_linux import RLIMIT_NPROC # NOQA + from ._psutil_linux import RLIMIT_RSS # NOQA + from ._psutil_linux import RLIMIT_STACK # NOQA + # Kinda ugly but considerably faster than using hasattr() and + # setattr() against the module object (we are at import time: + # speed matters). + from . import _psutil_linux + try: + RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE + except AttributeError: + pass + try: + RLIMIT_NICE = _psutil_linux.RLIMIT_NICE + except AttributeError: + pass + try: + RLIMIT_RTPRIO = _psutil_linux.RLIMIT_RTPRIO + except AttributeError: + pass + try: + RLIMIT_RTTIME = _psutil_linux.RLIMIT_RTTIME + except AttributeError: + pass + try: + RLIMIT_SIGPENDING = _psutil_linux.RLIMIT_SIGPENDING + except AttributeError: + pass + +elif WINDOWS: + from . import _pswindows as _psplatform + from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # NOQA + from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # NOQA + from ._psutil_windows import HIGH_PRIORITY_CLASS # NOQA + from ._psutil_windows import IDLE_PRIORITY_CLASS # NOQA + from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA + from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA + from ._pswindows import CONN_DELETE_TCB # NOQA + +elif OSX: + from . import _psosx as _psplatform + +elif BSD: + from . import _psbsd as _psplatform + +elif SUNOS: + from . import _pssunos as _psplatform + from ._pssunos import CONN_BOUND # NOQA + from ._pssunos import CONN_IDLE # NOQA + + # This is public writable API which is read from _pslinux.py and + # _pssunos.py via sys.modules. + PROCFS_PATH = "/proc" + +else: # pragma: no cover + raise NotImplementedError('platform %s is not supported' % sys.platform) + + +__all__ = [ + # exceptions + "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied", + "TimeoutExpired", + + # constants + "version_info", "__version__", + + "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", + "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", + "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", + + "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", + "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", + "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", + + "AF_LINK", + + "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN", + + "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED", + + "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "OSX", "POSIX", "SUNOS", + "WINDOWS", + + # classes + "Process", "Popen", + + # functions + "pid_exists", "pids", "process_iter", "wait_procs", # proc + "virtual_memory", "swap_memory", # memory + "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu + "cpu_stats", # "cpu_freq", + "net_io_counters", "net_connections", "net_if_addrs", # network + "net_if_stats", + "disk_io_counters", "disk_partitions", "disk_usage", # disk + # "sensors_temperatures", "sensors_battery", "sensors_fans" # sensors + "users", "boot_time", # others +] +__all__.extend(_psplatform.__extra__all__) +__author__ = "Giampaolo Rodola'" +__version__ = "5.2.0" +version_info = tuple([int(num) for num in __version__.split('.')]) +AF_LINK = _psplatform.AF_LINK +POWER_TIME_UNLIMITED = _common.POWER_TIME_UNLIMITED +POWER_TIME_UNKNOWN = _common.POWER_TIME_UNKNOWN +_TOTAL_PHYMEM = None +_timer = getattr(time, 'monotonic', time.time) + + +# Sanity check in case the user messed up with psutil installation +# or did something weird with sys.path. In this case we might end +# up importing a python module using a C extension module which +# was compiled for a different version of psutil. +# We want to prevent that by failing sooner rather than later. +# See: https://github.com/giampaolo/psutil/issues/564 +if (int(__version__.replace('.', '')) != + getattr(_psplatform.cext, 'version', None)): + msg = "version conflict: %r C extension module was built for another " \ + "version of psutil" % getattr(_psplatform.cext, "__file__") + if hasattr(_psplatform.cext, 'version'): + msg += " (%s instead of %s)" % ( + '.'.join([x for x in str(_psplatform.cext.version)]), __version__) + else: + msg += " (different than %s)" % __version__ + msg += "; you may try to 'pip uninstall psutil', manually remove %s" % ( + getattr(_psplatform.cext, "__file__", + "the existing psutil install directory")) + msg += " or clean the virtual env somehow, then reinstall" + raise ImportError(msg) + + +# ===================================================================== +# --- exceptions +# ===================================================================== + + +class Error(Exception): + """Base exception class. All other psutil exceptions inherit + from this one. + """ + + def __init__(self, msg=""): + Exception.__init__(self, msg) + self.msg = msg + + def __repr__(self): + ret = "%s.%s %s" % (self.__class__.__module__, + self.__class__.__name__, self.msg) + return ret.strip() + + __str__ = __repr__ + + +class NoSuchProcess(Error): + """Exception raised when a process with a certain PID doesn't + or no longer exists. + """ + + def __init__(self, pid, name=None, msg=None): + Error.__init__(self, msg) + self.pid = pid + self.name = name + self.msg = msg + if msg is None: + if name: + details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) + else: + details = "(pid=%s)" % self.pid + self.msg = "process no longer exists " + details + + +class ZombieProcess(NoSuchProcess): + """Exception raised when querying a zombie process. This is + raised on OSX, BSD and Solaris only, and not always: depending + on the query the OS may be able to succeed anyway. + On Linux all zombie processes are querable (hence this is never + raised). Windows doesn't have zombie processes. + """ + + def __init__(self, pid, name=None, ppid=None, msg=None): + Error.__init__(self, msg) + self.pid = pid + self.ppid = ppid + self.name = name + self.msg = msg + if msg is None: + args = ["pid=%s" % pid] + if name: + args.append("name=%s" % repr(self.name)) + if ppid: + args.append("ppid=%s" % self.ppid) + details = "(%s)" % ", ".join(args) + self.msg = "process still exists but it's a zombie " + details + + +class AccessDenied(Error): + """Exception raised when permission to perform an action is denied.""" + + def __init__(self, pid=None, name=None, msg=None): + Error.__init__(self, msg) + self.pid = pid + self.name = name + self.msg = msg + if msg is None: + if (pid is not None) and (name is not None): + self.msg = "(pid=%s, name=%s)" % (pid, repr(name)) + elif (pid is not None): + self.msg = "(pid=%s)" % self.pid + else: + self.msg = "" + + +class TimeoutExpired(Error): + """Raised on Process.wait(timeout) if timeout expires and process + is still alive. + """ + + def __init__(self, seconds, pid=None, name=None): + Error.__init__(self, "timeout after %s seconds" % seconds) + self.seconds = seconds + self.pid = pid + self.name = name + if (pid is not None) and (name is not None): + self.msg += " (pid=%s, name=%s)" % (pid, repr(name)) + elif (pid is not None): + self.msg += " (pid=%s)" % self.pid + + +# push exception classes into platform specific module namespace +_psplatform.NoSuchProcess = NoSuchProcess +_psplatform.ZombieProcess = ZombieProcess +_psplatform.AccessDenied = AccessDenied +_psplatform.TimeoutExpired = TimeoutExpired + + +# ===================================================================== +# --- Process class +# ===================================================================== + + +def _assert_pid_not_reused(fun): + """Decorator which raises NoSuchProcess in case a process is no + longer running or its PID has been reused. + """ + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + if not self.is_running(): + raise NoSuchProcess(self.pid, self._name) + return fun(self, *args, **kwargs) + return wrapper + + +class Process(object): + """Represents an OS process with the given PID. + If PID is omitted current process PID (os.getpid()) is used. + Raise NoSuchProcess if PID does not exist. + + Note that most of the methods of this class do not make sure + the PID of the process being queried has been reused over time. + That means you might end up retrieving an information referring + to another process in case the original one this instance + refers to is gone in the meantime. + + The only exceptions for which process identity is pre-emptively + checked and guaranteed are: + + - parent() + - children() + - nice() (set) + - ionice() (set) + - rlimit() (set) + - cpu_affinity (set) + - suspend() + - resume() + - send_signal() + - terminate() + - kill() + + To prevent this problem for all other methods you can: + - use is_running() before querying the process + - if you're continuously iterating over a set of Process + instances use process_iter() which pre-emptively checks + process identity for every yielded instance + """ + + def __init__(self, pid=None): + self._init(pid) + + def _init(self, pid, _ignore_nsp=False): + if pid is None: + pid = os.getpid() + else: + if not _PY3 and not isinstance(pid, (int, long)): + raise TypeError('pid must be an integer (got %r)' % pid) + if pid < 0: + raise ValueError('pid must be a positive integer (got %s)' + % pid) + self._pid = pid + self._name = None + self._exe = None + self._create_time = None + self._gone = False + self._hash = None + self._oneshot_inctx = False + # used for caching on Windows only (on POSIX ppid may change) + self._ppid = None + # platform-specific modules define an _psplatform.Process + # implementation class + self._proc = _psplatform.Process(pid) + self._last_sys_cpu_times = None + self._last_proc_cpu_times = None + # cache creation time for later use in is_running() method + try: + self.create_time() + except AccessDenied: + # We should never get here as AFAIK we're able to get + # process creation time on all platforms even as a + # limited user. + pass + except ZombieProcess: + # Zombies can still be queried by this class (although + # not always) and pids() return them so just go on. + pass + except NoSuchProcess: + if not _ignore_nsp: + msg = 'no process found with pid %s' % pid + raise NoSuchProcess(pid, None, msg) + else: + self._gone = True + # This pair is supposed to indentify a Process instance + # univocally over time (the PID alone is not enough as + # it might refer to a process whose PID has been reused). + # This will be used later in __eq__() and is_running(). + self._ident = (self.pid, self._create_time) + + def __str__(self): + try: + pid = self.pid + name = repr(self.name()) + except ZombieProcess: + details = "(pid=%s (zombie))" % self.pid + except NoSuchProcess: + details = "(pid=%s (terminated))" % self.pid + except AccessDenied: + details = "(pid=%s)" % (self.pid) + else: + details = "(pid=%s, name=%s)" % (pid, name) + return "%s.%s%s" % (self.__class__.__module__, + self.__class__.__name__, details) + + def __repr__(self): + return "<%s at %s>" % (self.__str__(), id(self)) + + def __eq__(self, other): + # Test for equality with another Process object based + # on PID and creation time. + if not isinstance(other, Process): + return NotImplemented + return self._ident == other._ident + + def __ne__(self, other): + return not self == other + + def __hash__(self): + if self._hash is None: + self._hash = hash(self._ident) + return self._hash + + @property + def pid(self): + """The process PID.""" + return self._pid + + # --- utility methods + + @contextlib.contextmanager + def oneshot(self): + """Utility context manager which considerably speeds up the + retrieval of multiple process information at the same time. + + Internally different process info (e.g. name, ppid, uids, + gids, ...) may be fetched by using the same routine, but + only one information is returned and the others are discarded. + When using this context manager the internal routine is + executed once (in the example below on name()) and the + other info are cached. + + The cache is cleared when exiting the context manager block. + The advice is to use this every time you retrieve more than + one information about the process. If you're lucky, you'll + get a hell of a speedup. + + >>> import psutil + >>> p = psutil.Process() + >>> with p.oneshot(): + ... p.name() # collect multiple info + ... p.cpu_times() # return cached value + ... p.cpu_percent() # return cached value + ... p.create_time() # return cached value + ... + >>> + """ + if self._oneshot_inctx: + # NOOP: this covers the use case where the user enters the + # context twice. Since as_dict() internally uses oneshot() + # I expect that the code below will be a pretty common + # "mistake" that the user will make, so let's guard + # against that: + # + # >>> with p.oneshot(): + # ... p.as_dict() + # ... + yield + else: + self._oneshot_inctx = True + try: + # cached in case cpu_percent() is used + self.cpu_times.cache_activate() + # cached in case memory_percent() is used + self.memory_info.cache_activate() + # cached in case parent() is used + self.ppid.cache_activate() + # cached in case username() is used + if POSIX: + self.uids.cache_activate() + # specific implementation cache + self._proc.oneshot_enter() + yield + finally: + self.cpu_times.cache_deactivate() + self.memory_info.cache_deactivate() + self.ppid.cache_deactivate() + if POSIX: + self.uids.cache_deactivate() + self._proc.oneshot_exit() + self._oneshot_inctx = False + + def as_dict(self, attrs=None, ad_value=None): + """Utility method returning process information as a + hashable dictionary. + If 'attrs' is specified it must be a list of strings + reflecting available Process class' attribute names + (e.g. ['cpu_times', 'name']) else all public (read + only) attributes are assumed. + 'ad_value' is the value which gets assigned in case + AccessDenied or ZombieProcess exception is raised when + retrieving that particular process information. + """ + valid_names = _as_dict_attrnames + if attrs is not None: + if not isinstance(attrs, (list, tuple, set, frozenset)): + raise TypeError("invalid attrs type %s" % type(attrs)) + attrs = set(attrs) + invalid_names = attrs - valid_names + if invalid_names: + raise ValueError("invalid attr name%s %s" % ( + "s" if len(invalid_names) > 1 else "", + ", ".join(map(repr, invalid_names)))) + + retdict = dict() + ls = attrs or valid_names + with self.oneshot(): + for name in ls: + try: + if name == 'pid': + ret = self.pid + else: + meth = getattr(self, name) + ret = meth() + except (AccessDenied, ZombieProcess): + ret = ad_value + except NotImplementedError: + # in case of not implemented functionality (may happen + # on old or exotic systems) we want to crash only if + # the user explicitly asked for that particular attr + if attrs: + raise + continue + retdict[name] = ret + return retdict + + def parent(self): + """Return the parent process as a Process object pre-emptively + checking whether PID has been reused. + If no parent is known return None. + """ + ppid = self.ppid() + if ppid is not None: + ctime = self.create_time() + try: + parent = Process(ppid) + if parent.create_time() <= ctime: + return parent + # ...else ppid has been reused by another process + except NoSuchProcess: + pass + + def is_running(self): + """Return whether this process is running. + It also checks if PID has been reused by another process in + which case return False. + """ + if self._gone: + return False + try: + # Checking if PID is alive is not enough as the PID might + # have been reused by another process: we also want to + # verify process identity. + # Process identity / uniqueness over time is guaranteed by + # (PID + creation time) and that is verified in __eq__. + return self == Process(self.pid) + except ZombieProcess: + # We should never get here as it's already handled in + # Process.__init__; here just for extra safety. + return True + except NoSuchProcess: + self._gone = True + return False + + # --- actual API + + @memoize_when_activated + def ppid(self): + """The process parent PID. + On Windows the return value is cached after first call. + """ + # On POSIX we don't want to cache the ppid as it may unexpectedly + # change to 1 (init) in case this process turns into a zombie: + # https://github.com/giampaolo/psutil/issues/321 + # http://stackoverflow.com/questions/356722/ + + # XXX should we check creation time here rather than in + # Process.parent()? + if POSIX: + return self._proc.ppid() + else: + self._ppid = self._ppid or self._proc.ppid() + return self._ppid + + def name(self): + """The process name. The return value is cached after first call.""" + # Process name is only cached on Windows as on POSIX it may + # change, see: + # https://github.com/giampaolo/psutil/issues/692 + if WINDOWS and self._name is not None: + return self._name + name = self._proc.name() + if POSIX and len(name) >= 15: + # On UNIX the name gets truncated to the first 15 characters. + # If it matches the first part of the cmdline we return that + # one instead because it's usually more explicative. + # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon". + try: + cmdline = self.cmdline() + except AccessDenied: + pass + else: + if cmdline: + extended_name = os.path.basename(cmdline[0]) + if extended_name.startswith(name): + name = extended_name + self._name = name + self._proc._name = name + return name + + def exe(self): + """The process executable as an absolute path. + May also be an empty string. + The return value is cached after first call. + """ + def guess_it(fallback): + # try to guess exe from cmdline[0] in absence of a native + # exe representation + cmdline = self.cmdline() + if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'): + exe = cmdline[0] # the possible exe + # Attempt to guess only in case of an absolute path. + # It is not safe otherwise as the process might have + # changed cwd. + if (os.path.isabs(exe) and + os.path.isfile(exe) and + os.access(exe, os.X_OK)): + return exe + if isinstance(fallback, AccessDenied): + raise fallback + return fallback + + if self._exe is None: + try: + exe = self._proc.exe() + except AccessDenied as err: + return guess_it(fallback=err) + else: + if not exe: + # underlying implementation can legitimately return an + # empty string; if that's the case we don't want to + # raise AD while guessing from the cmdline + try: + exe = guess_it(fallback=exe) + except AccessDenied: + pass + self._exe = exe + return self._exe + + def cmdline(self): + """The command line this process has been called with.""" + return self._proc.cmdline() + + def status(self): + """The process current status as a STATUS_* constant.""" + try: + return self._proc.status() + except ZombieProcess: + return STATUS_ZOMBIE + + def username(self): + """The name of the user that owns the process. + On UNIX this is calculated by using *real* process uid. + """ + if POSIX: + if pwd is None: + # might happen if python was installed from sources + raise ImportError( + "requires pwd module shipped with standard python") + real_uid = self.uids().real + try: + return pwd.getpwuid(real_uid).pw_name + except KeyError: + # the uid can't be resolved by the system + return str(real_uid) + else: + return self._proc.username() + + def create_time(self): + """The process creation time as a floating point number + expressed in seconds since the epoch, in UTC. + The return value is cached after first call. + """ + if self._create_time is None: + self._create_time = self._proc.create_time() + return self._create_time + + def cwd(self): + """Process current working directory as an absolute path.""" + return self._proc.cwd() + + def nice(self, value=None): + """Get or set process niceness (priority).""" + if value is None: + return self._proc.nice_get() + else: + if not self.is_running(): + raise NoSuchProcess(self.pid, self._name) + self._proc.nice_set(value) + + if POSIX: + + @memoize_when_activated + def uids(self): + """Return process UIDs as a (real, effective, saved) + namedtuple. + """ + return self._proc.uids() + + def gids(self): + """Return process GIDs as a (real, effective, saved) + namedtuple. + """ + return self._proc.gids() + + def terminal(self): + """The terminal associated with this process, if any, + else None. + """ + return self._proc.terminal() + + def num_fds(self): + """Return the number of file descriptors opened by this + process (POSIX only). + """ + return self._proc.num_fds() + + # Linux, BSD and Windows only + if hasattr(_psplatform.Process, "io_counters"): + + def io_counters(self): + """Return process I/O statistics as a + (read_count, write_count, read_bytes, write_bytes) + namedtuple. + Those are the number of read/write calls performed and the + amount of bytes read and written by the process. + """ + return self._proc.io_counters() + + # Linux and Windows >= Vista only + if hasattr(_psplatform.Process, "ionice_get"): + + def ionice(self, ioclass=None, value=None): + """Get or set process I/O niceness (priority). + + On Linux 'ioclass' is one of the IOPRIO_CLASS_* constants. + 'value' is a number which goes from 0 to 7. The higher the + value, the lower the I/O priority of the process. + + On Windows only 'ioclass' is used and it can be set to 2 + (normal), 1 (low) or 0 (very low). + + Available on Linux and Windows > Vista only. + """ + if ioclass is None: + if value is not None: + raise ValueError("'ioclass' argument must be specified") + return self._proc.ionice_get() + else: + return self._proc.ionice_set(ioclass, value) + + # Linux only + if hasattr(_psplatform.Process, "rlimit"): + + def rlimit(self, resource, limits=None): + """Get or set process resource limits as a (soft, hard) + tuple. + + 'resource' is one of the RLIMIT_* constants. + 'limits' is supposed to be a (soft, hard) tuple. + + See "man prlimit" for further info. + Available on Linux only. + """ + if limits is None: + return self._proc.rlimit(resource) + else: + return self._proc.rlimit(resource, limits) + + # Windows, Linux and FreeBSD only + if hasattr(_psplatform.Process, "cpu_affinity_get"): + + def cpu_affinity(self, cpus=None): + """Get or set process CPU affinity. + If specified 'cpus' must be a list of CPUs for which you + want to set the affinity (e.g. [0, 1]). + If an empty list is passed, all egible CPUs are assumed + (and set). + (Windows, Linux and BSD only). + """ + # Automatically remove duplicates both on get and + # set (for get it's not really necessary, it's + # just for extra safety). + if cpus is None: + return list(set(self._proc.cpu_affinity_get())) + else: + if not cpus: + if hasattr(self._proc, "_get_eligible_cpus"): + cpus = self._proc._get_eligible_cpus() + else: + cpus = tuple(range(len(cpu_times(percpu=True)))) + self._proc.cpu_affinity_set(list(set(cpus))) + + # Linux, FreeBSD, SunOS + if hasattr(_psplatform.Process, "cpu_num"): + + def cpu_num(self): + """Return what CPU this process is currently running on. + The returned number should be <= psutil.cpu_count() + and <= len(psutil.cpu_percent(percpu=True)). + It may be used in conjunction with + psutil.cpu_percent(percpu=True) to observe the system + workload distributed across CPUs. + """ + return self._proc.cpu_num() + + # Linux, OSX and Windows only + if hasattr(_psplatform.Process, "environ"): + + def environ(self): + """The environment variables of the process as a dict. Note: this + might not reflect changes made after the process started. """ + return self._proc.environ() + + if WINDOWS: + + def num_handles(self): + """Return the number of handles opened by this process + (Windows only). + """ + return self._proc.num_handles() + + def num_ctx_switches(self): + """Return the number of voluntary and involuntary context + switches performed by this process. + """ + return self._proc.num_ctx_switches() + + def num_threads(self): + """Return the number of threads used by this process.""" + return self._proc.num_threads() + + def threads(self): + """Return threads opened by process as a list of + (id, user_time, system_time) namedtuples representing + thread id and thread CPU times (user/system). + On OpenBSD this method requires root access. + """ + return self._proc.threads() + + @_assert_pid_not_reused + def children(self, recursive=False): + """Return the children of this process as a list of Process + instances, pre-emptively checking whether PID has been reused. + If recursive is True return all the parent descendants. + + Example (A == this process): + + A ─┠+ │ + ├─ B (child) ─┠+ │ └─ X (grandchild) ─┠+ │ └─ Y (great grandchild) + ├─ C (child) + └─ D (child) + + >>> import psutil + >>> p = psutil.Process() + >>> p.children() + B, C, D + >>> p.children(recursive=True) + B, X, Y, C, D + + Note that in the example above if process X disappears + process Y won't be listed as the reference to process A + is lost. + """ + if hasattr(_psplatform, 'ppid_map'): + # Windows only: obtain a {pid:ppid, ...} dict for all running + # processes in one shot (faster). + ppid_map = _psplatform.ppid_map() + else: + ppid_map = None + + ret = [] + if not recursive: + if ppid_map is None: + # 'slow' version, common to all platforms except Windows + for p in process_iter(): + try: + if p.ppid() == self.pid: + # if child happens to be older than its parent + # (self) it means child's PID has been reused + if self.create_time() <= p.create_time(): + ret.append(p) + except (NoSuchProcess, ZombieProcess): + pass + else: # pragma: no cover + # Windows only (faster) + for pid, ppid in ppid_map.items(): + if ppid == self.pid: + try: + child = Process(pid) + # if child happens to be older than its parent + # (self) it means child's PID has been reused + if self.create_time() <= child.create_time(): + ret.append(child) + except (NoSuchProcess, ZombieProcess): + pass + else: + # construct a dict where 'values' are all the processes + # having 'key' as their parent + table = collections.defaultdict(list) + if ppid_map is None: + for p in process_iter(): + try: + table[p.ppid()].append(p) + except (NoSuchProcess, ZombieProcess): + pass + else: # pragma: no cover + for pid, ppid in ppid_map.items(): + try: + p = Process(pid) + table[ppid].append(p) + except (NoSuchProcess, ZombieProcess): + pass + # At this point we have a mapping table where table[self.pid] + # are the current process' children. + # Below, we look for all descendants recursively, similarly + # to a recursive function call. + checkpids = [self.pid] + for pid in checkpids: + for child in table[pid]: + try: + # if child happens to be older than its parent + # (self) it means child's PID has been reused + intime = self.create_time() <= child.create_time() + except (NoSuchProcess, ZombieProcess): + pass + else: + if intime: + ret.append(child) + if child.pid not in checkpids: + checkpids.append(child.pid) + return ret + + def cpu_percent(self, interval=None): + """Return a float representing the current process CPU + utilization as a percentage. + + When interval is 0.0 or None (default) compares process times + to system CPU times elapsed since last call, returning + immediately (non-blocking). That means that the first time + this is called it will return a meaningful 0.0 value. + + When interval is > 0.0 compares process times to system CPU + times elapsed before and after the interval (blocking). + + In this case is recommended for accuracy that this function + be called with at least 0.1 seconds between calls. + + A value > 100.0 can be returned in case of processes running + multiple threads on different CPU cores. + + The returned value is explicitly *not* split evenly between + all available logical CPUs. This means that a busy loop process + running on a system with 2 logical CPUs will be reported as + having 100% CPU utilization instead of 50%. + + Examples: + + >>> import psutil + >>> p = psutil.Process(os.getpid()) + >>> # blocking + >>> p.cpu_percent(interval=1) + 2.0 + >>> # non-blocking (percentage since last call) + >>> p.cpu_percent(interval=None) + 2.9 + >>> + """ + blocking = interval is not None and interval > 0.0 + if interval is not None and interval < 0: + raise ValueError("interval is not positive (got %r)" % interval) + num_cpus = cpu_count() or 1 + + def timer(): + return _timer() * num_cpus + + if blocking: + st1 = timer() + pt1 = self._proc.cpu_times() + time.sleep(interval) + st2 = timer() + pt2 = self._proc.cpu_times() + else: + st1 = self._last_sys_cpu_times + pt1 = self._last_proc_cpu_times + st2 = timer() + pt2 = self._proc.cpu_times() + if st1 is None or pt1 is None: + self._last_sys_cpu_times = st2 + self._last_proc_cpu_times = pt2 + return 0.0 + + delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system) + delta_time = st2 - st1 + # reset values for next call in case of interval == None + self._last_sys_cpu_times = st2 + self._last_proc_cpu_times = pt2 + + try: + # This is the utilization split evenly between all CPUs. + # E.g. a busy loop process on a 2-CPU-cores system at this + # point is reported as 50% instead of 100%. + overall_cpus_percent = ((delta_proc / delta_time) * 100) + except ZeroDivisionError: + # interval was too low + return 0.0 + else: + # Note 1. + # in order to emulate "top" we multiply the value for the num + # of CPU cores. This way the busy process will be reported as + # having 100% (or more) usage. + # + # Note 2: + # taskmgr.exe on Windows differs in that it will show 50% + # instead. + # + # Note #3: + # a percentage > 100 is legitimate as it can result from a + # process with multiple threads running on different CPU + # cores (top does the same), see: + # http://stackoverflow.com/questions/1032357 + # https://github.com/giampaolo/psutil/issues/474 + single_cpu_percent = overall_cpus_percent * num_cpus + return round(single_cpu_percent, 1) + + @memoize_when_activated + def cpu_times(self): + """Return a (user, system, children_user, children_system) + namedtuple representing the accumulated process time, in + seconds. + This is similar to os.times() but per-process. + On OSX and Windows children_user and children_system are + always set to 0. + """ + return self._proc.cpu_times() + + @memoize_when_activated + def memory_info(self): + """Return a namedtuple with variable fields depending on the + platform, representing memory information about the process. + + The "portable" fields available on all plaforms are `rss` and `vms`. + + All numbers are expressed in bytes. + """ + return self._proc.memory_info() + + @deprecated_method(replacement="memory_info") + def memory_info_ex(self): + return self.memory_info() + + def memory_full_info(self): + """This method returns the same information as memory_info(), + plus, on some platform (Linux, OSX, Windows), also provides + additional metrics (USS, PSS and swap). + The additional metrics provide a better representation of actual + process memory usage. + + Namely USS is the memory which is unique to a process and which + would be freed if the process was terminated right now. + + It does so by passing through the whole process address. + As such it usually requires higher user privileges than + memory_info() and is considerably slower. + """ + return self._proc.memory_full_info() + + def memory_percent(self, memtype="rss"): + """Compare process memory to total physical system memory and + calculate process memory utilization as a percentage. + 'memtype' argument is a string that dictates what type of + process memory you want to compare against (defaults to "rss"). + The list of available strings can be obtained like this: + + >>> psutil.Process().memory_info()._fields + ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss') + """ + valid_types = list(_psplatform.pfullmem._fields) + if hasattr(_psplatform, "pfullmem"): + valid_types.extend(list(_psplatform.pfullmem._fields)) + if memtype not in valid_types: + raise ValueError("invalid memtype %r; valid types are %r" % ( + memtype, tuple(valid_types))) + fun = self.memory_full_info if memtype in ('uss', 'pss', 'swap') else \ + self.memory_info + metrics = fun() + value = getattr(metrics, memtype) + + # use cached value if available + total_phymem = _TOTAL_PHYMEM or virtual_memory().total + if not total_phymem > 0: + # we should never get here + raise ValueError( + "can't calculate process memory percent because " + "total physical system memory is not positive (%r)" + % total_phymem) + return (value / float(total_phymem)) * 100 + + if hasattr(_psplatform.Process, "memory_maps"): + # Available everywhere except OpenBSD and NetBSD. + + def memory_maps(self, grouped=True): + """Return process' mapped memory regions as a list of namedtuples + whose fields are variable depending on the platform. + + If 'grouped' is True the mapped regions with the same 'path' + are grouped together and the different memory fields are summed. + + If 'grouped' is False every mapped region is shown as a single + entity and the namedtuple will also include the mapped region's + address space ('addr') and permission set ('perms'). + """ + it = self._proc.memory_maps() + if grouped: + d = {} + for tupl in it: + path = tupl[2] + nums = tupl[3:] + try: + d[path] = map(lambda x, y: x + y, d[path], nums) + except KeyError: + d[path] = nums + nt = _psplatform.pmmap_grouped + return [nt(path, *d[path]) for path in d] # NOQA + else: + nt = _psplatform.pmmap_ext + return [nt(*x) for x in it] + + def open_files(self): + """Return files opened by process as a list of + (path, fd) namedtuples including the absolute file name + and file descriptor number. + """ + return self._proc.open_files() + + def connections(self, kind='inet'): + """Return connections opened by process as a list of + (fd, family, type, laddr, raddr, status) namedtuples. + The 'kind' parameter filters for connections that match the + following criteria: + + Kind Value Connections using + inet IPv4 and IPv6 + inet4 IPv4 + inet6 IPv6 + tcp TCP + tcp4 TCP over IPv4 + tcp6 TCP over IPv6 + udp UDP + udp4 UDP over IPv4 + udp6 UDP over IPv6 + unix UNIX socket (both UDP and TCP protocols) + all the sum of all the possible families and protocols + """ + return self._proc.connections(kind) + + # --- signals + + if POSIX: + def _send_signal(self, sig): + assert not self.pid < 0, self.pid + if self.pid == 0: + # see "man 2 kill" + raise ValueError( + "preventing sending signal to process with PID 0 as it " + "would affect every process in the process group of the " + "calling process (os.getpid()) instead of PID 0") + try: + os.kill(self.pid, sig) + except OSError as err: + if err.errno == errno.ESRCH: + if OPENBSD and pid_exists(self.pid): + # We do this because os.kill() lies in case of + # zombie processes. + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + self._gone = True + raise NoSuchProcess(self.pid, self._name) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + + @_assert_pid_not_reused + def send_signal(self, sig): + """Send a signal to process pre-emptively checking whether + PID has been reused (see signal module constants) . + On Windows only SIGTERM is valid and is treated as an alias + for kill(). + """ + if POSIX: + self._send_signal(sig) + else: # pragma: no cover + if sig == signal.SIGTERM: + self._proc.kill() + # py >= 2.7 + elif sig in (getattr(signal, "CTRL_C_EVENT", object()), + getattr(signal, "CTRL_BREAK_EVENT", object())): + self._proc.send_signal(sig) + else: + raise ValueError( + "only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals " + "are supported on Windows") + + @_assert_pid_not_reused + def suspend(self): + """Suspend process execution with SIGSTOP pre-emptively checking + whether PID has been reused. + On Windows this has the effect ot suspending all process threads. + """ + if POSIX: + self._send_signal(signal.SIGSTOP) + else: # pragma: no cover + self._proc.suspend() + + @_assert_pid_not_reused + def resume(self): + """Resume process execution with SIGCONT pre-emptively checking + whether PID has been reused. + On Windows this has the effect of resuming all process threads. + """ + if POSIX: + self._send_signal(signal.SIGCONT) + else: # pragma: no cover + self._proc.resume() + + @_assert_pid_not_reused + def terminate(self): + """Terminate the process with SIGTERM pre-emptively checking + whether PID has been reused. + On Windows this is an alias for kill(). + """ + if POSIX: + self._send_signal(signal.SIGTERM) + else: # pragma: no cover + self._proc.kill() + + @_assert_pid_not_reused + def kill(self): + """Kill the current process with SIGKILL pre-emptively checking + whether PID has been reused. + """ + if POSIX: + self._send_signal(signal.SIGKILL) + else: # pragma: no cover + self._proc.kill() + + def wait(self, timeout=None): + """Wait for process to terminate and, if process is a children + of os.getpid(), also return its exit code, else None. + + If the process is already terminated immediately return None + instead of raising NoSuchProcess. + + If timeout (in seconds) is specified and process is still alive + raise TimeoutExpired. + + To wait for multiple Process(es) use psutil.wait_procs(). + """ + if timeout is not None and not timeout >= 0: + raise ValueError("timeout must be a positive integer") + return self._proc.wait(timeout) + + +# ===================================================================== +# --- Popen class +# ===================================================================== + + +class Popen(Process): + """A more convenient interface to stdlib subprocess.Popen class. + It starts a sub process and deals with it exactly as when using + subprocess.Popen class but in addition also provides all the + properties and methods of psutil.Process class as a unified + interface: + + >>> import psutil + >>> from subprocess import PIPE + >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE) + >>> p.name() + 'python' + >>> p.uids() + user(real=1000, effective=1000, saved=1000) + >>> p.username() + 'giampaolo' + >>> p.communicate() + ('hi\n', None) + >>> p.terminate() + >>> p.wait(timeout=2) + 0 + >>> + + For method names common to both classes such as kill(), terminate() + and wait(), psutil.Process implementation takes precedence. + + Unlike subprocess.Popen this class pre-emptively checks whether PID + has been reused on send_signal(), terminate() and kill() so that + you don't accidentally terminate another process, fixing + http://bugs.python.org/issue6973. + + For a complete documentation refer to: + http://docs.python.org/library/subprocess.html + """ + + def __init__(self, *args, **kwargs): + # Explicitly avoid to raise NoSuchProcess in case the process + # spawned by subprocess.Popen terminates too quickly, see: + # https://github.com/giampaolo/psutil/issues/193 + self.__subproc = subprocess.Popen(*args, **kwargs) + self._init(self.__subproc.pid, _ignore_nsp=True) + + def __dir__(self): + return sorted(set(dir(Popen) + dir(subprocess.Popen))) + + def __enter__(self): + if hasattr(self.__subproc, '__enter__'): + self.__subproc.__enter__() + return self + + def __exit__(self, *args, **kwargs): + if hasattr(self.__subproc, '__exit__'): + return self.__subproc.__exit__(*args, **kwargs) + else: + if self.stdout: + self.stdout.close() + if self.stderr: + self.stderr.close() + try: + # Flushing a BufferedWriter may raise an error. + if self.stdin: + self.stdin.close() + finally: + # Wait for the process to terminate, to avoid zombies. + self.wait() + + def __getattribute__(self, name): + try: + return object.__getattribute__(self, name) + except AttributeError: + try: + return object.__getattribute__(self.__subproc, name) + except AttributeError: + raise AttributeError("%s instance has no attribute '%s'" + % (self.__class__.__name__, name)) + + def wait(self, timeout=None): + if self.__subproc.returncode is not None: + return self.__subproc.returncode + ret = super(Popen, self).wait(timeout) + self.__subproc.returncode = ret + return ret + + +# The valid attr names which can be processed by Process.as_dict(). +_as_dict_attrnames = set( + [x for x in dir(Process) if not x.startswith('_') and x not in + ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', + 'is_running', 'as_dict', 'parent', 'children', 'rlimit', + 'memory_info_ex', 'oneshot']]) + + +# ===================================================================== +# --- system processes related functions +# ===================================================================== + + +def pids(): + """Return a list of current running PIDs.""" + return _psplatform.pids() + + +def pid_exists(pid): + """Return True if given PID exists in the current process list. + This is faster than doing "pid in psutil.pids()" and + should be preferred. + """ + if pid < 0: + return False + elif pid == 0 and POSIX: + # On POSIX we use os.kill() to determine PID existence. + # According to "man 2 kill" PID 0 has a special meaning + # though: it refers to <> and that is not we want + # to do here. + return pid in pids() + else: + return _psplatform.pid_exists(pid) + + +_pmap = {} + + +def process_iter(): + """Return a generator yielding a Process instance for all + running processes. + + Every new Process instance is only created once and then cached + into an internal table which is updated every time this is used. + + Cached Process instances are checked for identity so that you're + safe in case a PID has been reused by another process, in which + case the cached instance is updated. + + The sorting order in which processes are yielded is based on + their PIDs. + """ + def add(pid): + proc = Process(pid) + _pmap[proc.pid] = proc + return proc + + def remove(pid): + _pmap.pop(pid, None) + + a = set(pids()) + b = set(_pmap.keys()) + new_pids = a - b + gone_pids = b - a + + for pid in gone_pids: + remove(pid) + for pid, proc in sorted(list(_pmap.items()) + + list(dict.fromkeys(new_pids).items())): + try: + if proc is None: # new process + yield add(pid) + else: + # use is_running() to check whether PID has been reused by + # another process in which case yield a new Process instance + if proc.is_running(): + yield proc + else: + yield add(pid) + except NoSuchProcess: + remove(pid) + except AccessDenied: + # Process creation time can't be determined hence there's + # no way to tell whether the pid of the cached process + # has been reused. Just return the cached version. + if proc is None and pid in _pmap: + try: + yield _pmap[pid] + except KeyError: + # If we get here it is likely that 2 threads were + # using process_iter(). + pass + else: + raise + + +def wait_procs(procs, timeout=None, callback=None): + """Convenience function which waits for a list of processes to + terminate. + + Return a (gone, alive) tuple indicating which processes + are gone and which ones are still alive. + + The gone ones will have a new 'returncode' attribute indicating + process exit status (may be None). + + 'callback' is a function which gets called every time a process + terminates (a Process instance is passed as callback argument). + + Function will return as soon as all processes terminate or when + timeout occurs. + + Typical use case is: + + - send SIGTERM to a list of processes + - give them some time to terminate + - send SIGKILL to those ones which are still alive + + Example: + + >>> def on_terminate(proc): + ... print("process {} terminated".format(proc)) + ... + >>> for p in procs: + ... p.terminate() + ... + >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate) + >>> for p in alive: + ... p.kill() + """ + def check_gone(proc, timeout): + try: + returncode = proc.wait(timeout=timeout) + except TimeoutExpired: + pass + else: + if returncode is not None or not proc.is_running(): + proc.returncode = returncode + gone.add(proc) + if callback is not None: + callback(proc) + + if timeout is not None and not timeout >= 0: + msg = "timeout must be a positive integer, got %s" % timeout + raise ValueError(msg) + gone = set() + alive = set(procs) + if callback is not None and not callable(callback): + raise TypeError("callback %r is not a callable" % callable) + if timeout is not None: + deadline = _timer() + timeout + + while alive: + if timeout is not None and timeout <= 0: + break + for proc in alive: + # Make sure that every complete iteration (all processes) + # will last max 1 sec. + # We do this because we don't want to wait too long on a + # single process: in case it terminates too late other + # processes may disappear in the meantime and their PID + # reused. + max_timeout = 1.0 / len(alive) + if timeout is not None: + timeout = min((deadline - _timer()), max_timeout) + if timeout <= 0: + break + check_gone(proc, timeout) + else: + check_gone(proc, max_timeout) + alive = alive - gone + + if alive: + # Last attempt over processes survived so far. + # timeout == 0 won't make this function wait any further. + for proc in alive: + check_gone(proc, 0) + alive = alive - gone + + return (list(gone), list(alive)) + + +# ===================================================================== +# --- CPU related functions +# ===================================================================== + + +@memoize +def cpu_count(logical=True): + """Return the number of logical CPUs in the system (same as + os.cpu_count() in Python 3.4). + + If logical is False return the number of physical cores only + (e.g. hyper thread CPUs are excluded). + + Return None if undetermined. + + The return value is cached after first call. + If desired cache can be cleared like this: + + >>> psutil.cpu_count.cache_clear() + """ + if logical: + return _psplatform.cpu_count_logical() + else: + return _psplatform.cpu_count_physical() + + +def cpu_times(percpu=False): + """Return system-wide CPU times as a namedtuple. + Every CPU time represents the seconds the CPU has spent in the given mode. + The namedtuple's fields availability varies depending on the platform: + - user + - system + - idle + - nice (UNIX) + - iowait (Linux) + - irq (Linux, FreeBSD) + - softirq (Linux) + - steal (Linux >= 2.6.11) + - guest (Linux >= 2.6.24) + - guest_nice (Linux >= 3.2.0) + + When percpu is True return a list of namedtuples for each CPU. + First element of the list refers to first CPU, second element + to second CPU and so on. + The order of the list is consistent across calls. + """ + if not percpu: + return _psplatform.cpu_times() + else: + return _psplatform.per_cpu_times() + + +try: + _last_cpu_times = cpu_times() +except Exception: + # Don't want to crash at import time. + _last_cpu_times = None + traceback.print_exc() + +try: + _last_per_cpu_times = cpu_times(percpu=True) +except Exception: + # Don't want to crash at import time. + _last_per_cpu_times = None + traceback.print_exc() + + +def _cpu_tot_time(times): + """Given a cpu_time() ntuple calculates the total CPU time + (including idle time). + """ + tot = sum(times) + if LINUX: + # On Linux guest times are already accounted in "user" or + # "nice" times, so we subtract them from total. + # Htop does the same. References: + # https://github.com/giampaolo/psutil/pull/940 + # http://unix.stackexchange.com/questions/178045 + # https://github.com/torvalds/linux/blob/ + # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/ + # cputime.c#L158 + tot -= getattr(times, "guest", 0) # Linux 2.6.24+ + tot -= getattr(times, "guest_nice", 0) # Linux 3.2.0+ + return tot + + +def _cpu_busy_time(times): + """Given a cpu_time() ntuple calculates the busy CPU time. + We do so by subtracting all idle CPU times. + """ + busy = _cpu_tot_time(times) + busy -= times.idle + # Linux: "iowait" is time during which the CPU does not do anything + # (waits for IO to complete). On Linux IO wait is *not* accounted + # in "idle" time so we subtract it. Htop does the same. + # References: + # https://github.com/torvalds/linux/blob/ + # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244 + busy -= getattr(times, "iowait", 0) + return busy + + +def cpu_percent(interval=None, percpu=False): + """Return a float representing the current system-wide CPU + utilization as a percentage. + + When interval is > 0.0 compares system CPU times elapsed before + and after the interval (blocking). + + When interval is 0.0 or None compares system CPU times elapsed + since last call or module import, returning immediately (non + blocking). That means the first time this is called it will + return a meaningless 0.0 value which you should ignore. + In this case is recommended for accuracy that this function be + called with at least 0.1 seconds between calls. + + When percpu is True returns a list of floats representing the + utilization as a percentage for each CPU. + First element of the list refers to first CPU, second element + to second CPU and so on. + The order of the list is consistent across calls. + + Examples: + + >>> # blocking, system-wide + >>> psutil.cpu_percent(interval=1) + 2.0 + >>> + >>> # blocking, per-cpu + >>> psutil.cpu_percent(interval=1, percpu=True) + [2.0, 1.0] + >>> + >>> # non-blocking (percentage since last call) + >>> psutil.cpu_percent(interval=None) + 2.9 + >>> + """ + global _last_cpu_times + global _last_per_cpu_times + blocking = interval is not None and interval > 0.0 + if interval is not None and interval < 0: + raise ValueError("interval is not positive (got %r)" % interval) + + def calculate(t1, t2): + t1_all = _cpu_tot_time(t1) + t1_busy = _cpu_busy_time(t1) + + t2_all = _cpu_tot_time(t2) + t2_busy = _cpu_busy_time(t2) + + # this usually indicates a float precision issue + if t2_busy <= t1_busy: + return 0.0 + + busy_delta = t2_busy - t1_busy + all_delta = t2_all - t1_all + try: + busy_perc = (busy_delta / all_delta) * 100 + except ZeroDivisionError: + return 0.0 + else: + return round(busy_perc, 1) + + # system-wide usage + if not percpu: + if blocking: + t1 = cpu_times() + time.sleep(interval) + else: + t1 = _last_cpu_times + if t1 is None: + # Something bad happened at import time. We'll + # get a meaningful result on the next call. See: + # https://github.com/giampaolo/psutil/pull/715 + t1 = cpu_times() + _last_cpu_times = cpu_times() + return calculate(t1, _last_cpu_times) + # per-cpu usage + else: + ret = [] + if blocking: + tot1 = cpu_times(percpu=True) + time.sleep(interval) + else: + tot1 = _last_per_cpu_times + if tot1 is None: + # Something bad happened at import time. We'll + # get a meaningful result on the next call. See: + # https://github.com/giampaolo/psutil/pull/715 + tot1 = cpu_times(percpu=True) + _last_per_cpu_times = cpu_times(percpu=True) + for t1, t2 in zip(tot1, _last_per_cpu_times): + ret.append(calculate(t1, t2)) + return ret + + +# Use separate global vars for cpu_times_percent() so that it's +# independent from cpu_percent() and they can both be used within +# the same program. +_last_cpu_times_2 = _last_cpu_times +_last_per_cpu_times_2 = _last_per_cpu_times + + +def cpu_times_percent(interval=None, percpu=False): + """Same as cpu_percent() but provides utilization percentages + for each specific CPU time as is returned by cpu_times(). + For instance, on Linux we'll get: + + >>> cpu_times_percent() + cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0, + irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) + >>> + + interval and percpu arguments have the same meaning as in + cpu_percent(). + """ + global _last_cpu_times_2 + global _last_per_cpu_times_2 + blocking = interval is not None and interval > 0.0 + if interval is not None and interval < 0: + raise ValueError("interval is not positive (got %r)" % interval) + + def calculate(t1, t2): + nums = [] + all_delta = _cpu_tot_time(t2) - _cpu_tot_time(t1) + for field in t1._fields: + field_delta = getattr(t2, field) - getattr(t1, field) + try: + field_perc = (100 * field_delta) / all_delta + except ZeroDivisionError: + field_perc = 0.0 + field_perc = round(field_perc, 1) + # CPU times are always supposed to increase over time + # or at least remain the same and that's because time + # cannot go backwards. + # Surprisingly sometimes this might not be the case (at + # least on Windows and Linux), see: + # https://github.com/giampaolo/psutil/issues/392 + # https://github.com/giampaolo/psutil/issues/645 + # I really don't know what to do about that except + # forcing the value to 0 or 100. + if field_perc > 100.0: + field_perc = 100.0 + # `<=` because `-0.0 == 0.0` evaluates to True + elif field_perc <= 0.0: + field_perc = 0.0 + nums.append(field_perc) + return _psplatform.scputimes(*nums) + + # system-wide usage + if not percpu: + if blocking: + t1 = cpu_times() + time.sleep(interval) + else: + t1 = _last_cpu_times_2 + if t1 is None: + # Something bad happened at import time. We'll + # get a meaningful result on the next call. See: + # https://github.com/giampaolo/psutil/pull/715 + t1 = cpu_times() + _last_cpu_times_2 = cpu_times() + return calculate(t1, _last_cpu_times_2) + # per-cpu usage + else: + ret = [] + if blocking: + tot1 = cpu_times(percpu=True) + time.sleep(interval) + else: + tot1 = _last_per_cpu_times_2 + if tot1 is None: + # Something bad happened at import time. We'll + # get a meaningful result on the next call. See: + # https://github.com/giampaolo/psutil/pull/715 + tot1 = cpu_times(percpu=True) + _last_per_cpu_times_2 = cpu_times(percpu=True) + for t1, t2 in zip(tot1, _last_per_cpu_times_2): + ret.append(calculate(t1, t2)) + return ret + + +def cpu_stats(): + """Return CPU statistics.""" + return _psplatform.cpu_stats() + + +if hasattr(_psplatform, "cpu_freq"): + + def cpu_freq(percpu=False): + """Return CPU frequency as a nameduple including current, + min and max frequency expressed in Mhz. + + If percpu is True and the system supports per-cpu frequency + retrieval (Linux only) a list of frequencies is returned for + each CPU. If not a list with one element is returned. + """ + ret = _psplatform.cpu_freq() + if percpu: + return ret + else: + num_cpus = float(len(ret)) + if num_cpus == 0: + return [] + elif num_cpus == 1: + return ret[0] + else: + currs, mins, maxs = 0.0, 0.0, 0.0 + for cpu in ret: + currs += cpu.current + mins += cpu.min + maxs += cpu.max + try: + current = currs / num_cpus + except ZeroDivisionError: + current = 0.0 + try: + min_ = mins / num_cpus + except ZeroDivisionError: + min_ = 0.0 + try: + max_ = maxs / num_cpus + except ZeroDivisionError: + max_ = 0.0 + return _common.scpufreq(current, min_, max_) + + __all__.append("cpu_freq") + + +# ===================================================================== +# --- system memory related functions +# ===================================================================== + + +def virtual_memory(): + """Return statistics about system memory usage as a namedtuple + including the following fields, expressed in bytes: + + - total: + total physical memory available. + + - available: + the memory that can be given instantly to processes without the + system going into swap. + This is calculated by summing different memory values depending + on the platform and it is supposed to be used to monitor actual + memory usage in a cross platform fashion. + + - percent: + the percentage usage calculated as (total - available) / total * 100 + + - used: + memory used, calculated differently depending on the platform and + designed for informational purposes only: + OSX: active + inactive + wired + BSD: active + wired + cached + LINUX: total - free + + - free: + memory not being used at all (zeroed) that is readily available; + note that this doesn't reflect the actual memory available + (use 'available' instead) + + Platform-specific fields: + + - active (UNIX): + memory currently in use or very recently used, and so it is in RAM. + + - inactive (UNIX): + memory that is marked as not used. + + - buffers (BSD, Linux): + cache for things like file system metadata. + + - cached (BSD, OSX): + cache for various things. + + - wired (OSX, BSD): + memory that is marked to always stay in RAM. It is never moved to disk. + + - shared (BSD): + memory that may be simultaneously accessed by multiple processes. + + The sum of 'used' and 'available' does not necessarily equal total. + On Windows 'available' and 'free' are the same. + """ + global _TOTAL_PHYMEM + ret = _psplatform.virtual_memory() + # cached for later use in Process.memory_percent() + _TOTAL_PHYMEM = ret.total + return ret + + +def swap_memory(): + """Return system swap memory statistics as a namedtuple including + the following fields: + + - total: total swap memory in bytes + - used: used swap memory in bytes + - free: free swap memory in bytes + - percent: the percentage usage + - sin: no. of bytes the system has swapped in from disk (cumulative) + - sout: no. of bytes the system has swapped out from disk (cumulative) + + 'sin' and 'sout' on Windows are meaningless and always set to 0. + """ + return _psplatform.swap_memory() + + +# ===================================================================== +# --- disks/paritions related functions +# ===================================================================== + + +def disk_usage(path): + """Return disk usage statistics about the given path as a namedtuple + including total, used and free space expressed in bytes plus the + percentage usage. + """ + return _psplatform.disk_usage(path) + + +def disk_partitions(all=False): + """Return mounted partitions as a list of + (device, mountpoint, fstype, opts) namedtuple. + 'opts' field is a raw string separated by commas indicating mount + options which may vary depending on the platform. + + If "all" parameter is False return physical devices only and ignore + all others. + """ + return _psplatform.disk_partitions(all) + + +def disk_io_counters(perdisk=False): + """Return system disk I/O statistics as a namedtuple including + the following fields: + + - read_count: number of reads + - write_count: number of writes + - read_bytes: number of bytes read + - write_bytes: number of bytes written + - read_time: time spent reading from disk (in milliseconds) + - write_time: time spent writing to disk (in milliseconds) + + If perdisk is True return the same information for every + physical disk installed on the system as a dictionary + with partition names as the keys and the namedtuple + described above as the values. + + On recent Windows versions 'diskperf -y' command may need to be + executed first otherwise this function won't find any disk. + """ + rawdict = _psplatform.disk_io_counters() + if not rawdict: + raise RuntimeError("couldn't find any physical disk") + nt = getattr(_psplatform, "sdiskio", _common.sdiskio) + if perdisk: + for disk, fields in rawdict.items(): + rawdict[disk] = nt(*fields) + return rawdict + else: + return nt(*[sum(x) for x in zip(*rawdict.values())]) + + +# ===================================================================== +# --- network related functions +# ===================================================================== + + +def net_io_counters(pernic=False): + """Return network I/O statistics as a namedtuple including + the following fields: + + - bytes_sent: number of bytes sent + - bytes_recv: number of bytes received + - packets_sent: number of packets sent + - packets_recv: number of packets received + - errin: total number of errors while receiving + - errout: total number of errors while sending + - dropin: total number of incoming packets which were dropped + - dropout: total number of outgoing packets which were dropped + (always 0 on OSX and BSD) + + If pernic is True return the same information for every + network interface installed on the system as a dictionary + with network interface names as the keys and the namedtuple + described above as the values. + """ + rawdict = _psplatform.net_io_counters() + if not rawdict: + raise RuntimeError("couldn't find any network interface") + if pernic: + for nic, fields in rawdict.items(): + rawdict[nic] = _common.snetio(*fields) + return rawdict + else: + return _common.snetio(*[sum(x) for x in zip(*rawdict.values())]) + + +def net_connections(kind='inet'): + """Return system-wide connections as a list of + (fd, family, type, laddr, raddr, status, pid) namedtuples. + In case of limited privileges 'fd' and 'pid' may be set to -1 + and None respectively. + The 'kind' parameter filters for connections that fit the + following criteria: + + Kind Value Connections using + inet IPv4 and IPv6 + inet4 IPv4 + inet6 IPv6 + tcp TCP + tcp4 TCP over IPv4 + tcp6 TCP over IPv6 + udp UDP + udp4 UDP over IPv4 + udp6 UDP over IPv6 + unix UNIX socket (both UDP and TCP protocols) + all the sum of all the possible families and protocols + + On OSX this function requires root privileges. + """ + return _psplatform.net_connections(kind) + + +def net_if_addrs(): + """Return the addresses associated to each NIC (network interface + card) installed on the system as a dictionary whose keys are the + NIC names and value is a list of namedtuples for each address + assigned to the NIC. Each namedtuple includes 5 fields: + + - family + - address + - netmask + - broadcast + - ptp + + 'family' can be either socket.AF_INET, socket.AF_INET6 or + psutil.AF_LINK, which refers to a MAC address. + 'address' is the primary address and it is always set. + 'netmask' and 'broadcast' and 'ptp' may be None. + 'ptp' stands for "point to point" and references the destination + address on a point to point interface (typically a VPN). + 'broadcast' and 'ptp' are mutually exclusive. + + Note: you can have more than one address of the same family + associated with each interface. + """ + has_enums = sys.version_info >= (3, 4) + if has_enums: + import socket + rawlist = _psplatform.net_if_addrs() + rawlist.sort(key=lambda x: x[1]) # sort by family + ret = collections.defaultdict(list) + for name, fam, addr, mask, broadcast, ptp in rawlist: + if has_enums: + try: + fam = socket.AddressFamily(fam) + except ValueError: + if WINDOWS and fam == -1: + fam = _psplatform.AF_LINK + elif (hasattr(_psplatform, "AF_LINK") and + _psplatform.AF_LINK == fam): + # Linux defines AF_LINK as an alias for AF_PACKET. + # We re-set the family here so that repr(family) + # will show AF_LINK rather than AF_PACKET + fam = _psplatform.AF_LINK + if fam == _psplatform.AF_LINK: + # The underlying C function may return an incomplete MAC + # address in which case we fill it with null bytes, see: + # https://github.com/giampaolo/psutil/issues/786 + separator = ":" if POSIX else "-" + while addr.count(separator) < 5: + addr += "%s00" % separator + ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp)) + return dict(ret) + + +def net_if_stats(): + """Return information about each NIC (network interface card) + installed on the system as a dictionary whose keys are the + NIC names and value is a namedtuple with the following fields: + + - isup: whether the interface is up (bool) + - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or + NIC_DUPLEX_UNKNOWN + - speed: the NIC speed expressed in mega bits (MB); if it can't + be determined (e.g. 'localhost') it will be set to 0. + - mtu: the maximum transmission unit expressed in bytes. + """ + return _psplatform.net_if_stats() + + +# ===================================================================== +# --- sensors +# ===================================================================== + + +# Linux +if hasattr(_psplatform, "sensors_temperatures"): + + def sensors_temperatures(fahrenheit=False): + """Return hardware temperatures. Each entry is a namedtuple + representing a certain hardware sensor (it may be a CPU, an + hard disk or something else, depending on the OS and its + configuration). + All temperatures are expressed in celsius unless *fahrenheit* + is set to True. + """ + def to_fahrenheit(n): + return (float(n) * 9 / 5) + 32 + + ret = collections.defaultdict(list) + rawdict = _psplatform.sensors_temperatures() + + for name, values in rawdict.items(): + while values: + label, current, high, critical = values.pop(0) + if fahrenheit: + current = to_fahrenheit(current) + if high is not None: + high = to_fahrenheit(high) + if critical is not None: + critical = to_fahrenheit(critical) + + if high and not critical: + critical = high + elif critical and not high: + high = critical + + ret[name].append( + _common.shwtemp(label, current, high, critical)) + + return dict(ret) + + __all__.append("sensors_temperatures") + + +# Linux +if hasattr(_psplatform, "sensors_fans"): + + def sensors_fans(): + """Return fans speed. Each entry is a namedtuple + representing a certain hardware sensor. + All speed are expressed in RPM (rounds per minute). + """ + return _psplatform.sensors_fans() + + __all__.append("sensors_fans") + + +# Linux, Windows, FreeBSD +if hasattr(_psplatform, "sensors_battery"): + + def sensors_battery(): + """Return battery information. If no battery is installed + returns None. + + - percent: battery power left as a percentage. + - secsleft: a rough approximation of how many seconds are left + before the battery runs out of power. + May be POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED. + - power_plugged: True if the AC power cable is connected. + """ + return _psplatform.sensors_battery() + + __all__.append("sensors_battery") + + +# ===================================================================== +# --- other system related functions +# ===================================================================== + + +def boot_time(): + """Return the system boot time expressed in seconds since the epoch.""" + # Note: we are not caching this because it is subject to + # system clock updates. + return _psplatform.boot_time() + + +def users(): + """Return users currently connected on the system as a list of + namedtuples including the following fields. + + - user: the name of the user + - terminal: the tty or pseudo-tty associated with the user, if any. + - host: the host name associated with the entry, if any. + - started: the creation time as a floating point number expressed in + seconds since the epoch. + """ + return _psplatform.users() + + +# ===================================================================== +# --- Windows services +# ===================================================================== + + +if WINDOWS: + + def win_service_iter(): + """Return a generator yielding a WindowsService instance for all + Windows services installed. + """ + return _psplatform.win_service_iter() + + def win_service_get(name): + """Get a Windows service by name. + Raise NoSuchProcess if no service with such name exists. + """ + return _psplatform.win_service_get(name) + + +# ===================================================================== + + +def test(): # pragma: no cover + """List info of all currently running processes emulating ps aux + output. + """ + import datetime + + today_day = datetime.date.today() + templ = "%-10s %5s %4s %7s %7s %-13s %5s %7s %s" + attrs = ['pid', 'memory_percent', 'name', 'cpu_times', 'create_time', + 'memory_info'] + if POSIX: + attrs.append('uids') + attrs.append('terminal') + print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "TTY", "START", "TIME", + "COMMAND")) + for p in process_iter(): + try: + pinfo = p.as_dict(attrs, ad_value='') + except NoSuchProcess: + pass + else: + if pinfo['create_time']: + ctime = datetime.datetime.fromtimestamp(pinfo['create_time']) + if ctime.date() == today_day: + ctime = ctime.strftime("%H:%M") + else: + ctime = ctime.strftime("%b%d") + else: + ctime = '' + cputime = time.strftime("%M:%S", + time.localtime(sum(pinfo['cpu_times']))) + try: + user = p.username() + except Error: + user = '' + if WINDOWS and '\\' in user: + user = user.split('\\')[1] + vms = pinfo['memory_info'] and \ + int(pinfo['memory_info'].vms / 1024) or '?' + rss = pinfo['memory_info'] and \ + int(pinfo['memory_info'].rss / 1024) or '?' + memp = pinfo['memory_percent'] and \ + round(pinfo['memory_percent'], 1) or '?' + print(templ % ( + user[:10], + pinfo['pid'], + memp, + vms, + rss, + pinfo.get('terminal', '') or '?', + ctime, + cputime, + pinfo['name'].strip() or '?')) + + +del memoize, memoize_when_activated, division, deprecated_method +if sys.version_info[0] < 3: + del num, x + +if __name__ == "__main__": + test() diff --git a/pipenv/vendor/psutil/_common.py b/pipenv/vendor/psutil/_common.py new file mode 100644 index 00000000..2497226a --- /dev/null +++ b/pipenv/vendor/psutil/_common.py @@ -0,0 +1,449 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Common objects shared by __init__.py and _ps*.py modules.""" + +from __future__ import division + +import contextlib +import errno +import functools +import os +import socket +import stat +import sys +import warnings +from collections import namedtuple +from socket import AF_INET +from socket import SOCK_DGRAM +from socket import SOCK_STREAM +try: + from socket import AF_INET6 +except ImportError: + AF_INET6 = None +try: + from socket import AF_UNIX +except ImportError: + AF_UNIX = None + +if sys.version_info >= (3, 4): + import enum +else: + enum = None + +__all__ = [ + # OS constants + 'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS', + 'WINDOWS', + # connection constants + 'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED', + 'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN', + 'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT', + # net constants + 'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN', + # process status constants + 'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED', + 'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED', + 'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL', + 'STATUS_WAKING', 'STATUS_ZOMBIE', + # named tuples + 'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile', + 'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart', + 'sdiskusage', 'snetio', 'snic', 'snicstats', 'sswap', 'suser', + # utility functions + 'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize', + 'parse_environ_block', 'path_exists_strict', 'usage_percent', + 'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum', +] + + +# =================================================================== +# --- OS constants +# =================================================================== + + +POSIX = os.name == "posix" +WINDOWS = os.name == "nt" +LINUX = sys.platform.startswith("linux") +OSX = sys.platform.startswith("darwin") +FREEBSD = sys.platform.startswith("freebsd") +OPENBSD = sys.platform.startswith("openbsd") +NETBSD = sys.platform.startswith("netbsd") +BSD = FREEBSD or OPENBSD or NETBSD +SUNOS = sys.platform.startswith("sunos") or sys.platform.startswith("solaris") + + +# =================================================================== +# --- API constants +# =================================================================== + + +# Process.status() +STATUS_RUNNING = "running" +STATUS_SLEEPING = "sleeping" +STATUS_DISK_SLEEP = "disk-sleep" +STATUS_STOPPED = "stopped" +STATUS_TRACING_STOP = "tracing-stop" +STATUS_ZOMBIE = "zombie" +STATUS_DEAD = "dead" +STATUS_WAKE_KILL = "wake-kill" +STATUS_WAKING = "waking" +STATUS_IDLE = "idle" # FreeBSD, OSX +STATUS_LOCKED = "locked" # FreeBSD +STATUS_WAITING = "waiting" # FreeBSD +STATUS_SUSPENDED = "suspended" # NetBSD + +# Process.connections() and psutil.net_connections() +CONN_ESTABLISHED = "ESTABLISHED" +CONN_SYN_SENT = "SYN_SENT" +CONN_SYN_RECV = "SYN_RECV" +CONN_FIN_WAIT1 = "FIN_WAIT1" +CONN_FIN_WAIT2 = "FIN_WAIT2" +CONN_TIME_WAIT = "TIME_WAIT" +CONN_CLOSE = "CLOSE" +CONN_CLOSE_WAIT = "CLOSE_WAIT" +CONN_LAST_ACK = "LAST_ACK" +CONN_LISTEN = "LISTEN" +CONN_CLOSING = "CLOSING" +CONN_NONE = "NONE" + +# net_if_stats() +if enum is None: + NIC_DUPLEX_FULL = 2 + NIC_DUPLEX_HALF = 1 + NIC_DUPLEX_UNKNOWN = 0 +else: + class NicDuplex(enum.IntEnum): + NIC_DUPLEX_FULL = 2 + NIC_DUPLEX_HALF = 1 + NIC_DUPLEX_UNKNOWN = 0 + + globals().update(NicDuplex.__members__) + +# sensors_battery() +if enum is None: + POWER_TIME_UNKNOWN = -1 + POWER_TIME_UNLIMITED = -2 +else: + class BatteryTime(enum.IntEnum): + POWER_TIME_UNKNOWN = -1 + POWER_TIME_UNLIMITED = -2 + + globals().update(BatteryTime.__members__) + + +# =================================================================== +# --- namedtuples +# =================================================================== + +# --- for system functions + +# psutil.swap_memory() +sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin', + 'sout']) +# psutil.disk_usage() +sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent']) +# psutil.disk_io_counters() +sdiskio = namedtuple('sdiskio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes', + 'read_time', 'write_time']) +# psutil.disk_partitions() +sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts']) +# psutil.net_io_counters() +snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv', + 'packets_sent', 'packets_recv', + 'errin', 'errout', + 'dropin', 'dropout']) +# psutil.users() +suser = namedtuple('suser', ['name', 'terminal', 'host', 'started']) +# psutil.net_connections() +sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr', + 'status', 'pid']) +# psutil.net_if_addrs() +snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp']) +# psutil.net_if_stats() +snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) +# psutil.cpu_stats() +scpustats = namedtuple( + 'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls']) +# psutil.cpu_freq() +scpufreq = namedtuple('scpufreq', ['current', 'min', 'max']) +# psutil.sensors_temperatures() +shwtemp = namedtuple( + 'shwtemp', ['label', 'current', 'high', 'critical']) +# psutil.sensors_battery() +sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged']) +# psutil.sensors_battery() +sfan = namedtuple('sfan', ['label', 'current']) + +# --- for Process methods + +# psutil.Process.cpu_times() +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) +# psutil.Process.open_files() +popenfile = namedtuple('popenfile', ['path', 'fd']) +# psutil.Process.threads() +pthread = namedtuple('pthread', ['id', 'user_time', 'system_time']) +# psutil.Process.uids() +puids = namedtuple('puids', ['real', 'effective', 'saved']) +# psutil.Process.gids() +pgids = namedtuple('pgids', ['real', 'effective', 'saved']) +# psutil.Process.io_counters() +pio = namedtuple('pio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes']) +# psutil.Process.ionice() +pionice = namedtuple('pionice', ['ioclass', 'value']) +# psutil.Process.ctx_switches() +pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary']) +# psutil.Process.connections() +pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr', + 'status']) + + +# =================================================================== +# --- Process.connections() 'kind' parameter mapping +# =================================================================== + + +conn_tmap = { + "all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]), + "tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]), + "tcp4": ([AF_INET], [SOCK_STREAM]), + "udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]), + "udp4": ([AF_INET], [SOCK_DGRAM]), + "inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]), + "inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]), + "inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]), +} + +if AF_INET6 is not None: + conn_tmap.update({ + "tcp6": ([AF_INET6], [SOCK_STREAM]), + "udp6": ([AF_INET6], [SOCK_DGRAM]), + }) + +if AF_UNIX is not None: + conn_tmap.update({ + "unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]), + }) + +del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM + + +# =================================================================== +# --- utils +# =================================================================== + + +def usage_percent(used, total, _round=None): + """Calculate percentage usage of 'used' against 'total'.""" + try: + ret = (used / total) * 100 + except ZeroDivisionError: + ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0 + if _round is not None: + return round(ret, _round) + else: + return ret + + +def memoize(fun): + """A simple memoize decorator for functions supporting (hashable) + positional arguments. + It also provides a cache_clear() function for clearing the cache: + + >>> @memoize + ... def foo() + ... return 1 + ... + >>> foo() + 1 + >>> foo.cache_clear() + >>> + """ + @functools.wraps(fun) + def wrapper(*args, **kwargs): + key = (args, frozenset(sorted(kwargs.items()))) + try: + return cache[key] + except KeyError: + ret = cache[key] = fun(*args, **kwargs) + return ret + + def cache_clear(): + """Clear cache.""" + cache.clear() + + cache = {} + wrapper.cache_clear = cache_clear + return wrapper + + +def memoize_when_activated(fun): + """A memoize decorator which is disabled by default. It can be + activated and deactivated on request. + For efficiency reasons it can be used only against class methods + accepting no arguments. + + >>> class Foo: + ... @memoize + ... def foo() + ... print(1) + ... + >>> f = Foo() + >>> # deactivated (default) + >>> foo() + 1 + >>> foo() + 1 + >>> + >>> # activated + >>> foo.cache_activate() + >>> foo() + 1 + >>> foo() + >>> foo() + >>> + """ + @functools.wraps(fun) + def wrapper(self): + if not wrapper.cache_activated: + return fun(self) + else: + try: + ret = cache[fun] + except KeyError: + ret = cache[fun] = fun(self) + return ret + + def cache_activate(): + """Activate cache.""" + wrapper.cache_activated = True + + def cache_deactivate(): + """Deactivate and clear cache.""" + wrapper.cache_activated = False + cache.clear() + + cache = {} + wrapper.cache_activated = False + wrapper.cache_activate = cache_activate + wrapper.cache_deactivate = cache_deactivate + return wrapper + + +def isfile_strict(path): + """Same as os.path.isfile() but does not swallow EACCES / EPERM + exceptions, see: + http://mail.python.org/pipermail/python-dev/2012-June/120787.html + """ + try: + st = os.stat(path) + except OSError as err: + if err.errno in (errno.EPERM, errno.EACCES): + raise + return False + else: + return stat.S_ISREG(st.st_mode) + + +def path_exists_strict(path): + """Same as os.path.exists() but does not swallow EACCES / EPERM + exceptions, see: + http://mail.python.org/pipermail/python-dev/2012-June/120787.html + """ + try: + os.stat(path) + except OSError as err: + if err.errno in (errno.EPERM, errno.EACCES): + raise + return False + else: + return True + + +def supports_ipv6(): + """Return True if IPv6 is supported on this platform.""" + if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"): + return False + try: + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + with contextlib.closing(sock): + sock.bind(("::1", 0)) + return True + except socket.error: + return False + + +def parse_environ_block(data): + """Parse a C environ block of environment variables into a dictionary.""" + # The block is usually raw data from the target process. It might contain + # trailing garbage and lines that do not look like assignments. + ret = {} + pos = 0 + + # localize global variable to speed up access. + WINDOWS_ = WINDOWS + while True: + next_pos = data.find("\0", pos) + # nul byte at the beginning or double nul byte means finish + if next_pos <= pos: + break + # there might not be an equals sign + equal_pos = data.find("=", pos, next_pos) + if equal_pos > pos: + key = data[pos:equal_pos] + value = data[equal_pos + 1:next_pos] + # Windows expects environment variables to be uppercase only + if WINDOWS_: + key = key.upper() + ret[key] = value + pos = next_pos + 1 + + return ret + + +def sockfam_to_enum(num): + """Convert a numeric socket family value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + if enum is None: + return num + else: # pragma: no cover + try: + return socket.AddressFamily(num) + except (ValueError, AttributeError): + return num + + +def socktype_to_enum(num): + """Convert a numeric socket type value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + if enum is None: + return num + else: # pragma: no cover + try: + return socket.AddressType(num) + except (ValueError, AttributeError): + return num + + +def deprecated_method(replacement): + """A decorator which can be used to mark a method as deprecated + 'replcement' is the method name which will be called instead. + """ + def outer(fun): + msg = "%s() is deprecated; use %s() instead" % ( + fun.__name__, replacement) + if fun.__doc__ is None: + fun.__doc__ = msg + + @functools.wraps(fun) + def inner(self, *args, **kwargs): + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) + return getattr(self, replacement)(*args, **kwargs) + return inner + return outer diff --git a/pipenv/vendor/psutil/_compat.py b/pipenv/vendor/psutil/_compat.py new file mode 100644 index 00000000..de91638f --- /dev/null +++ b/pipenv/vendor/psutil/_compat.py @@ -0,0 +1,249 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Module which provides compatibility with older Python versions.""" + +import collections +import functools +import os +import sys + +__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b", + "callable", "lru_cache", "which"] + +PY3 = sys.version_info[0] == 3 + +if PY3: + long = int + xrange = range + unicode = str + basestring = str + + def u(s): + return s + + def b(s): + return s.encode("latin-1") +else: + long = long + xrange = xrange + unicode = unicode + basestring = basestring + + def u(s): + return unicode(s, "unicode_escape") + + def b(s): + return s + + +# removed in 3.0, reintroduced in 3.2 +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +# --- stdlib additions + + +# py 3.2 functools.lru_cache +# Taken from: http://code.activestate.com/recipes/578078 +# Credit: Raymond Hettinger +try: + from functools import lru_cache +except ImportError: + try: + from threading import RLock + except ImportError: + from dummy_threading import RLock + + _CacheInfo = collections.namedtuple( + "CacheInfo", ["hits", "misses", "maxsize", "currsize"]) + + class _HashedSeq(list): + __slots__ = 'hashvalue' + + def __init__(self, tup, hash=hash): + self[:] = tup + self.hashvalue = hash(tup) + + def __hash__(self): + return self.hashvalue + + def _make_key(args, kwds, typed, + kwd_mark=(object(), ), + fasttypes=set((int, str, frozenset, type(None))), + sorted=sorted, tuple=tuple, type=type, len=len): + key = args + if kwds: + sorted_items = sorted(kwds.items()) + key += kwd_mark + for item in sorted_items: + key += item + if typed: + key += tuple(type(v) for v in args) + if kwds: + key += tuple(type(v) for k, v in sorted_items) + elif len(key) == 1 and type(key[0]) in fasttypes: + return key[0] + return _HashedSeq(key) + + def lru_cache(maxsize=100, typed=False): + """Least-recently-used cache decorator, see: + http://docs.python.org/3/library/functools.html#functools.lru_cache + """ + def decorating_function(user_function): + cache = dict() + stats = [0, 0] + HITS, MISSES = 0, 1 + make_key = _make_key + cache_get = cache.get + _len = len + lock = RLock() + root = [] + root[:] = [root, root, None, None] + nonlocal_root = [root] + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 + if maxsize == 0: + def wrapper(*args, **kwds): + result = user_function(*args, **kwds) + stats[MISSES] += 1 + return result + elif maxsize is None: + def wrapper(*args, **kwds): + key = make_key(args, kwds, typed) + result = cache_get(key, root) + if result is not root: + stats[HITS] += 1 + return result + result = user_function(*args, **kwds) + cache[key] = result + stats[MISSES] += 1 + return result + else: + def wrapper(*args, **kwds): + if kwds or typed: + key = make_key(args, kwds, typed) + else: + key = args + lock.acquire() + try: + link = cache_get(key) + if link is not None: + root, = nonlocal_root + link_prev, link_next, key, result = link + link_prev[NEXT] = link_next + link_next[PREV] = link_prev + last = root[PREV] + last[NEXT] = root[PREV] = link + link[PREV] = last + link[NEXT] = root + stats[HITS] += 1 + return result + finally: + lock.release() + result = user_function(*args, **kwds) + lock.acquire() + try: + root, = nonlocal_root + if key in cache: + pass + elif _len(cache) >= maxsize: + oldroot = root + oldroot[KEY] = key + oldroot[RESULT] = result + root = nonlocal_root[0] = oldroot[NEXT] + oldkey = root[KEY] + root[KEY] = root[RESULT] = None + del cache[oldkey] + cache[key] = oldroot + else: + last = root[PREV] + link = [last, root, key, result] + last[NEXT] = root[PREV] = cache[key] = link + stats[MISSES] += 1 + finally: + lock.release() + return result + + def cache_info(): + """Report cache statistics""" + lock.acquire() + try: + return _CacheInfo(stats[HITS], stats[MISSES], maxsize, + len(cache)) + finally: + lock.release() + + def cache_clear(): + """Clear the cache and cache statistics""" + lock.acquire() + try: + cache.clear() + root = nonlocal_root[0] + root[:] = [root, root, None, None] + stats[:] = [0, 0] + finally: + lock.release() + + wrapper.__wrapped__ = user_function + wrapper.cache_info = cache_info + wrapper.cache_clear = cache_clear + return functools.update_wrapper(wrapper, user_function) + + return decorating_function + + +# python 3.3 +try: + from shutil import which +except ImportError: + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + """ + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) and + not os.path.isdir(fn)) + + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + if os.curdir not in path: + path.insert(0, os.curdir) + + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if normdir not in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None diff --git a/pipenv/vendor/psutil/_psbsd.py b/pipenv/vendor/psutil/_psbsd.py new file mode 100644 index 00000000..fc5e1dc8 --- /dev/null +++ b/pipenv/vendor/psutil/_psbsd.py @@ -0,0 +1,855 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""FreeBSD, OpenBSD and NetBSD platforms implementation.""" + +import contextlib +import errno +import functools +import os +import xml.etree.ElementTree as ET +from collections import namedtuple + +from . import _common +from . import _psposix +from . import _psutil_bsd as cext +from . import _psutil_posix as cext_posix +from ._common import conn_tmap +from ._common import FREEBSD +from ._common import memoize +from ._common import memoize_when_activated +from ._common import NETBSD +from ._common import OPENBSD +from ._common import sockfam_to_enum +from ._common import socktype_to_enum +from ._common import usage_percent +from ._compat import which + +__extra__all__ = [] + + +# ===================================================================== +# --- globals +# ===================================================================== + + +if FREEBSD: + PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SRUN: _common.STATUS_RUNNING, + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SSTOP: _common.STATUS_STOPPED, + cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SWAIT: _common.STATUS_WAITING, + cext.SLOCK: _common.STATUS_LOCKED, + } +elif OPENBSD or NETBSD: + PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SSTOP: _common.STATUS_STOPPED, + # According to /usr/include/sys/proc.h SZOMB is unused. + # test_zombie_process() shows that SDEAD is the right + # equivalent. Also it appears there's no equivalent of + # psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE. + # cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SDEAD: _common.STATUS_ZOMBIE, + cext.SZOMB: _common.STATUS_ZOMBIE, + # From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt + # OpenBSD has SRUN and SONPROC: SRUN indicates that a process + # is runnable but *not* yet running, i.e. is on a run queue. + # SONPROC indicates that the process is actually executing on + # a CPU, i.e. it is no longer on a run queue. + # As such we'll map SRUN to STATUS_WAKING and SONPROC to + # STATUS_RUNNING + cext.SRUN: _common.STATUS_WAKING, + cext.SONPROC: _common.STATUS_RUNNING, + } +elif NETBSD: + PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SACTIVE: _common.STATUS_RUNNING, + cext.SDYING: _common.STATUS_ZOMBIE, + cext.SSTOP: _common.STATUS_STOPPED, + cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SDEAD: _common.STATUS_DEAD, + cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD + } + +TCP_STATUSES = { + cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, + cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, + cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV, + cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, + cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, + cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, + cext.TCPS_CLOSED: _common.CONN_CLOSE, + cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, + cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, + cext.TCPS_LISTEN: _common.CONN_LISTEN, + cext.TCPS_CLOSING: _common.CONN_CLOSING, + cext.PSUTIL_CONN_NONE: _common.CONN_NONE, +} + +if NETBSD: + PAGESIZE = os.sysconf("SC_PAGESIZE") +else: + PAGESIZE = os.sysconf("SC_PAGE_SIZE") +AF_LINK = cext_posix.AF_LINK + +kinfo_proc_map = dict( + ppid=0, + status=1, + real_uid=2, + effective_uid=3, + saved_uid=4, + real_gid=5, + effective_gid=6, + saved_gid=7, + ttynr=8, + create_time=9, + ctx_switches_vol=10, + ctx_switches_unvol=11, + read_io_count=12, + write_io_count=13, + user_time=14, + sys_time=15, + ch_user_time=16, + ch_sys_time=17, + rss=18, + vms=19, + memtext=20, + memdata=21, + memstack=22, + cpunum=23, + name=24, +) + +# these get overwritten on "import psutil" from the __init__.py file +NoSuchProcess = None +ZombieProcess = None +AccessDenied = None +TimeoutExpired = None + + +# ===================================================================== +# --- named tuples +# ===================================================================== + + +# psutil.virtual_memory() +svmem = namedtuple( + 'svmem', ['total', 'available', 'percent', 'used', 'free', + 'active', 'inactive', 'buffers', 'cached', 'shared', 'wired']) +# psutil.cpu_times() +scputimes = namedtuple( + 'scputimes', ['user', 'nice', 'system', 'idle', 'irq']) +# psutil.Process.memory_info() +pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack']) +# psutil.Process.memory_full_info() +pfullmem = pmem +# psutil.Process.cpu_times() +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) +# psutil.Process.memory_maps(grouped=True) +pmmap_grouped = namedtuple( + 'pmmap_grouped', 'path rss, private, ref_count, shadow_count') +# psutil.Process.memory_maps(grouped=False) +pmmap_ext = namedtuple( + 'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count') +# psutil.disk_io_counters() +if FREEBSD: + sdiskio = namedtuple('sdiskio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes', + 'read_time', 'write_time', + 'busy_time']) +else: + sdiskio = namedtuple('sdiskio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes']) + + +# ===================================================================== +# --- memory +# ===================================================================== + + +def virtual_memory(): + """System virtual memory as a namedtuple.""" + mem = cext.virtual_mem() + total, free, active, inactive, wired, cached, buffers, shared = mem + if NETBSD: + # On NetBSD buffers and shared mem is determined via /proc. + # The C ext set them to 0. + with open('/proc/meminfo', 'rb') as f: + for line in f: + if line.startswith(b'Buffers:'): + buffers = int(line.split()[1]) * 1024 + elif line.startswith(b'MemShared:'): + shared = int(line.split()[1]) * 1024 + avail = inactive + cached + free + used = active + wired + cached + percent = usage_percent((total - avail), total, _round=1) + return svmem(total, avail, percent, used, free, + active, inactive, buffers, cached, shared, wired) + + +def swap_memory(): + """System swap memory as (total, used, free, sin, sout) namedtuple.""" + total, used, free, sin, sout = cext.swap_mem() + percent = usage_percent(used, total, _round=1) + return _common.sswap(total, used, free, percent, sin, sout) + + +# ===================================================================== +# --- CPU +# ===================================================================== + + +def cpu_times(): + """Return system per-CPU times as a namedtuple""" + user, nice, system, idle, irq = cext.cpu_times() + return scputimes(user, nice, system, idle, irq) + + +if hasattr(cext, "per_cpu_times"): + def per_cpu_times(): + """Return system CPU times as a namedtuple""" + ret = [] + for cpu_t in cext.per_cpu_times(): + user, nice, system, idle, irq = cpu_t + item = scputimes(user, nice, system, idle, irq) + ret.append(item) + return ret +else: + # XXX + # Ok, this is very dirty. + # On FreeBSD < 8 we cannot gather per-cpu information, see: + # https://github.com/giampaolo/psutil/issues/226 + # If num cpus > 1, on first call we return single cpu times to avoid a + # crash at psutil import time. + # Next calls will fail with NotImplementedError + def per_cpu_times(): + """Return system CPU times as a namedtuple""" + if cpu_count_logical() == 1: + return [cpu_times()] + if per_cpu_times.__called__: + raise NotImplementedError("supported only starting from FreeBSD 8") + per_cpu_times.__called__ = True + return [cpu_times()] + + per_cpu_times.__called__ = False + + +def cpu_count_logical(): + """Return the number of logical CPUs in the system.""" + return cext.cpu_count_logical() + + +if OPENBSD or NETBSD: + def cpu_count_physical(): + # OpenBSD and NetBSD do not implement this. + return 1 if cpu_count_logical() == 1 else None +else: + def cpu_count_physical(): + """Return the number of physical CPUs in the system.""" + # From the C module we'll get an XML string similar to this: + # http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html + # We may get None in case "sysctl kern.sched.topology_spec" + # is not supported on this BSD version, in which case we'll mimic + # os.cpu_count() and return None. + ret = None + s = cext.cpu_count_phys() + if s is not None: + # get rid of padding chars appended at the end of the string + index = s.rfind("") + if index != -1: + s = s[:index + 9] + root = ET.fromstring(s) + try: + ret = len(root.findall('group/children/group/cpu')) or None + finally: + # needed otherwise it will memleak + root.clear() + if not ret: + # If logical CPUs are 1 it's obvious we'll have only 1 + # physical CPU. + if cpu_count_logical() == 1: + return 1 + return ret + + +def cpu_stats(): + """Return various CPU stats as a named tuple.""" + if FREEBSD: + # Note: the C ext is returning some metrics we are not exposing: + # traps. + ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats() + elif NETBSD: + # XXX + # Note about intrs: the C extension returns 0. intrs + # can be determined via /proc/stat; it has the same value as + # soft_intrs thought so the kernel is faking it (?). + # + # Note about syscalls: the C extension always sets it to 0 (?). + # + # Note: the C ext is returning some metrics we are not exposing: + # traps, faults and forks. + ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \ + cext.cpu_stats() + with open('/proc/stat', 'rb') as f: + for line in f: + if line.startswith(b'intr'): + intrs = int(line.split()[1]) + elif OPENBSD: + # Note: the C ext is returning some metrics we are not exposing: + # traps, faults and forks. + ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \ + cext.cpu_stats() + return _common.scpustats(ctxsw, intrs, soft_intrs, syscalls) + + +# ===================================================================== +# --- disks +# ===================================================================== + + +def disk_partitions(all=False): + """Return mounted disk partitions as a list of namedtuples. + 'all' argument is ignored, see: + https://github.com/giampaolo/psutil/issues/906 + """ + retlist = [] + partitions = cext.disk_partitions() + for partition in partitions: + device, mountpoint, fstype, opts = partition + ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) + retlist.append(ntuple) + return retlist + + +disk_usage = _psposix.disk_usage +disk_io_counters = cext.disk_io_counters + + +# ===================================================================== +# --- network +# ===================================================================== + + +net_io_counters = cext.net_io_counters +net_if_addrs = cext_posix.net_if_addrs + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + names = net_io_counters().keys() + ret = {} + for name in names: + mtu = cext_posix.net_if_mtu(name) + isup = cext_posix.net_if_flags(name) + duplex, speed = cext_posix.net_if_duplex_speed(name) + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + +def net_connections(kind): + """System-wide network connections.""" + if OPENBSD: + ret = [] + for pid in pids(): + try: + cons = Process(pid).connections(kind) + except (NoSuchProcess, ZombieProcess): + continue + else: + for conn in cons: + conn = list(conn) + conn.append(pid) + ret.append(_common.sconn(*conn)) + return ret + + if kind not in _common.conn_tmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in conn_tmap]))) + families, types = conn_tmap[kind] + ret = set() + if NETBSD: + rawlist = cext.net_connections(-1) + else: + rawlist = cext.net_connections() + for item in rawlist: + fd, fam, type, laddr, raddr, status, pid = item + # TODO: apply filter at C level + if fam in families and type in types: + try: + status = TCP_STATUSES[status] + except KeyError: + # XXX: Not sure why this happens. I saw this occurring + # with IPv6 sockets opened by 'vim'. Those sockets + # have a very short lifetime so maybe the kernel + # can't initialize their status? + status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) + ret.add(nt) + return list(ret) + + +# ===================================================================== +# --- sensors +# ===================================================================== + + +if FREEBSD: + + def sensors_battery(): + """Return battery info.""" + percent, minsleft, power_plugged = cext.sensors_battery() + power_plugged = power_plugged == 1 + if power_plugged: + secsleft = _common.POWER_TIME_UNLIMITED + elif minsleft == -1: + secsleft = _common.POWER_TIME_UNKNOWN + else: + secsleft = minsleft * 60 + return _common.sbattery(percent, secsleft, power_plugged) + + +# ===================================================================== +# --- other system functions +# ===================================================================== + + +def boot_time(): + """The system boot time expressed in seconds since the epoch.""" + return cext.boot_time() + + +def users(): + """Return currently connected users as a list of namedtuples.""" + retlist = [] + rawlist = cext.users() + for item in rawlist: + user, tty, hostname, tstamp = item + if tty == '~': + continue # reboot or shutdown + nt = _common.suser(user, tty or None, hostname, tstamp) + retlist.append(nt) + return retlist + + +# ===================================================================== +# --- processes +# ===================================================================== + + +@memoize +def _pid_0_exists(): + try: + Process(0).name() + except NoSuchProcess: + return False + except AccessDenied: + return True + else: + return True + + +def pids(): + """Returns a list of PIDs currently running on the system.""" + ret = cext.pids() + if OPENBSD and (0 not in ret) and _pid_0_exists(): + # On OpenBSD the kernel does not return PID 0 (neither does + # ps) but it's actually querable (Process(0) will succeed). + ret.insert(0, 0) + return ret + + +if OPENBSD or NETBSD: + def pid_exists(pid): + """Return True if pid exists.""" + exists = _psposix.pid_exists(pid) + if not exists: + # We do this because _psposix.pid_exists() lies in case of + # zombie processes. + return pid in pids() + else: + return True +else: + pid_exists = _psposix.pid_exists + + +def wrap_exceptions(fun): + """Decorator which translates bare OSError exceptions into + NoSuchProcess and AccessDenied. + """ + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except OSError as err: + if self.pid == 0: + if 0 in pids(): + raise AccessDenied(self.pid, self._name) + else: + raise + if err.errno == errno.ESRCH: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + return wrapper + + +@contextlib.contextmanager +def wrap_exceptions_procfs(inst): + """Same as above, for routines relying on reading /proc fs.""" + try: + yield + except EnvironmentError as err: + # ENOENT (no such file or directory) gets raised on open(). + # ESRCH (no such process) can get raised on read() if + # process is gone in meantime. + if err.errno in (errno.ENOENT, errno.ESRCH): + if not pid_exists(inst.pid): + raise NoSuchProcess(inst.pid, inst._name) + else: + raise ZombieProcess(inst.pid, inst._name, inst._ppid) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(inst.pid, inst._name) + raise + + +class Process(object): + """Wrapper class around underlying C implementation.""" + + __slots__ = ["pid", "_name", "_ppid"] + + def __init__(self, pid): + self.pid = pid + self._name = None + self._ppid = None + + @memoize_when_activated + def oneshot(self): + """Retrieves multiple process info in one shot as a raw tuple.""" + ret = cext.proc_oneshot_info(self.pid) + assert len(ret) == len(kinfo_proc_map) + return ret + + def oneshot_enter(self): + self.oneshot.cache_activate() + + def oneshot_exit(self): + self.oneshot.cache_deactivate() + + @wrap_exceptions + def name(self): + name = self.oneshot()[kinfo_proc_map['name']] + return name if name is not None else cext.proc_name(self.pid) + + @wrap_exceptions + def exe(self): + if FREEBSD: + return cext.proc_exe(self.pid) + elif NETBSD: + if self.pid == 0: + # /proc/0 dir exists but /proc/0/exe doesn't + return "" + with wrap_exceptions_procfs(self): + return os.readlink("/proc/%s/exe" % self.pid) + else: + # OpenBSD: exe cannot be determined; references: + # https://chromium.googlesource.com/chromium/src/base/+/ + # master/base_paths_posix.cc + # We try our best guess by using which against the first + # cmdline arg (may return None). + cmdline = self.cmdline() + if cmdline: + return which(cmdline[0]) + else: + return "" + + @wrap_exceptions + def cmdline(self): + if OPENBSD and self.pid == 0: + return [] # ...else it crashes + elif NETBSD: + # XXX - most of the times the underlying sysctl() call on Net + # and Open BSD returns a truncated string. + # Also /proc/pid/cmdline behaves the same so it looks + # like this is a kernel bug. + try: + return cext.proc_cmdline(self.pid) + except OSError as err: + if err.errno == errno.EINVAL: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise + else: + return cext.proc_cmdline(self.pid) + + @wrap_exceptions + def terminal(self): + tty_nr = self.oneshot()[kinfo_proc_map['ttynr']] + tmap = _psposix.get_terminal_map() + try: + return tmap[tty_nr] + except KeyError: + return None + + @wrap_exceptions + def ppid(self): + self._ppid = self.oneshot()[kinfo_proc_map['ppid']] + return self._ppid + + @wrap_exceptions + def uids(self): + rawtuple = self.oneshot() + return _common.puids( + rawtuple[kinfo_proc_map['real_uid']], + rawtuple[kinfo_proc_map['effective_uid']], + rawtuple[kinfo_proc_map['saved_uid']]) + + @wrap_exceptions + def gids(self): + rawtuple = self.oneshot() + return _common.pgids( + rawtuple[kinfo_proc_map['real_gid']], + rawtuple[kinfo_proc_map['effective_gid']], + rawtuple[kinfo_proc_map['saved_gid']]) + + @wrap_exceptions + def cpu_times(self): + rawtuple = self.oneshot() + return _common.pcputimes( + rawtuple[kinfo_proc_map['user_time']], + rawtuple[kinfo_proc_map['sys_time']], + rawtuple[kinfo_proc_map['ch_user_time']], + rawtuple[kinfo_proc_map['ch_sys_time']]) + + if FREEBSD: + @wrap_exceptions + def cpu_num(self): + return self.oneshot()[kinfo_proc_map['cpunum']] + + @wrap_exceptions + def memory_info(self): + rawtuple = self.oneshot() + return pmem( + rawtuple[kinfo_proc_map['rss']], + rawtuple[kinfo_proc_map['vms']], + rawtuple[kinfo_proc_map['memtext']], + rawtuple[kinfo_proc_map['memdata']], + rawtuple[kinfo_proc_map['memstack']]) + + memory_full_info = memory_info + + @wrap_exceptions + def create_time(self): + return self.oneshot()[kinfo_proc_map['create_time']] + + @wrap_exceptions + def num_threads(self): + if hasattr(cext, "proc_num_threads"): + # FreeBSD + return cext.proc_num_threads(self.pid) + else: + return len(self.threads()) + + @wrap_exceptions + def num_ctx_switches(self): + rawtuple = self.oneshot() + return _common.pctxsw( + rawtuple[kinfo_proc_map['ctx_switches_vol']], + rawtuple[kinfo_proc_map['ctx_switches_unvol']]) + + @wrap_exceptions + def threads(self): + # Note: on OpenSBD this (/dev/mem) requires root access. + rawlist = cext.proc_threads(self.pid) + retlist = [] + for thread_id, utime, stime in rawlist: + ntuple = _common.pthread(thread_id, utime, stime) + retlist.append(ntuple) + if OPENBSD: + # On OpenBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us + return retlist + + @wrap_exceptions + def connections(self, kind='inet'): + if kind not in conn_tmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in conn_tmap]))) + + if NETBSD: + families, types = conn_tmap[kind] + ret = set() + rawlist = cext.net_connections(self.pid) + for item in rawlist: + fd, fam, type, laddr, raddr, status, pid = item + assert pid == self.pid + if fam in families and type in types: + try: + status = TCP_STATUSES[status] + except KeyError: + status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + nt = _common.pconn(fd, fam, type, laddr, raddr, status) + ret.add(nt) + # On NetBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us + return list(ret) + + families, types = conn_tmap[kind] + rawlist = cext.proc_connections(self.pid, families, types) + ret = [] + for item in rawlist: + fd, fam, type, laddr, raddr, status = item + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + status = TCP_STATUSES[status] + nt = _common.pconn(fd, fam, type, laddr, raddr, status) + ret.append(nt) + if OPENBSD: + # On OpenBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us + return ret + + @wrap_exceptions + def wait(self, timeout=None): + try: + return _psposix.wait_pid(self.pid, timeout) + except _psposix.TimeoutExpired: + raise TimeoutExpired(timeout, self.pid, self._name) + + @wrap_exceptions + def nice_get(self): + return cext_posix.getpriority(self.pid) + + @wrap_exceptions + def nice_set(self, value): + return cext_posix.setpriority(self.pid, value) + + @wrap_exceptions + def status(self): + code = self.oneshot()[kinfo_proc_map['status']] + # XXX is '?' legit? (we're not supposed to return it anyway) + return PROC_STATUSES.get(code, '?') + + @wrap_exceptions + def io_counters(self): + rawtuple = self.oneshot() + return _common.pio( + rawtuple[kinfo_proc_map['read_io_count']], + rawtuple[kinfo_proc_map['write_io_count']], + -1, + -1) + + @wrap_exceptions + def cwd(self): + """Return process current working directory.""" + # sometimes we get an empty string, in which case we turn + # it into None + if OPENBSD and self.pid == 0: + return None # ...else it would raise EINVAL + elif NETBSD: + with wrap_exceptions_procfs(self): + return os.readlink("/proc/%s/cwd" % self.pid) + elif hasattr(cext, 'proc_open_files'): + # FreeBSD < 8 does not support functions based on + # kinfo_getfile() and kinfo_getvmmap() + return cext.proc_cwd(self.pid) or None + else: + raise NotImplementedError( + "supported only starting from FreeBSD 8" if + FREEBSD else "") + + nt_mmap_grouped = namedtuple( + 'mmap', 'path rss, private, ref_count, shadow_count') + nt_mmap_ext = namedtuple( + 'mmap', 'addr, perms path rss, private, ref_count, shadow_count') + + def _not_implemented(self): + raise NotImplementedError + + # FreeBSD < 8 does not support functions based on kinfo_getfile() + # and kinfo_getvmmap() + if hasattr(cext, 'proc_open_files'): + @wrap_exceptions + def open_files(self): + """Return files opened by process as a list of namedtuples.""" + rawlist = cext.proc_open_files(self.pid) + return [_common.popenfile(path, fd) for path, fd in rawlist] + else: + open_files = _not_implemented + + # FreeBSD < 8 does not support functions based on kinfo_getfile() + # and kinfo_getvmmap() + if hasattr(cext, 'proc_num_fds'): + @wrap_exceptions + def num_fds(self): + """Return the number of file descriptors opened by this process.""" + ret = cext.proc_num_fds(self.pid) + if NETBSD: + # On NetBSD the underlying C function does not raise NSP + # in case the process is gone. + self.name() # raise NSP if the process disappeared on us + return ret + else: + num_fds = _not_implemented + + # --- FreeBSD only APIs + + if FREEBSD: + + @wrap_exceptions + def cpu_affinity_get(self): + return cext.proc_cpu_affinity_get(self.pid) + + @wrap_exceptions + def cpu_affinity_set(self, cpus): + # Pre-emptively check if CPUs are valid because the C + # function has a weird behavior in case of invalid CPUs, + # see: https://github.com/giampaolo/psutil/issues/586 + allcpus = tuple(range(len(per_cpu_times()))) + for cpu in cpus: + if cpu not in allcpus: + raise ValueError("invalid CPU #%i (choose between %s)" + % (cpu, allcpus)) + try: + cext.proc_cpu_affinity_set(self.pid, cpus) + except OSError as err: + # 'man cpuset_setaffinity' about EDEADLK: + # <> + if err.errno in (errno.EINVAL, errno.EDEADLK): + for cpu in cpus: + if cpu not in allcpus: + raise ValueError( + "invalid CPU #%i (choose between %s)" % ( + cpu, allcpus)) + raise + + @wrap_exceptions + def memory_maps(self): + return cext.proc_memory_maps(self.pid) diff --git a/pipenv/vendor/psutil/_pslinux.py b/pipenv/vendor/psutil/_pslinux.py new file mode 100644 index 00000000..533b5485 --- /dev/null +++ b/pipenv/vendor/psutil/_pslinux.py @@ -0,0 +1,1872 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Linux platform implementation.""" + +from __future__ import division + +import base64 +import collections +import errno +import functools +import glob +import os +import re +import socket +import struct +import sys +import traceback +import warnings +from collections import defaultdict +from collections import namedtuple + +from . import _common +from . import _psposix +from . import _psutil_linux as cext +from . import _psutil_posix as cext_posix +from ._common import isfile_strict +from ._common import memoize +from ._common import memoize_when_activated +from ._common import parse_environ_block +from ._common import NIC_DUPLEX_FULL +from ._common import NIC_DUPLEX_HALF +from ._common import NIC_DUPLEX_UNKNOWN +from ._common import path_exists_strict +from ._common import supports_ipv6 +from ._common import usage_percent +from ._compat import b +from ._compat import basestring +from ._compat import long +from ._compat import PY3 + +if sys.version_info >= (3, 4): + import enum +else: + enum = None + + +__extra__all__ = [ + # + 'PROCFS_PATH', + # io prio constants + "IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE", + "IOPRIO_CLASS_IDLE", + # connection status constants + "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", + "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", + "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", ] + + +# ===================================================================== +# --- globals +# ===================================================================== + + +POWER_SUPPLY_PATH = "/sys/class/power_supply" +HAS_SMAPS = os.path.exists('/proc/%s/smaps' % os.getpid()) +HAS_PRLIMIT = hasattr(cext, "linux_prlimit") +_DEFAULT = object() + +# RLIMIT_* constants, not guaranteed to be present on all kernels +if HAS_PRLIMIT: + for name in dir(cext): + if name.startswith('RLIM'): + __extra__all__.append(name) + +# Number of clock ticks per second +CLOCK_TICKS = os.sysconf("SC_CLK_TCK") +PAGESIZE = os.sysconf("SC_PAGE_SIZE") +BOOT_TIME = None # set later +# Used when reading "big" files, namely /proc/{pid}/smaps and /proc/net/*. +# On Python 2, using a buffer with open() for such files may result in a +# speedup, see: https://github.com/giampaolo/psutil/issues/708 +BIGGER_FILE_BUFFERING = -1 if PY3 else 8192 +LITTLE_ENDIAN = sys.byteorder == 'little' +if PY3: + FS_ENCODING = sys.getfilesystemencoding() + ENCODING_ERRORS_HANDLER = 'surrogateescape' +if enum is None: + AF_LINK = socket.AF_PACKET +else: + AddressFamily = enum.IntEnum('AddressFamily', + {'AF_LINK': int(socket.AF_PACKET)}) + AF_LINK = AddressFamily.AF_LINK + +# ioprio_* constants http://linux.die.net/man/2/ioprio_get +if enum is None: + IOPRIO_CLASS_NONE = 0 + IOPRIO_CLASS_RT = 1 + IOPRIO_CLASS_BE = 2 + IOPRIO_CLASS_IDLE = 3 +else: + class IOPriority(enum.IntEnum): + IOPRIO_CLASS_NONE = 0 + IOPRIO_CLASS_RT = 1 + IOPRIO_CLASS_BE = 2 + IOPRIO_CLASS_IDLE = 3 + + globals().update(IOPriority.__members__) + +# taken from /fs/proc/array.c +PROC_STATUSES = { + "R": _common.STATUS_RUNNING, + "S": _common.STATUS_SLEEPING, + "D": _common.STATUS_DISK_SLEEP, + "T": _common.STATUS_STOPPED, + "t": _common.STATUS_TRACING_STOP, + "Z": _common.STATUS_ZOMBIE, + "X": _common.STATUS_DEAD, + "x": _common.STATUS_DEAD, + "K": _common.STATUS_WAKE_KILL, + "W": _common.STATUS_WAKING +} + +# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h +TCP_STATUSES = { + "01": _common.CONN_ESTABLISHED, + "02": _common.CONN_SYN_SENT, + "03": _common.CONN_SYN_RECV, + "04": _common.CONN_FIN_WAIT1, + "05": _common.CONN_FIN_WAIT2, + "06": _common.CONN_TIME_WAIT, + "07": _common.CONN_CLOSE, + "08": _common.CONN_CLOSE_WAIT, + "09": _common.CONN_LAST_ACK, + "0A": _common.CONN_LISTEN, + "0B": _common.CONN_CLOSING +} + +# these get overwritten on "import psutil" from the __init__.py file +NoSuchProcess = None +ZombieProcess = None +AccessDenied = None +TimeoutExpired = None + + +# ===================================================================== +# --- named tuples +# ===================================================================== + + +# psutil.virtual_memory() +svmem = namedtuple( + 'svmem', ['total', 'available', 'percent', 'used', 'free', + 'active', 'inactive', 'buffers', 'cached', 'shared']) +# psutil.disk_io_counters() +sdiskio = namedtuple( + 'sdiskio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes', + 'read_time', 'write_time', + 'read_merged_count', 'write_merged_count', + 'busy_time']) +# psutil.Process().open_files() +popenfile = namedtuple( + 'popenfile', ['path', 'fd', 'position', 'mode', 'flags']) +# psutil.Process().memory_info() +pmem = namedtuple('pmem', 'rss vms shared text lib data dirty') +# psutil.Process().memory_full_info() +pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', 'pss', 'swap')) +# psutil.Process().memory_maps(grouped=True) +pmmap_grouped = namedtuple( + 'pmmap_grouped', + ['path', 'rss', 'size', 'pss', 'shared_clean', 'shared_dirty', + 'private_clean', 'private_dirty', 'referenced', 'anonymous', 'swap']) +# psutil.Process().memory_maps(grouped=False) +pmmap_ext = namedtuple( + 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) +# psutil.Process.io_counters() +pio = namedtuple('pio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes', + 'read_chars', 'write_chars']) + + +# ===================================================================== +# --- utils +# ===================================================================== + + +def open_binary(fname, **kwargs): + return open(fname, "rb", **kwargs) + + +def open_text(fname, **kwargs): + """On Python 3 opens a file in text mode by using fs encoding and + a proper en/decoding errors handler. + On Python 2 this is just an alias for open(name, 'rt'). + """ + if PY3: + # See: + # https://github.com/giampaolo/psutil/issues/675 + # https://github.com/giampaolo/psutil/pull/733 + kwargs.setdefault('encoding', FS_ENCODING) + kwargs.setdefault('errors', ENCODING_ERRORS_HANDLER) + return open(fname, "rt", **kwargs) + + +if PY3: + def decode(s): + return s.decode(encoding=FS_ENCODING, errors=ENCODING_ERRORS_HANDLER) +else: + def decode(s): + return s + + +def get_procfs_path(): + """Return updated psutil.PROCFS_PATH constant.""" + return sys.modules['psutil'].PROCFS_PATH + + +def readlink(path): + """Wrapper around os.readlink().""" + assert isinstance(path, basestring), path + path = os.readlink(path) + # readlink() might return paths containing null bytes ('\x00') + # resulting in "TypeError: must be encoded string without NULL + # bytes, not str" errors when the string is passed to other + # fs-related functions (os.*, open(), ...). + # Apparently everything after '\x00' is garbage (we can have + # ' (deleted)', 'new' and possibly others), see: + # https://github.com/giampaolo/psutil/issues/717 + path = path.split('\x00')[0] + # Certain paths have ' (deleted)' appended. Usually this is + # bogus as the file actually exists. Even if it doesn't we + # don't care. + if path.endswith(' (deleted)') and not path_exists_strict(path): + path = path[:-10] + return path + + +def file_flags_to_mode(flags): + """Convert file's open() flags into a readable string. + Used by Process.open_files(). + """ + modes_map = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} + mode = modes_map[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] + if flags & os.O_APPEND: + mode = mode.replace('w', 'a', 1) + mode = mode.replace('w+', 'r+') + # possible values: r, w, a, r+, a+ + return mode + + +def get_sector_size(partition): + """Return the sector size of a partition. + Used by disk_io_counters(). + """ + try: + with open("/sys/block/%s/queue/hw_sector_size" % partition, "rt") as f: + return int(f.read()) + except (IOError, ValueError): + # man iostat states that sectors are equivalent with blocks and + # have a size of 512 bytes since 2.4 kernels. + return 512 + + +@memoize +def set_scputimes_ntuple(procfs_path): + """Set a namedtuple of variable fields depending on the CPU times + available on this Linux kernel version which may be: + (user, nice, system, idle, iowait, irq, softirq, [steal, [guest, + [guest_nice]]]) + Used by cpu_times() function. + """ + global scputimes + with open_binary('%s/stat' % procfs_path) as f: + values = f.readline().split()[1:] + fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq'] + vlen = len(values) + if vlen >= 8: + # Linux >= 2.6.11 + fields.append('steal') + if vlen >= 9: + # Linux >= 2.6.24 + fields.append('guest') + if vlen >= 10: + # Linux >= 3.2.0 + fields.append('guest_nice') + scputimes = namedtuple('scputimes', fields) + + +def cat(fname, fallback=_DEFAULT, binary=True): + """Return file content. + fallback: the value returned in case the file does not exist or + cannot be read + binary: whether to open the file in binary or text mode. + """ + try: + with open_binary(fname) if binary else open_text(fname) as f: + return f.read().strip() + except IOError: + if fallback != _DEFAULT: + return fallback + raise + + +try: + set_scputimes_ntuple("/proc") +except Exception: + # Don't want to crash at import time. + traceback.print_exc() + scputimes = namedtuple('scputimes', 'user system idle')(0.0, 0.0, 0.0) + + +# ===================================================================== +# --- system memory +# ===================================================================== + + +def calculate_avail_vmem(mems): + """Fallback for kernels < 3.14 where /proc/meminfo does not provide + "MemAvailable:" column (see: https://blog.famzah.net/2014/09/24/). + This code reimplements the algorithm outlined here: + https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ + commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773 + + XXX: on recent kernels this calculation differs by ~1.5% than + "MemAvailable:" as it's calculated slightly differently, see: + https://gitlab.com/procps-ng/procps/issues/42 + https://github.com/famzah/linux-memavailable-procfs/issues/2 + It is still way more realistic than doing (free + cached) though. + """ + # Fallback for very old distros. According to + # https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ + # commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773 + # ...long ago "avail" was calculated as (free + cached). + # We might fallback in such cases: + # "Active(file)" not available: 2.6.28 / Dec 2008 + # "Inactive(file)" not available: 2.6.28 / Dec 2008 + # "SReclaimable:" not available: 2.6.19 / Nov 2006 + # /proc/zoneinfo not available: 2.6.13 / Aug 2005 + free = mems[b'MemFree:'] + fallback = free + mems.get(b"Cached:", 0) + try: + lru_active_file = mems[b'Active(file):'] + lru_inactive_file = mems[b'Inactive(file):'] + slab_reclaimable = mems[b'SReclaimable:'] + except KeyError: + return fallback + try: + f = open_binary('%s/zoneinfo' % get_procfs_path()) + except IOError: + return fallback # kernel 2.6.13 + + watermark_low = 0 + with f: + for line in f: + line = line.strip() + if line.startswith(b'low'): + watermark_low += int(line.split()[1]) + watermark_low *= PAGESIZE + watermark_low = watermark_low + + avail = free - watermark_low + pagecache = lru_active_file + lru_inactive_file + pagecache -= min(pagecache / 2, watermark_low) + avail += pagecache + avail += slab_reclaimable - min(slab_reclaimable / 2.0, watermark_low) + return int(avail) + + +def virtual_memory(): + """Report virtual memory stats. + This implementation matches "free" and "vmstat -s" cmdline + utility values and procps-ng-3.3.12 source was used as a reference + (2016-09-18): + https://gitlab.com/procps-ng/procps/blob/ + 24fd2605c51fccc375ab0287cec33aa767f06718/proc/sysinfo.c + For reference, procps-ng-3.3.10 is the version available on Ubuntu + 16.04. + + Note about "available" memory: up until psutil 4.3 it was + calculated as "avail = (free + buffers + cached)". Now + "MemAvailable:" column (kernel 3.14) from /proc/meminfo is used as + it's more accurate. + That matches "available" column in newer versions of "free". + """ + missing_fields = [] + mems = {} + with open_binary('%s/meminfo' % get_procfs_path()) as f: + for line in f: + fields = line.split() + mems[fields[0]] = int(fields[1]) * 1024 + + # /proc doc states that the available fields in /proc/meminfo vary + # by architecture and compile options, but these 3 values are also + # returned by sysinfo(2); as such we assume they are always there. + total = mems[b'MemTotal:'] + free = mems[b'MemFree:'] + buffers = mems[b'Buffers:'] + + try: + cached = mems[b"Cached:"] + except KeyError: + cached = 0 + missing_fields.append('cached') + else: + # "free" cmdline utility sums reclaimable to cached. + # Older versions of procps used to add slab memory instead. + # This got changed in: + # https://gitlab.com/procps-ng/procps/commit/ + # 05d751c4f076a2f0118b914c5e51cfbb4762ad8e + cached += mems.get(b"SReclaimable:", 0) # since kernel 2.6.19 + + try: + shared = mems[b'Shmem:'] # since kernel 2.6.32 + except KeyError: + try: + shared = mems[b'MemShared:'] # kernels 2.4 + except KeyError: + shared = 0 + missing_fields.append('shared') + + try: + active = mems[b"Active:"] + except KeyError: + active = 0 + missing_fields.append('active') + + try: + inactive = mems[b"Inactive:"] + except KeyError: + try: + inactive = \ + mems[b"Inact_dirty:"] + \ + mems[b"Inact_clean:"] + \ + mems[b"Inact_laundry:"] + except KeyError: + inactive = 0 + missing_fields.append('inactive') + + used = total - free - cached - buffers + if used < 0: + # May be symptomatic of running within a LCX container where such + # values will be dramatically distorted over those of the host. + used = total - free + + # - starting from 4.4.0 we match free's "available" column. + # Before 4.4.0 we calculated it as (free + buffers + cached) + # which matched htop. + # - free and htop available memory differs as per: + # http://askubuntu.com/a/369589 + # http://unix.stackexchange.com/a/65852/168884 + # - MemAvailable has been introduced in kernel 3.14 + try: + avail = mems[b'MemAvailable:'] + except KeyError: + avail = calculate_avail_vmem(mems) + + if avail < 0: + avail = 0 + missing_fields.append('available') + + # If avail is greater than total or our calculation overflows, + # that's symptomatic of running within a LCX container where such + # values will be dramatically distorted over those of the host. + # https://gitlab.com/procps-ng/procps/blob/ + # 24fd2605c51fccc375ab0287cec33aa767f06718/proc/sysinfo.c#L764 + if avail > total: + avail = free + + percent = usage_percent((total - avail), total, _round=1) + + # Warn about missing metrics which are set to 0. + if missing_fields: + msg = "%s memory stats couldn't be determined and %s set to 0" % ( + ", ".join(missing_fields), + "was" if len(missing_fields) == 1 else "were") + warnings.warn(msg, RuntimeWarning) + + return svmem(total, avail, percent, used, free, + active, inactive, buffers, cached, shared) + + +def swap_memory(): + """Return swap memory metrics.""" + _, _, _, _, total, free, unit_multiplier = cext.linux_sysinfo() + total *= unit_multiplier + free *= unit_multiplier + used = total - free + percent = usage_percent(used, total, _round=1) + # get pgin/pgouts + try: + f = open_binary("%s/vmstat" % get_procfs_path()) + except IOError as err: + # see https://github.com/giampaolo/psutil/issues/722 + msg = "'sin' and 'sout' swap memory stats couldn't " \ + "be determined and were set to 0 (%s)" % str(err) + warnings.warn(msg, RuntimeWarning) + sin = sout = 0 + else: + with f: + sin = sout = None + for line in f: + # values are expressed in 4 kilo bytes, we want + # bytes instead + if line.startswith(b'pswpin'): + sin = int(line.split(b' ')[1]) * 4 * 1024 + elif line.startswith(b'pswpout'): + sout = int(line.split(b' ')[1]) * 4 * 1024 + if sin is not None and sout is not None: + break + else: + # we might get here when dealing with exotic Linux + # flavors, see: + # https://github.com/giampaolo/psutil/issues/313 + msg = "'sin' and 'sout' swap memory stats couldn't " \ + "be determined and were set to 0" + warnings.warn(msg, RuntimeWarning) + sin = sout = 0 + return _common.sswap(total, used, free, percent, sin, sout) + + +# ===================================================================== +# --- CPU +# ===================================================================== + + +def cpu_times(): + """Return a named tuple representing the following system-wide + CPU times: + (user, nice, system, idle, iowait, irq, softirq [steal, [guest, + [guest_nice]]]) + Last 3 fields may not be available on all Linux kernel versions. + """ + procfs_path = get_procfs_path() + set_scputimes_ntuple(procfs_path) + with open_binary('%s/stat' % procfs_path) as f: + values = f.readline().split() + fields = values[1:len(scputimes._fields) + 1] + fields = [float(x) / CLOCK_TICKS for x in fields] + return scputimes(*fields) + + +def per_cpu_times(): + """Return a list of namedtuple representing the CPU times + for every CPU available on the system. + """ + procfs_path = get_procfs_path() + set_scputimes_ntuple(procfs_path) + cpus = [] + with open_binary('%s/stat' % procfs_path) as f: + # get rid of the first line which refers to system wide CPU stats + f.readline() + for line in f: + if line.startswith(b'cpu'): + values = line.split() + fields = values[1:len(scputimes._fields) + 1] + fields = [float(x) / CLOCK_TICKS for x in fields] + entry = scputimes(*fields) + cpus.append(entry) + return cpus + + +def cpu_count_logical(): + """Return the number of logical CPUs in the system.""" + try: + return os.sysconf("SC_NPROCESSORS_ONLN") + except ValueError: + # as a second fallback we try to parse /proc/cpuinfo + num = 0 + with open_binary('%s/cpuinfo' % get_procfs_path()) as f: + for line in f: + if line.lower().startswith(b'processor'): + num += 1 + + # unknown format (e.g. amrel/sparc architectures), see: + # https://github.com/giampaolo/psutil/issues/200 + # try to parse /proc/stat as a last resort + if num == 0: + search = re.compile('cpu\d') + with open_text('%s/stat' % get_procfs_path()) as f: + for line in f: + line = line.split(' ')[0] + if search.match(line): + num += 1 + + if num == 0: + # mimic os.cpu_count() + return None + return num + + +def cpu_count_physical(): + """Return the number of physical cores in the system.""" + mapping = {} + current_info = {} + with open_binary('%s/cpuinfo' % get_procfs_path()) as f: + for line in f: + line = line.strip().lower() + if not line: + # new section + if (b'physical id' in current_info and + b'cpu cores' in current_info): + mapping[current_info[b'physical id']] = \ + current_info[b'cpu cores'] + current_info = {} + else: + # ongoing section + if (line.startswith(b'physical id') or + line.startswith(b'cpu cores')): + key, value = line.split(b'\t:', 1) + current_info[key] = int(value) + + # mimic os.cpu_count() + return sum(mapping.values()) or None + + +def cpu_stats(): + """Return various CPU stats as a named tuple.""" + with open_binary('%s/stat' % get_procfs_path()) as f: + ctx_switches = None + interrupts = None + soft_interrupts = None + for line in f: + if line.startswith(b'ctxt'): + ctx_switches = int(line.split()[1]) + elif line.startswith(b'intr'): + interrupts = int(line.split()[1]) + elif line.startswith(b'softirq'): + soft_interrupts = int(line.split()[1]) + if ctx_switches is not None and soft_interrupts is not None \ + and interrupts is not None: + break + syscalls = 0 + return _common.scpustats( + ctx_switches, interrupts, soft_interrupts, syscalls) + + +if os.path.exists("/sys/devices/system/cpu/cpufreq"): + + def cpu_freq(): + """Return frequency metrics for all CPUs. + Contrarily to other OSes, Linux updates these values in + real-time. + """ + # scaling_* files seem preferable to cpuinfo_*, see: + # http://unix.stackexchange.com/a/87537/168884 + ret = [] + ls = glob.glob("/sys/devices/system/cpu/cpufreq/policy*") + # Sort the list so that '10' comes after '2'. This should + # ensure the CPU order is consistent with other CPU functions + # having a 'percpu' argument and returning results for multiple + # CPUs (cpu_times(), cpu_percent(), cpu_times_percent()). + ls.sort(key=lambda x: int(os.path.basename(x)[6:])) + for path in ls: + curr = int(cat(os.path.join(path, "scaling_cur_freq"))) / 1000 + max_ = int(cat(os.path.join(path, "scaling_max_freq"))) / 1000 + min_ = int(cat(os.path.join(path, "scaling_min_freq"))) / 1000 + ret.append(_common.scpufreq(curr, min_, max_)) + return ret + + +# ===================================================================== +# --- network +# ===================================================================== + + +net_if_addrs = cext_posix.net_if_addrs + + +class _Ipv6UnsupportedError(Exception): + pass + + +class Connections: + """A wrapper on top of /proc/net/* files, retrieving per-process + and system-wide open connections (TCP, UDP, UNIX) similarly to + "netstat -an". + + Note: in case of UNIX sockets we're only able to determine the + local endpoint/path, not the one it's connected to. + According to [1] it would be possible but not easily. + + [1] http://serverfault.com/a/417946 + """ + + def __init__(self): + tcp4 = ("tcp", socket.AF_INET, socket.SOCK_STREAM) + tcp6 = ("tcp6", socket.AF_INET6, socket.SOCK_STREAM) + udp4 = ("udp", socket.AF_INET, socket.SOCK_DGRAM) + udp6 = ("udp6", socket.AF_INET6, socket.SOCK_DGRAM) + unix = ("unix", socket.AF_UNIX, None) + self.tmap = { + "all": (tcp4, tcp6, udp4, udp6, unix), + "tcp": (tcp4, tcp6), + "tcp4": (tcp4,), + "tcp6": (tcp6,), + "udp": (udp4, udp6), + "udp4": (udp4,), + "udp6": (udp6,), + "unix": (unix,), + "inet": (tcp4, tcp6, udp4, udp6), + "inet4": (tcp4, udp4), + "inet6": (tcp6, udp6), + } + self._procfs_path = None + + def get_proc_inodes(self, pid): + inodes = defaultdict(list) + for fd in os.listdir("%s/%s/fd" % (self._procfs_path, pid)): + try: + inode = readlink("%s/%s/fd/%s" % (self._procfs_path, pid, fd)) + except OSError as err: + # ENOENT == file which is gone in the meantime; + # os.stat('/proc/%s' % self.pid) will be done later + # to force NSP (if it's the case) + if err.errno in (errno.ENOENT, errno.ESRCH): + continue + elif err.errno == errno.EINVAL: + # not a link + continue + else: + raise + else: + if inode.startswith('socket:['): + # the process is using a socket + inode = inode[8:][:-1] + inodes[inode].append((pid, int(fd))) + return inodes + + def get_all_inodes(self): + inodes = {} + for pid in pids(): + try: + inodes.update(self.get_proc_inodes(pid)) + except OSError as err: + # os.listdir() is gonna raise a lot of access denied + # exceptions in case of unprivileged user; that's fine + # as we'll just end up returning a connection with PID + # and fd set to None anyway. + # Both netstat -an and lsof does the same so it's + # unlikely we can do any better. + # ENOENT just means a PID disappeared on us. + if err.errno not in ( + errno.ENOENT, errno.ESRCH, errno.EPERM, errno.EACCES): + raise + return inodes + + @staticmethod + def decode_address(addr, family): + """Accept an "ip:port" address as displayed in /proc/net/* + and convert it into a human readable form, like: + + "0500000A:0016" -> ("10.0.0.5", 22) + "0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521) + + The IP address portion is a little or big endian four-byte + hexadecimal number; that is, the least significant byte is listed + first, so we need to reverse the order of the bytes to convert it + to an IP address. + The port is represented as a two-byte hexadecimal number. + + Reference: + http://linuxdevcenter.com/pub/a/linux/2000/11/16/LinuxAdmin.html + """ + ip, port = addr.split(':') + port = int(port, 16) + # this usually refers to a local socket in listen mode with + # no end-points connected + if not port: + return () + if PY3: + ip = ip.encode('ascii') + if family == socket.AF_INET: + # see: https://github.com/giampaolo/psutil/issues/201 + if LITTLE_ENDIAN: + ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1]) + else: + ip = socket.inet_ntop(family, base64.b16decode(ip)) + else: # IPv6 + # old version - let's keep it, just in case... + # ip = ip.decode('hex') + # return socket.inet_ntop(socket.AF_INET6, + # ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4))) + ip = base64.b16decode(ip) + try: + # see: https://github.com/giampaolo/psutil/issues/201 + if LITTLE_ENDIAN: + ip = socket.inet_ntop( + socket.AF_INET6, + struct.pack('>4I', *struct.unpack('<4I', ip))) + else: + ip = socket.inet_ntop( + socket.AF_INET6, + struct.pack('<4I', *struct.unpack('<4I', ip))) + except ValueError: + # see: https://github.com/giampaolo/psutil/issues/623 + if not supports_ipv6(): + raise _Ipv6UnsupportedError + else: + raise + return (ip, port) + + @staticmethod + def process_inet(file, family, type_, inodes, filter_pid=None): + """Parse /proc/net/tcp* and /proc/net/udp* files.""" + if file.endswith('6') and not os.path.exists(file): + # IPv6 not supported + return + with open_text(file, buffering=BIGGER_FILE_BUFFERING) as f: + f.readline() # skip the first line + for lineno, line in enumerate(f, 1): + try: + _, laddr, raddr, status, _, _, _, _, _, inode = \ + line.split()[:10] + except ValueError: + raise RuntimeError( + "error while parsing %s; malformed line %s %r" % ( + file, lineno, line)) + if inode in inodes: + # # We assume inet sockets are unique, so we error + # # out if there are multiple references to the + # # same inode. We won't do this for UNIX sockets. + # if len(inodes[inode]) > 1 and family != socket.AF_UNIX: + # raise ValueError("ambiguos inode with multiple " + # "PIDs references") + pid, fd = inodes[inode][0] + else: + pid, fd = None, -1 + if filter_pid is not None and filter_pid != pid: + continue + else: + if type_ == socket.SOCK_STREAM: + status = TCP_STATUSES[status] + else: + status = _common.CONN_NONE + try: + laddr = Connections.decode_address(laddr, family) + raddr = Connections.decode_address(raddr, family) + except _Ipv6UnsupportedError: + continue + yield (fd, family, type_, laddr, raddr, status, pid) + + @staticmethod + def process_unix(file, family, inodes, filter_pid=None): + """Parse /proc/net/unix files.""" + with open_text(file, buffering=BIGGER_FILE_BUFFERING) as f: + f.readline() # skip the first line + for line in f: + tokens = line.split() + try: + _, _, _, _, type_, _, inode = tokens[0:7] + except ValueError: + if ' ' not in line: + # see: https://github.com/giampaolo/psutil/issues/766 + continue + raise RuntimeError( + "error while parsing %s; malformed line %r" % ( + file, line)) + if inode in inodes: + # With UNIX sockets we can have a single inode + # referencing many file descriptors. + pairs = inodes[inode] + else: + pairs = [(None, -1)] + for pid, fd in pairs: + if filter_pid is not None and filter_pid != pid: + continue + else: + if len(tokens) == 8: + path = tokens[-1] + else: + path = "" + type_ = int(type_) + raddr = None + status = _common.CONN_NONE + yield (fd, family, type_, path, raddr, status, pid) + + def retrieve(self, kind, pid=None): + if kind not in self.tmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in self.tmap]))) + self._procfs_path = get_procfs_path() + if pid is not None: + inodes = self.get_proc_inodes(pid) + if not inodes: + # no connections for this process + return [] + else: + inodes = self.get_all_inodes() + ret = set() + for f, family, type_ in self.tmap[kind]: + if family in (socket.AF_INET, socket.AF_INET6): + ls = self.process_inet( + "%s/net/%s" % (self._procfs_path, f), + family, type_, inodes, filter_pid=pid) + else: + ls = self.process_unix( + "%s/net/%s" % (self._procfs_path, f), + family, inodes, filter_pid=pid) + for fd, family, type_, laddr, raddr, status, bound_pid in ls: + if pid: + conn = _common.pconn(fd, family, type_, laddr, raddr, + status) + else: + conn = _common.sconn(fd, family, type_, laddr, raddr, + status, bound_pid) + ret.add(conn) + return list(ret) + + +_connections = Connections() + + +def net_connections(kind='inet'): + """Return system-wide open connections.""" + return _connections.retrieve(kind) + + +def net_io_counters(): + """Return network I/O statistics for every network interface + installed on the system as a dict of raw tuples. + """ + with open_text("%s/net/dev" % get_procfs_path()) as f: + lines = f.readlines() + retdict = {} + for line in lines[2:]: + colon = line.rfind(':') + assert colon > 0, repr(line) + name = line[:colon].strip() + fields = line[colon + 1:].strip().split() + + # in + (bytes_recv, + packets_recv, + errin, + dropin, + fifoin, # unused + framein, # unused + compressedin, # unused + multicastin, # unused + # out + bytes_sent, + packets_sent, + errout, + dropout, + fifoout, # unused + collisionsout, # unused + carrierout, # unused + compressedout) = map(int, fields) + + retdict[name] = (bytes_sent, bytes_recv, packets_sent, packets_recv, + errin, errout, dropin, dropout) + return retdict + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + duplex_map = {cext.DUPLEX_FULL: NIC_DUPLEX_FULL, + cext.DUPLEX_HALF: NIC_DUPLEX_HALF, + cext.DUPLEX_UNKNOWN: NIC_DUPLEX_UNKNOWN} + names = net_io_counters().keys() + ret = {} + for name in names: + mtu = cext_posix.net_if_mtu(name) + isup = cext_posix.net_if_flags(name) + duplex, speed = cext.net_if_duplex_speed(name) + ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu) + return ret + + +# ===================================================================== +# --- disks +# ===================================================================== + + +disk_usage = _psposix.disk_usage + + +def disk_io_counters(): + """Return disk I/O statistics for every disk installed on the + system as a dict of raw tuples. + """ + # determine partitions we want to look for + def get_partitions(): + partitions = [] + with open_text("%s/partitions" % get_procfs_path()) as f: + lines = f.readlines()[2:] + for line in reversed(lines): + _, _, _, name = line.split() + if name[-1].isdigit(): + # we're dealing with a partition (e.g. 'sda1'); 'sda' will + # also be around but we want to omit it + partitions.append(name) + else: + if not partitions or not partitions[-1].startswith(name): + # we're dealing with a disk entity for which no + # partitions have been defined (e.g. 'sda' but + # 'sda1' was not around), see: + # https://github.com/giampaolo/psutil/issues/338 + partitions.append(name) + return partitions + + retdict = {} + partitions = get_partitions() + with open_text("%s/diskstats" % get_procfs_path()) as f: + lines = f.readlines() + for line in lines: + # OK, this is a bit confusing. The format of /proc/diskstats can + # have 3 variations. + # On Linux 2.4 each line has always 15 fields, e.g.: + # "3 0 8 hda 8 8 8 8 8 8 8 8 8 8 8" + # On Linux 2.6+ each line *usually* has 14 fields, and the disk + # name is in another position, like this: + # "3 0 hda 8 8 8 8 8 8 8 8 8 8 8" + # ...unless (Linux 2.6) the line refers to a partition instead + # of a disk, in which case the line has less fields (7): + # "3 1 hda1 8 8 8 8" + # See: + # https://www.kernel.org/doc/Documentation/iostats.txt + # https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats + fields = line.split() + fields_len = len(fields) + if fields_len == 15: + # Linux 2.4 + name = fields[3] + reads = int(fields[2]) + (reads_merged, rbytes, rtime, writes, writes_merged, + wbytes, wtime, _, busy_time, _) = map(int, fields[4:14]) + elif fields_len == 14: + # Linux 2.6+, line referring to a disk + name = fields[2] + (reads, reads_merged, rbytes, rtime, writes, writes_merged, + wbytes, wtime, _, busy_time, _) = map(int, fields[3:14]) + elif fields_len == 7: + # Linux 2.6+, line referring to a partition + name = fields[2] + reads, rbytes, writes, wbytes = map(int, fields[3:]) + rtime = wtime = reads_merged = writes_merged = busy_time = 0 + else: + raise ValueError("not sure how to interpret line %r" % line) + + if name in partitions: + sector_size = get_sector_size(name) + rbytes = rbytes * sector_size + wbytes = wbytes * sector_size + retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime, + reads_merged, writes_merged, busy_time) + return retdict + + +def disk_partitions(all=False): + """Return mounted disk partitions as a list of namedtuples.""" + fstypes = set() + with open_text("%s/filesystems" % get_procfs_path()) as f: + for line in f: + line = line.strip() + if not line.startswith("nodev"): + fstypes.add(line.strip()) + else: + # ignore all lines starting with "nodev" except "nodev zfs" + fstype = line.split("\t")[1] + if fstype == "zfs": + fstypes.add("zfs") + + retlist = [] + partitions = cext.disk_partitions() + for partition in partitions: + device, mountpoint, fstype, opts = partition + if device == 'none': + device = '' + if not all: + if device == '' or fstype not in fstypes: + continue + ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) + retlist.append(ntuple) + return retlist + + +# ===================================================================== +# --- sensors +# ===================================================================== + + +def sensors_temperatures(): + """Return hardware (CPU and others) temperatures as a dict + including hardware name, label, current, max and critical + temperatures. + + Implementation notes: + - /sys/class/hwmon looks like the most recent interface to + retrieve this info, and this implementation relies on it + only (old distros will probably use something else) + - lm-sensors on Ubuntu 16.04 relies on /sys/class/hwmon + - /sys/class/thermal/thermal_zone* is another one but it's more + difficult to parse + """ + ret = collections.defaultdict(list) + basenames = glob.glob('/sys/class/hwmon/hwmon*/temp*_*') + if not basenames: + # CentOS has an intermediate /device directory: + # https://github.com/giampaolo/psutil/issues/971 + basenames = glob.glob('/sys/class/hwmon/hwmon*/device/temp*_*') + + basenames = sorted(set([x.split('_')[0] for x in basenames])) + for base in basenames: + unit_name = cat(os.path.join(os.path.dirname(base), 'name'), + binary=False) + label = cat(base + '_label', fallback='', binary=False) + current = float(cat(base + '_input')) / 1000.0 + high = cat(base + '_max', fallback=None) + critical = cat(base + '_crit', fallback=None) + + if high is not None: + high = float(high) / 1000.0 + if critical is not None: + critical = float(critical) / 1000.0 + + ret[unit_name].append((label, current, high, critical)) + + return ret + + +def sensors_fans(): + """Return hardware (CPU and others) fans as a dict + including hardware label, current speed. + + Implementation notes: + - /sys/class/hwmon looks like the most recent interface to + retrieve this info, and this implementation relies on it + only (old distros will probably use something else) + - lm-sensors on Ubuntu 16.04 relies on /sys/class/hwmon + """ + ret = collections.defaultdict(list) + basenames = glob.glob('/sys/class/hwmon/hwmon*/fan*_*') + if not basenames: + # CentOS has an intermediate /device directory: + # https://github.com/giampaolo/psutil/issues/971 + basenames = glob.glob('/sys/class/hwmon/hwmon*/device/fan*_*') + + basenames = sorted(set([x.split('_')[0] for x in basenames])) + for base in basenames: + unit_name = cat(os.path.join(os.path.dirname(base), 'name'), + binary=False) + label = cat(base + '_label', fallback='', binary=False) + current = int(cat(base + '_input')) + + ret[unit_name].append(_common.sfan(label, current)) + + return dict(ret) + + +def sensors_battery(): + """Return battery information. + Implementation note: it appears /sys/class/power_supply/BAT0/ + directory structure may vary and provide files with the same + meaning but under different names, see: + https://github.com/giampaolo/psutil/issues/966 + """ + null = object() + + def multi_cat(*paths): + """Attempt to read the content of multiple files which may + not exist. If none of them exist return None. + """ + for path in paths: + ret = cat(path, fallback=null) + if ret != null: + return int(ret) if ret.isdigit() else ret + return None + + root = os.path.join(POWER_SUPPLY_PATH, "BAT0") + if not os.path.exists(root): + return None + + # Base metrics. + energy_now = multi_cat( + root + "/energy_now", + root + "/charge_now") + power_now = multi_cat( + root + "/power_now", + root + "/current_now") + energy_full = multi_cat( + root + "/energy_full", + root + "/charge_full") + if energy_now is None or power_now is None: + return None + + # Percent. If we have energy_full the percentage will be more + # accurate compared to reading /capacity file (float vs. int). + if energy_full is not None: + try: + percent = 100.0 * energy_now / energy_full + except ZeroDivisionError: + percent = 0.0 + else: + percent = int(cat(root + "/capacity", fallback=-1)) + if percent == -1: + return None + + # Is AC power cable plugged in? + # Note: AC0 is not always available and sometimes (e.g. CentOS7) + # it's called "AC". + power_plugged = None + online = multi_cat( + os.path.join(POWER_SUPPLY_PATH, "AC0/online"), + os.path.join(POWER_SUPPLY_PATH, "AC/online")) + if online is not None: + power_plugged = online == 1 + else: + status = cat(root + "/status", fallback="", binary=False).lower() + if status == "discharging": + power_plugged = False + elif status in ("charging", "full"): + power_plugged = True + + # Seconds left. + # Note to self: we may also calculate the charging ETA as per: + # https://github.com/thialfihar/dotfiles/blob/ + # 013937745fd9050c30146290e8f963d65c0179e6/bin/battery.py#L55 + if power_plugged: + secsleft = _common.POWER_TIME_UNLIMITED + else: + try: + secsleft = int(energy_now / power_now * 3600) + except ZeroDivisionError: + secsleft = _common.POWER_TIME_UNKNOWN + + return _common.sbattery(percent, secsleft, power_plugged) + + +# ===================================================================== +# --- other system functions +# ===================================================================== + + +def users(): + """Return currently connected users as a list of namedtuples.""" + retlist = [] + rawlist = cext.users() + for item in rawlist: + user, tty, hostname, tstamp, user_process = item + # note: the underlying C function includes entries about + # system boot, run level and others. We might want + # to use them in the future. + if not user_process: + continue + if hostname == ':0.0' or hostname == ':0': + hostname = 'localhost' + nt = _common.suser(user, tty or None, hostname, tstamp) + retlist.append(nt) + return retlist + + +def boot_time(): + """Return the system boot time expressed in seconds since the epoch.""" + global BOOT_TIME + with open_binary('%s/stat' % get_procfs_path()) as f: + for line in f: + if line.startswith(b'btime'): + ret = float(line.strip().split()[1]) + BOOT_TIME = ret + return ret + raise RuntimeError( + "line 'btime' not found in %s/stat" % get_procfs_path()) + + +# ===================================================================== +# --- processes +# ===================================================================== + + +def pids(): + """Returns a list of PIDs currently running on the system.""" + return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] + + +def pid_exists(pid): + """Check for the existence of a unix PID.""" + if not _psposix.pid_exists(pid): + return False + else: + # Linux's apparently does not distinguish between PIDs and TIDs + # (thread IDs). + # listdir("/proc") won't show any TID (only PIDs) but + # os.stat("/proc/{tid}") will succeed if {tid} exists. + # os.kill() can also be passed a TID. This is quite confusing. + # In here we want to enforce this distinction and support PIDs + # only, see: + # https://github.com/giampaolo/psutil/issues/687 + try: + # Note: already checked that this is faster than using a + # regular expr. Also (a lot) faster than doing + # 'return pid in pids()' + with open_binary("%s/%s/status" % (get_procfs_path(), pid)) as f: + for line in f: + if line.startswith(b"Tgid:"): + tgid = int(line.split()[1]) + # If tgid and pid are the same then we're + # dealing with a process PID. + return tgid == pid + raise ValueError("'Tgid' line not found") + except (EnvironmentError, ValueError): + return pid in pids() + + +def wrap_exceptions(fun): + """Decorator which translates bare OSError and IOError exceptions + into NoSuchProcess and AccessDenied. + """ + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except EnvironmentError as err: + # ENOENT (no such file or directory) gets raised on open(). + # ESRCH (no such process) can get raised on read() if + # process is gone in meantime. + if err.errno in (errno.ENOENT, errno.ESRCH): + raise NoSuchProcess(self.pid, self._name) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + return wrapper + + +class Process(object): + """Linux process implementation.""" + + __slots__ = ["pid", "_name", "_ppid", "_procfs_path"] + + def __init__(self, pid): + self.pid = pid + self._name = None + self._ppid = None + self._procfs_path = get_procfs_path() + + @memoize_when_activated + def _parse_stat_file(self): + """Parse /proc/{pid}/stat file. Return a list of fields where + process name is in position 0. + Using "man proc" as a reference: where "man proc" refers to + position N, always substract 2 (e.g starttime pos 22 in + 'man proc' == pos 20 in the list returned here). + + The return value is cached in case oneshot() ctx manager is + in use. + """ + with open_binary("%s/%s/stat" % (self._procfs_path, self.pid)) as f: + data = f.read() + # Process name is between parentheses. It can contain spaces and + # other parentheses. This is taken into account by looking for + # the first occurrence of "(" and the last occurence of ")". + rpar = data.rfind(b')') + name = data[data.find(b'(') + 1:rpar] + fields_after_name = data[rpar + 2:].split() + return [name] + fields_after_name + + @memoize_when_activated + def _read_status_file(self): + """Read /proc/{pid}/stat file and return its content. + + The return value is cached in case oneshot() ctx manager is + in use. + """ + with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: + return f.read() + + @memoize_when_activated + def _read_smaps_file(self): + with open_binary("%s/%s/smaps" % (self._procfs_path, self.pid), + buffering=BIGGER_FILE_BUFFERING) as f: + return f.read().strip() + + def oneshot_enter(self): + self._parse_stat_file.cache_activate() + self._read_status_file.cache_activate() + self._read_smaps_file.cache_activate() + + def oneshot_exit(self): + self._parse_stat_file.cache_deactivate() + self._read_status_file.cache_deactivate() + self._read_smaps_file.cache_deactivate() + + @wrap_exceptions + def name(self): + name = self._parse_stat_file()[0] + if PY3: + name = decode(name) + # XXX - gets changed later and probably needs refactoring + return name + + def exe(self): + try: + return readlink("%s/%s/exe" % (self._procfs_path, self.pid)) + except OSError as err: + if err.errno in (errno.ENOENT, errno.ESRCH): + # no such file error; might be raised also if the + # path actually exists for system processes with + # low pids (about 0-20) + if os.path.lexists("%s/%s" % (self._procfs_path, self.pid)): + return "" + else: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + + @wrap_exceptions + def cmdline(self): + with open_text("%s/%s/cmdline" % (self._procfs_path, self.pid)) as f: + data = f.read() + if not data: + # may happen in case of zombie process + return [] + if data.endswith('\x00'): + data = data[:-1] + return [x for x in data.split('\x00')] + + @wrap_exceptions + def environ(self): + with open_text("%s/%s/environ" % (self._procfs_path, self.pid)) as f: + data = f.read() + return parse_environ_block(data) + + @wrap_exceptions + def terminal(self): + tty_nr = int(self._parse_stat_file()[5]) + tmap = _psposix.get_terminal_map() + try: + return tmap[tty_nr] + except KeyError: + return None + + if os.path.exists('/proc/%s/io' % os.getpid()): + @wrap_exceptions + def io_counters(self): + fname = "%s/%s/io" % (self._procfs_path, self.pid) + fields = {} + with open_binary(fname) as f: + for line in f: + name, value = line.split(b': ') + fields[name] = int(value) + return pio( + fields[b'syscr'], # read syscalls + fields[b'syscw'], # write syscalls + fields[b'read_bytes'], # read bytes + fields[b'write_bytes'], # write bytes + fields[b'rchar'], # read chars + fields[b'wchar'], # write chars + ) + else: + def io_counters(self): + raise NotImplementedError("couldn't find /proc/%s/io (kernel " + "too old?)" % self.pid) + + @wrap_exceptions + def cpu_times(self): + values = self._parse_stat_file() + utime = float(values[12]) / CLOCK_TICKS + stime = float(values[13]) / CLOCK_TICKS + children_utime = float(values[14]) / CLOCK_TICKS + children_stime = float(values[15]) / CLOCK_TICKS + return _common.pcputimes(utime, stime, children_utime, children_stime) + + @wrap_exceptions + def cpu_num(self): + """What CPU the process is on.""" + return int(self._parse_stat_file()[37]) + + @wrap_exceptions + def wait(self, timeout=None): + try: + return _psposix.wait_pid(self.pid, timeout) + except _psposix.TimeoutExpired: + raise TimeoutExpired(timeout, self.pid, self._name) + + @wrap_exceptions + def create_time(self): + values = self._parse_stat_file() + # According to documentation, starttime is in field 21 and the + # unit is jiffies (clock ticks). + # We first divide it for clock ticks and then add uptime returning + # seconds since the epoch, in UTC. + # Also use cached value if available. + bt = BOOT_TIME or boot_time() + return (float(values[20]) / CLOCK_TICKS) + bt + + @wrap_exceptions + def memory_info(self): + # ============================================================ + # | FIELD | DESCRIPTION | AKA | TOP | + # ============================================================ + # | rss | resident set size | | RES | + # | vms | total program size | size | VIRT | + # | shared | shared pages (from shared mappings) | | SHR | + # | text | text ('code') | trs | CODE | + # | lib | library (unused in Linux 2.6) | lrs | | + # | data | data + stack | drs | DATA | + # | dirty | dirty pages (unused in Linux 2.6) | dt | | + # ============================================================ + with open_binary("%s/%s/statm" % (self._procfs_path, self.pid)) as f: + vms, rss, shared, text, lib, data, dirty = \ + [int(x) * PAGESIZE for x in f.readline().split()[:7]] + return pmem(rss, vms, shared, text, lib, data, dirty) + + # /proc/pid/smaps does not exist on kernels < 2.6.14 or if + # CONFIG_MMU kernel configuration option is not enabled. + if HAS_SMAPS: + + @wrap_exceptions + def memory_full_info( + self, + _private_re=re.compile(b"Private.*:\s+(\d+)"), + _pss_re=re.compile(b"Pss.*:\s+(\d+)"), + _swap_re=re.compile(b"Swap.*:\s+(\d+)")): + basic_mem = self.memory_info() + # Note: using 3 regexes is faster than reading the file + # line by line. + # XXX: on Python 3 the 2 regexes are 30% slower than on + # Python 2 though. Figure out why. + # + # You might be tempted to calculate USS by subtracting + # the "shared" value from the "resident" value in + # /proc//statm. But at least on Linux, statm's "shared" + # value actually counts pages backed by files, which has + # little to do with whether the pages are actually shared. + # /proc/self/smaps on the other hand appears to give us the + # correct information. + smaps_data = self._read_smaps_file() + # Note: smaps file can be empty for certain processes. + # The code below will not crash though and will result to 0. + uss = sum(map(int, _private_re.findall(smaps_data))) * 1024 + pss = sum(map(int, _pss_re.findall(smaps_data))) * 1024 + swap = sum(map(int, _swap_re.findall(smaps_data))) * 1024 + return pfullmem(*basic_mem + (uss, pss, swap)) + + else: + memory_full_info = memory_info + + if HAS_SMAPS: + + @wrap_exceptions + def memory_maps(self): + """Return process's mapped memory regions as a list of named + tuples. Fields are explained in 'man proc'; here is an updated + (Apr 2012) version: http://goo.gl/fmebo + """ + def get_blocks(lines, current_block): + data = {} + for line in lines: + fields = line.split(None, 5) + if not fields[0].endswith(b':'): + # new block section + yield (current_block.pop(), data) + current_block.append(line) + else: + try: + data[fields[0]] = int(fields[1]) * 1024 + except ValueError: + if fields[0].startswith(b'VmFlags:'): + # see issue #369 + continue + else: + raise ValueError("don't know how to inte" + "rpret line %r" % line) + yield (current_block.pop(), data) + + data = self._read_smaps_file() + # Note: smaps file can be empty for certain processes. + if not data: + return [] + lines = data.split(b'\n') + ls = [] + first_line = lines.pop(0) + current_block = [first_line] + for header, data in get_blocks(lines, current_block): + hfields = header.split(None, 5) + try: + addr, perms, offset, dev, inode, path = hfields + except ValueError: + addr, perms, offset, dev, inode, path = \ + hfields + [''] + if not path: + path = '[anon]' + else: + if PY3: + path = decode(path) + path = path.strip() + if (path.endswith(' (deleted)') and not + path_exists_strict(path)): + path = path[:-10] + ls.append(( + decode(addr), decode(perms), path, + data[b'Rss:'], + data.get(b'Size:', 0), + data.get(b'Pss:', 0), + data.get(b'Shared_Clean:', 0), + data.get(b'Shared_Dirty:', 0), + data.get(b'Private_Clean:', 0), + data.get(b'Private_Dirty:', 0), + data.get(b'Referenced:', 0), + data.get(b'Anonymous:', 0), + data.get(b'Swap:', 0) + )) + return ls + + else: + def memory_maps(self): + raise NotImplementedError( + "/proc/%s/smaps does not exist on kernels < 2.6.14 or " + "if CONFIG_MMU kernel configuration option is not " + "enabled." % self.pid) + + @wrap_exceptions + def cwd(self): + try: + return readlink("%s/%s/cwd" % (self._procfs_path, self.pid)) + except OSError as err: + # https://github.com/giampaolo/psutil/issues/986 + if err.errno in (errno.ENOENT, errno.ESRCH): + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + raise + + @wrap_exceptions + def num_ctx_switches(self, _ctxsw_re=re.compile(b'ctxt_switches:\t(\d+)')): + data = self._read_status_file() + ctxsw = _ctxsw_re.findall(data) + if not ctxsw: + raise NotImplementedError( + "'voluntary_ctxt_switches' and 'nonvoluntary_ctxt_switches'" + "lines were not found in %s/%s/status; the kernel is " + "probably older than 2.6.23" % ( + self._procfs_path, self.self.pid)) + else: + return _common.pctxsw(int(ctxsw[0]), int(ctxsw[1])) + + @wrap_exceptions + def num_threads(self, _num_threads_re=re.compile(b'Threads:\t(\d+)')): + # Note: on Python 3 using a re is faster than iterating over file + # line by line. On Python 2 is the exact opposite, and iterating + # over a file on Python 3 is slower than on Python 2. + data = self._read_status_file() + return int(_num_threads_re.findall(data)[0]) + + @wrap_exceptions + def threads(self): + thread_ids = os.listdir("%s/%s/task" % (self._procfs_path, self.pid)) + thread_ids.sort() + retlist = [] + hit_enoent = False + for thread_id in thread_ids: + fname = "%s/%s/task/%s/stat" % ( + self._procfs_path, self.pid, thread_id) + try: + with open_binary(fname) as f: + st = f.read().strip() + except IOError as err: + if err.errno == errno.ENOENT: + # no such file or directory; it means thread + # disappeared on us + hit_enoent = True + continue + raise + # ignore the first two values ("pid (exe)") + st = st[st.find(b')') + 2:] + values = st.split(b' ') + utime = float(values[11]) / CLOCK_TICKS + stime = float(values[12]) / CLOCK_TICKS + ntuple = _common.pthread(int(thread_id), utime, stime) + retlist.append(ntuple) + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (self._procfs_path, self.pid)) + return retlist + + @wrap_exceptions + def nice_get(self): + # with open_text('%s/%s/stat' % (self._procfs_path, self.pid)) as f: + # data = f.read() + # return int(data.split()[18]) + + # Use C implementation + return cext_posix.getpriority(self.pid) + + @wrap_exceptions + def nice_set(self, value): + return cext_posix.setpriority(self.pid, value) + + @wrap_exceptions + def cpu_affinity_get(self): + return cext.proc_cpu_affinity_get(self.pid) + + def _get_eligible_cpus( + self, _re=re.compile(b"Cpus_allowed_list:\t(\d+)-(\d+)")): + # See: https://github.com/giampaolo/psutil/issues/956 + data = self._read_status_file() + match = _re.findall(data) + if match: + return list(range(int(match[0][0]), int(match[0][1]) + 1)) + else: + return list(range(len(per_cpu_times()))) + + @wrap_exceptions + def cpu_affinity_set(self, cpus): + try: + cext.proc_cpu_affinity_set(self.pid, cpus) + except (OSError, ValueError) as err: + if isinstance(err, ValueError) or err.errno == errno.EINVAL: + eligible_cpus = self._get_eligible_cpus() + all_cpus = tuple(range(len(per_cpu_times()))) + for cpu in cpus: + if cpu not in all_cpus: + raise ValueError( + "invalid CPU number %r; choose between %s" % ( + cpu, eligible_cpus)) + if cpu not in eligible_cpus: + raise ValueError( + "CPU number %r is not eligible; choose " + "between %s" % (cpu, eligible_cpus)) + raise + + # only starting from kernel 2.6.13 + if hasattr(cext, "proc_ioprio_get"): + + @wrap_exceptions + def ionice_get(self): + ioclass, value = cext.proc_ioprio_get(self.pid) + if enum is not None: + ioclass = IOPriority(ioclass) + return _common.pionice(ioclass, value) + + @wrap_exceptions + def ionice_set(self, ioclass, value): + if value is not None: + if not PY3 and not isinstance(value, (int, long)): + msg = "value argument is not an integer (gor %r)" % value + raise TypeError(msg) + if not 0 <= value <= 7: + raise ValueError( + "value argument range expected is between 0 and 7") + + if ioclass in (IOPRIO_CLASS_NONE, None): + if value: + msg = "can't specify value with IOPRIO_CLASS_NONE " \ + "(got %r)" % value + raise ValueError(msg) + ioclass = IOPRIO_CLASS_NONE + value = 0 + elif ioclass == IOPRIO_CLASS_IDLE: + if value: + msg = "can't specify value with IOPRIO_CLASS_IDLE " \ + "(got %r)" % value + raise ValueError(msg) + value = 0 + elif ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): + if value is None: + # TODO: add comment explaining why this is 4 (?) + value = 4 + else: + # otherwise we would get OSError(EVINAL) + raise ValueError("invalid ioclass argument %r" % ioclass) + + return cext.proc_ioprio_set(self.pid, ioclass, value) + + if HAS_PRLIMIT: + @wrap_exceptions + def rlimit(self, resource, limits=None): + # If pid is 0 prlimit() applies to the calling process and + # we don't want that. We should never get here though as + # PID 0 is not supported on Linux. + if self.pid == 0: + raise ValueError("can't use prlimit() against PID 0 process") + try: + if limits is None: + # get + return cext.linux_prlimit(self.pid, resource) + else: + # set + if len(limits) != 2: + raise ValueError( + "second argument must be a (soft, hard) tuple, " + "got %s" % repr(limits)) + soft, hard = limits + cext.linux_prlimit(self.pid, resource, soft, hard) + except OSError as err: + if err.errno == errno.ENOSYS and pid_exists(self.pid): + # I saw this happening on Travis: + # https://travis-ci.org/giampaolo/psutil/jobs/51368273 + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise + + @wrap_exceptions + def status(self): + letter = self._parse_stat_file()[1] + if PY3: + letter = letter.decode() + # XXX is '?' legit? (we're not supposed to return it anyway) + return PROC_STATUSES.get(letter, '?') + + @wrap_exceptions + def open_files(self): + retlist = [] + files = os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)) + hit_enoent = False + for fd in files: + file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd) + try: + path = readlink(file) + except OSError as err: + # ENOENT == file which is gone in the meantime + if err.errno in (errno.ENOENT, errno.ESRCH): + hit_enoent = True + continue + elif err.errno == errno.EINVAL: + # not a link + continue + else: + raise + else: + # If path is not an absolute there's no way to tell + # whether it's a regular file or not, so we skip it. + # A regular file is always supposed to be have an + # absolute path though. + if path.startswith('/') and isfile_strict(path): + # Get file position and flags. + file = "%s/%s/fdinfo/%s" % ( + self._procfs_path, self.pid, fd) + with open_binary(file) as f: + pos = int(f.readline().split()[1]) + flags = int(f.readline().split()[1], 8) + mode = file_flags_to_mode(flags) + ntuple = popenfile(path, int(fd), int(pos), mode, flags) + retlist.append(ntuple) + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (self._procfs_path, self.pid)) + return retlist + + @wrap_exceptions + def connections(self, kind='inet'): + ret = _connections.retrieve(kind, self.pid) + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (self._procfs_path, self.pid)) + return ret + + @wrap_exceptions + def num_fds(self): + return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) + + @wrap_exceptions + def ppid(self): + return int(self._parse_stat_file()[2]) + + @wrap_exceptions + def uids(self, _uids_re=re.compile(b'Uid:\t(\d+)\t(\d+)\t(\d+)')): + data = self._read_status_file() + real, effective, saved = _uids_re.findall(data)[0] + return _common.puids(int(real), int(effective), int(saved)) + + @wrap_exceptions + def gids(self, _gids_re=re.compile(b'Gid:\t(\d+)\t(\d+)\t(\d+)')): + data = self._read_status_file() + real, effective, saved = _gids_re.findall(data)[0] + return _common.pgids(int(real), int(effective), int(saved)) diff --git a/pipenv/vendor/psutil/_psosx.py b/pipenv/vendor/psutil/_psosx.py new file mode 100644 index 00000000..f780d459 --- /dev/null +++ b/pipenv/vendor/psutil/_psosx.py @@ -0,0 +1,506 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""OSX platform implementation.""" + +import errno +import functools +import os +from collections import namedtuple + +from . import _common +from . import _psposix +from . import _psutil_osx as cext +from . import _psutil_posix as cext_posix +from ._common import conn_tmap +from ._common import isfile_strict +from ._common import memoize_when_activated +from ._common import parse_environ_block +from ._common import sockfam_to_enum +from ._common import socktype_to_enum +from ._common import usage_percent + + +__extra__all__ = [] + + +# ===================================================================== +# --- globals +# ===================================================================== + + +PAGESIZE = os.sysconf("SC_PAGE_SIZE") +AF_LINK = cext_posix.AF_LINK + +# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h +TCP_STATUSES = { + cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, + cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, + cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV, + cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, + cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, + cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, + cext.TCPS_CLOSED: _common.CONN_CLOSE, + cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, + cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, + cext.TCPS_LISTEN: _common.CONN_LISTEN, + cext.TCPS_CLOSING: _common.CONN_CLOSING, + cext.PSUTIL_CONN_NONE: _common.CONN_NONE, +} + +PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SRUN: _common.STATUS_RUNNING, + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SSTOP: _common.STATUS_STOPPED, + cext.SZOMB: _common.STATUS_ZOMBIE, +} + +kinfo_proc_map = dict( + ppid=0, + ruid=1, + euid=2, + suid=3, + rgid=4, + egid=5, + sgid=6, + ttynr=7, + ctime=8, + status=9, + name=10, +) + +pidtaskinfo_map = dict( + cpuutime=0, + cpustime=1, + rss=2, + vms=3, + pfaults=4, + pageins=5, + numthreads=6, + volctxsw=7, +) + +# these get overwritten on "import psutil" from the __init__.py file +NoSuchProcess = None +ZombieProcess = None +AccessDenied = None +TimeoutExpired = None + + +# ===================================================================== +# --- named tuples +# ===================================================================== + + +# psutil.cpu_times() +scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle']) +# psutil.virtual_memory() +svmem = namedtuple( + 'svmem', ['total', 'available', 'percent', 'used', 'free', + 'active', 'inactive', 'wired']) +# psutil.Process.memory_info() +pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins']) +# psutil.Process.memory_full_info() +pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', )) +# psutil.Process.memory_maps(grouped=True) +pmmap_grouped = namedtuple( + 'pmmap_grouped', + 'path rss private swapped dirtied ref_count shadow_depth') +# psutil.Process.memory_maps(grouped=False) +pmmap_ext = namedtuple( + 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) + + +# ===================================================================== +# --- memory +# ===================================================================== + + +def virtual_memory(): + """System virtual memory as a namedtuple.""" + total, active, inactive, wired, free = cext.virtual_mem() + avail = inactive + free + used = active + inactive + wired + percent = usage_percent((total - avail), total, _round=1) + return svmem(total, avail, percent, used, free, + active, inactive, wired) + + +def swap_memory(): + """Swap system memory as a (total, used, free, sin, sout) tuple.""" + total, used, free, sin, sout = cext.swap_mem() + percent = usage_percent(used, total, _round=1) + return _common.sswap(total, used, free, percent, sin, sout) + + +# ===================================================================== +# --- CPU +# ===================================================================== + + +def cpu_times(): + """Return system CPU times as a namedtuple.""" + user, nice, system, idle = cext.cpu_times() + return scputimes(user, nice, system, idle) + + +def per_cpu_times(): + """Return system CPU times as a named tuple""" + ret = [] + for cpu_t in cext.per_cpu_times(): + user, nice, system, idle = cpu_t + item = scputimes(user, nice, system, idle) + ret.append(item) + return ret + + +def cpu_count_logical(): + """Return the number of logical CPUs in the system.""" + return cext.cpu_count_logical() + + +def cpu_count_physical(): + """Return the number of physical CPUs in the system.""" + return cext.cpu_count_phys() + + +def cpu_stats(): + ctx_switches, interrupts, soft_interrupts, syscalls, traps = \ + cext.cpu_stats() + return _common.scpustats( + ctx_switches, interrupts, soft_interrupts, syscalls) + + +def cpu_freq(): + """Return CPU frequency. + On OSX per-cpu frequency is not supported. + Also, the returned frequency never changes, see: + https://arstechnica.com/civis/viewtopic.php?f=19&t=465002 + """ + curr, min_, max_ = cext.cpu_freq() + return [_common.scpufreq(curr, min_, max_)] + + +# ===================================================================== +# --- disks +# ===================================================================== + + +disk_usage = _psposix.disk_usage +disk_io_counters = cext.disk_io_counters + + +def disk_partitions(all=False): + """Return mounted disk partitions as a list of namedtuples.""" + retlist = [] + partitions = cext.disk_partitions() + for partition in partitions: + device, mountpoint, fstype, opts = partition + if device == 'none': + device = '' + if not all: + if not os.path.isabs(device) or not os.path.exists(device): + continue + ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) + retlist.append(ntuple) + return retlist + + +# ===================================================================== +# --- network +# ===================================================================== + + +net_io_counters = cext.net_io_counters +net_if_addrs = cext_posix.net_if_addrs + + +def net_connections(kind='inet'): + """System-wide network connections.""" + # Note: on OSX this will fail with AccessDenied unless + # the process is owned by root. + ret = [] + for pid in pids(): + try: + cons = Process(pid).connections(kind) + except NoSuchProcess: + continue + else: + if cons: + for c in cons: + c = list(c) + [pid] + ret.append(_common.sconn(*c)) + return ret + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + names = net_io_counters().keys() + ret = {} + for name in names: + mtu = cext_posix.net_if_mtu(name) + isup = cext_posix.net_if_flags(name) + duplex, speed = cext_posix.net_if_duplex_speed(name) + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + +# ===================================================================== +# --- other system functions +# ===================================================================== + + +def boot_time(): + """The system boot time expressed in seconds since the epoch.""" + return cext.boot_time() + + +def users(): + """Return currently connected users as a list of namedtuples.""" + retlist = [] + rawlist = cext.users() + for item in rawlist: + user, tty, hostname, tstamp = item + if tty == '~': + continue # reboot or shutdown + if not tstamp: + continue + nt = _common.suser(user, tty or None, hostname or None, tstamp) + retlist.append(nt) + return retlist + + +# ===================================================================== +# --- processes +# ===================================================================== + + +pids = cext.pids +pid_exists = _psposix.pid_exists + + +def wrap_exceptions(fun): + """Decorator which translates bare OSError exceptions into + NoSuchProcess and AccessDenied. + """ + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except OSError as err: + if self.pid == 0: + if 0 in pids(): + raise AccessDenied(self.pid, self._name) + else: + raise + if err.errno == errno.ESRCH: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + return wrapper + + +class Process(object): + """Wrapper class around underlying C implementation.""" + + __slots__ = ["pid", "_name", "_ppid"] + + def __init__(self, pid): + self.pid = pid + self._name = None + self._ppid = None + + @memoize_when_activated + def _get_kinfo_proc(self): + # Note: should work with all PIDs without permission issues. + ret = cext.proc_kinfo_oneshot(self.pid) + assert len(ret) == len(kinfo_proc_map) + return ret + + @memoize_when_activated + def _get_pidtaskinfo(self): + # Note: should work for PIDs owned by user only. + ret = cext.proc_pidtaskinfo_oneshot(self.pid) + assert len(ret) == len(pidtaskinfo_map) + return ret + + def oneshot_enter(self): + self._get_kinfo_proc.cache_activate() + self._get_pidtaskinfo.cache_activate() + + def oneshot_exit(self): + self._get_kinfo_proc.cache_deactivate() + self._get_pidtaskinfo.cache_deactivate() + + @wrap_exceptions + def name(self): + name = self._get_kinfo_proc()[kinfo_proc_map['name']] + return name if name is not None else cext.proc_name(self.pid) + + @wrap_exceptions + def exe(self): + return cext.proc_exe(self.pid) + + @wrap_exceptions + def cmdline(self): + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + return cext.proc_cmdline(self.pid) + + @wrap_exceptions + def environ(self): + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + return parse_environ_block(cext.proc_environ(self.pid)) + + @wrap_exceptions + def ppid(self): + self._ppid = self._get_kinfo_proc()[kinfo_proc_map['ppid']] + return self._ppid + + @wrap_exceptions + def cwd(self): + return cext.proc_cwd(self.pid) + + @wrap_exceptions + def uids(self): + rawtuple = self._get_kinfo_proc() + return _common.puids( + rawtuple[kinfo_proc_map['ruid']], + rawtuple[kinfo_proc_map['euid']], + rawtuple[kinfo_proc_map['suid']]) + + @wrap_exceptions + def gids(self): + rawtuple = self._get_kinfo_proc() + return _common.puids( + rawtuple[kinfo_proc_map['rgid']], + rawtuple[kinfo_proc_map['egid']], + rawtuple[kinfo_proc_map['sgid']]) + + @wrap_exceptions + def terminal(self): + tty_nr = self._get_kinfo_proc()[kinfo_proc_map['ttynr']] + tmap = _psposix.get_terminal_map() + try: + return tmap[tty_nr] + except KeyError: + return None + + @wrap_exceptions + def memory_info(self): + rawtuple = self._get_pidtaskinfo() + return pmem( + rawtuple[pidtaskinfo_map['rss']], + rawtuple[pidtaskinfo_map['vms']], + rawtuple[pidtaskinfo_map['pfaults']], + rawtuple[pidtaskinfo_map['pageins']], + ) + + @wrap_exceptions + def memory_full_info(self): + basic_mem = self.memory_info() + uss = cext.proc_memory_uss(self.pid) + return pfullmem(*basic_mem + (uss, )) + + @wrap_exceptions + def cpu_times(self): + rawtuple = self._get_pidtaskinfo() + return _common.pcputimes( + rawtuple[pidtaskinfo_map['cpuutime']], + rawtuple[pidtaskinfo_map['cpustime']], + # children user / system times are not retrievable (set to 0) + 0, 0) + + @wrap_exceptions + def create_time(self): + return self._get_kinfo_proc()[kinfo_proc_map['ctime']] + + @wrap_exceptions + def num_ctx_switches(self): + # Unvoluntary value seems not to be available; + # getrusage() numbers seems to confirm this theory. + # We set it to 0. + vol = self._get_pidtaskinfo()[pidtaskinfo_map['volctxsw']] + return _common.pctxsw(vol, 0) + + @wrap_exceptions + def num_threads(self): + return self._get_pidtaskinfo()[pidtaskinfo_map['numthreads']] + + @wrap_exceptions + def open_files(self): + if self.pid == 0: + return [] + files = [] + rawlist = cext.proc_open_files(self.pid) + for path, fd in rawlist: + if isfile_strict(path): + ntuple = _common.popenfile(path, fd) + files.append(ntuple) + return files + + @wrap_exceptions + def connections(self, kind='inet'): + if kind not in conn_tmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in conn_tmap]))) + families, types = conn_tmap[kind] + rawlist = cext.proc_connections(self.pid, families, types) + ret = [] + for item in rawlist: + fd, fam, type, laddr, raddr, status = item + status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + nt = _common.pconn(fd, fam, type, laddr, raddr, status) + ret.append(nt) + return ret + + @wrap_exceptions + def num_fds(self): + if self.pid == 0: + return 0 + return cext.proc_num_fds(self.pid) + + @wrap_exceptions + def wait(self, timeout=None): + try: + return _psposix.wait_pid(self.pid, timeout) + except _psposix.TimeoutExpired: + raise TimeoutExpired(timeout, self.pid, self._name) + + @wrap_exceptions + def nice_get(self): + return cext_posix.getpriority(self.pid) + + @wrap_exceptions + def nice_set(self, value): + return cext_posix.setpriority(self.pid, value) + + @wrap_exceptions + def status(self): + code = self._get_kinfo_proc()[kinfo_proc_map['status']] + # XXX is '?' legit? (we're not supposed to return it anyway) + return PROC_STATUSES.get(code, '?') + + @wrap_exceptions + def threads(self): + rawlist = cext.proc_threads(self.pid) + retlist = [] + for thread_id, utime, stime in rawlist: + ntuple = _common.pthread(thread_id, utime, stime) + retlist.append(ntuple) + return retlist + + @wrap_exceptions + def memory_maps(self): + return cext.proc_memory_maps(self.pid) diff --git a/pipenv/vendor/psutil/_psposix.py b/pipenv/vendor/psutil/_psposix.py new file mode 100644 index 00000000..6ed7694a --- /dev/null +++ b/pipenv/vendor/psutil/_psposix.py @@ -0,0 +1,184 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Routines common to all posix systems.""" + +import errno +import glob +import os +import sys +import time + +from ._common import memoize +from ._common import sdiskusage +from ._common import usage_percent +from ._compat import PY3 +from ._compat import unicode + + +__all__ = ['TimeoutExpired', 'pid_exists', 'wait_pid', 'disk_usage', + 'get_terminal_map'] + + +class TimeoutExpired(Exception): + pass + + +def pid_exists(pid): + """Check whether pid exists in the current process table.""" + if pid == 0: + # According to "man 2 kill" PID 0 has a special meaning: + # it refers to <> so we don't want to go any further. + # If we get here it means this UNIX platform *does* have + # a process with id 0. + return True + try: + os.kill(pid, 0) + except OSError as err: + if err.errno == errno.ESRCH: + # ESRCH == No such process + return False + elif err.errno == errno.EPERM: + # EPERM clearly means there's a process to deny access to + return True + else: + # According to "man 2 kill" possible error values are + # (EINVAL, EPERM, ESRCH) therefore we should never get + # here. If we do let's be explicit in considering this + # an error. + raise err + else: + return True + + +def wait_pid(pid, timeout=None): + """Wait for process with pid 'pid' to terminate and return its + exit status code as an integer. + + If pid is not a children of os.getpid() (current process) just + waits until the process disappears and return None. + + If pid does not exist at all return None immediately. + + Raise TimeoutExpired on timeout expired. + """ + def check_timeout(delay): + if timeout is not None: + if timer() >= stop_at: + raise TimeoutExpired() + time.sleep(delay) + return min(delay * 2, 0.04) + + timer = getattr(time, 'monotonic', time.time) + if timeout is not None: + def waitcall(): + return os.waitpid(pid, os.WNOHANG) + stop_at = timer() + timeout + else: + def waitcall(): + return os.waitpid(pid, 0) + + delay = 0.0001 + while True: + try: + retpid, status = waitcall() + except OSError as err: + if err.errno == errno.EINTR: + delay = check_timeout(delay) + continue + elif err.errno == errno.ECHILD: + # This has two meanings: + # - pid is not a child of os.getpid() in which case + # we keep polling until it's gone + # - pid never existed in the first place + # In both cases we'll eventually return None as we + # can't determine its exit status code. + while True: + if pid_exists(pid): + delay = check_timeout(delay) + else: + return + else: + raise + else: + if retpid == 0: + # WNOHANG was used, pid is still running + delay = check_timeout(delay) + continue + # process exited due to a signal; return the integer of + # that signal + if os.WIFSIGNALED(status): + return -os.WTERMSIG(status) + # process exited using exit(2) system call; return the + # integer exit(2) system call has been called with + elif os.WIFEXITED(status): + return os.WEXITSTATUS(status) + else: + # should never happen + raise ValueError("unknown process exit status %r" % status) + + +def disk_usage(path): + """Return disk usage associated with path. + Note: UNIX usually reserves 5% disk space which is not accessible + by user. In this function "total" and "used" values reflect the + total and used disk space whereas "free" and "percent" represent + the "free" and "used percent" user disk space. + """ + try: + st = os.statvfs(path) + except UnicodeEncodeError: + if not PY3 and isinstance(path, unicode): + # this is a bug with os.statvfs() and unicode on + # Python 2, see: + # - https://github.com/giampaolo/psutil/issues/416 + # - http://bugs.python.org/issue18695 + try: + path = path.encode(sys.getfilesystemencoding()) + except UnicodeEncodeError: + pass + st = os.statvfs(path) + else: + raise + + # Total space which is only available to root (unless changed + # at system level). + total = (st.f_blocks * st.f_frsize) + # Remaining free space usable by root. + avail_to_root = (st.f_bfree * st.f_frsize) + # Remaining free space usable by user. + avail_to_user = (st.f_bavail * st.f_frsize) + # Total space being used in general. + used = (total - avail_to_root) + # Total space which is available to user (same as 'total' but + # for the user). + total_user = used + avail_to_user + # User usage percent compared to the total amount of space + # the user can use. This number would be higher if compared + # to root's because the user has less space (usually -5%). + usage_percent_user = usage_percent(used, total_user, _round=1) + + # NB: the percentage is -5% than what shown by df due to + # reserved blocks that we are currently not considering: + # https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462 + return sdiskusage( + total=total, used=used, free=avail_to_user, percent=usage_percent_user) + + +@memoize +def get_terminal_map(): + """Get a map of device-id -> path as a dict. + Used by Process.terminal() + """ + ret = {} + ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') + for name in ls: + assert name not in ret, name + try: + ret[os.stat(name).st_rdev] = name + except OSError as err: + if err.errno != errno.ENOENT: + raise + return ret diff --git a/pipenv/vendor/psutil/_pssunos.py b/pipenv/vendor/psutil/_pssunos.py new file mode 100644 index 00000000..ad72de25 --- /dev/null +++ b/pipenv/vendor/psutil/_pssunos.py @@ -0,0 +1,702 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Sun OS Solaris platform implementation.""" + +import errno +import os +import socket +import subprocess +import sys +from collections import namedtuple + +from . import _common +from . import _psposix +from . import _psutil_posix as cext_posix +from . import _psutil_sunos as cext +from ._common import isfile_strict +from ._common import memoize_when_activated +from ._common import sockfam_to_enum +from ._common import socktype_to_enum +from ._common import usage_percent +from ._compat import b +from ._compat import PY3 + + +__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"] + + +# ===================================================================== +# --- globals +# ===================================================================== + + +PAGE_SIZE = os.sysconf('SC_PAGE_SIZE') +AF_LINK = cext_posix.AF_LINK +IS_64_BIT = sys.maxsize > 2**32 + +CONN_IDLE = "IDLE" +CONN_BOUND = "BOUND" + +PROC_STATUSES = { + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SRUN: _common.STATUS_RUNNING, + cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SSTOP: _common.STATUS_STOPPED, + cext.SIDL: _common.STATUS_IDLE, + cext.SONPROC: _common.STATUS_RUNNING, # same as run + cext.SWAIT: _common.STATUS_WAITING, +} + +TCP_STATUSES = { + cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, + cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, + cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV, + cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, + cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, + cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, + cext.TCPS_CLOSED: _common.CONN_CLOSE, + cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, + cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, + cext.TCPS_LISTEN: _common.CONN_LISTEN, + cext.TCPS_CLOSING: _common.CONN_CLOSING, + cext.PSUTIL_CONN_NONE: _common.CONN_NONE, + cext.TCPS_IDLE: CONN_IDLE, # sunos specific + cext.TCPS_BOUND: CONN_BOUND, # sunos specific +} + +# these get overwritten on "import psutil" from the __init__.py file +NoSuchProcess = None +ZombieProcess = None +AccessDenied = None +TimeoutExpired = None + + +# ===================================================================== +# --- named tuples +# ===================================================================== + + +# psutil.cpu_times() +scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait']) +# psutil.cpu_times(percpu=True) +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) +# psutil.virtual_memory() +svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) +# psutil.Process.memory_info() +pmem = namedtuple('pmem', ['rss', 'vms']) +pfullmem = pmem +# psutil.Process.memory_maps(grouped=True) +pmmap_grouped = namedtuple('pmmap_grouped', + ['path', 'rss', 'anonymous', 'locked']) +# psutil.Process.memory_maps(grouped=False) +pmmap_ext = namedtuple( + 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) + + +# ===================================================================== +# --- utils +# ===================================================================== + + +def get_procfs_path(): + """Return updated psutil.PROCFS_PATH constant.""" + return sys.modules['psutil'].PROCFS_PATH + + +# ===================================================================== +# --- memory +# ===================================================================== + + +def virtual_memory(): + """Report virtual memory metrics.""" + # we could have done this with kstat, but IMHO this is good enough + total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE + # note: there's no difference on Solaris + free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE + used = total - free + percent = usage_percent(used, total, _round=1) + return svmem(total, avail, percent, used, free) + + +def swap_memory(): + """Report swap memory metrics.""" + sin, sout = cext.swap_mem() + # XXX + # we are supposed to get total/free by doing so: + # http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/ + # usr/src/cmd/swap/swap.c + # ...nevertheless I can't manage to obtain the same numbers as 'swap' + # cmdline utility, so let's parse its output (sigh!) + p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' % + os.environ['PATH'], 'swap', '-l'], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + if PY3: + stdout = stdout.decode(sys.stdout.encoding) + if p.returncode != 0: + raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode) + + lines = stdout.strip().split('\n')[1:] + if not lines: + raise RuntimeError('no swap device(s) configured') + total = free = 0 + for line in lines: + line = line.split() + t, f = line[-2:] + total += int(int(t) * 512) + free += int(int(f) * 512) + used = total - free + percent = usage_percent(used, total, _round=1) + return _common.sswap(total, used, free, percent, + sin * PAGE_SIZE, sout * PAGE_SIZE) + + +# ===================================================================== +# --- CPU +# ===================================================================== + + +def cpu_times(): + """Return system-wide CPU times as a named tuple""" + ret = cext.per_cpu_times() + return scputimes(*[sum(x) for x in zip(*ret)]) + + +def per_cpu_times(): + """Return system per-CPU times as a list of named tuples""" + ret = cext.per_cpu_times() + return [scputimes(*x) for x in ret] + + +def cpu_count_logical(): + """Return the number of logical CPUs in the system.""" + try: + return os.sysconf("SC_NPROCESSORS_ONLN") + except ValueError: + # mimic os.cpu_count() behavior + return None + + +def cpu_count_physical(): + """Return the number of physical CPUs in the system.""" + return cext.cpu_count_phys() + + +def cpu_stats(): + """Return various CPU stats as a named tuple.""" + ctx_switches, interrupts, syscalls, traps = cext.cpu_stats() + soft_interrupts = 0 + return _common.scpustats(ctx_switches, interrupts, soft_interrupts, + syscalls) + + +# ===================================================================== +# --- disks +# ===================================================================== + + +disk_io_counters = cext.disk_io_counters +disk_usage = _psposix.disk_usage + + +def disk_partitions(all=False): + """Return system disk partitions.""" + # TODO - the filtering logic should be better checked so that + # it tries to reflect 'df' as much as possible + retlist = [] + partitions = cext.disk_partitions() + for partition in partitions: + device, mountpoint, fstype, opts = partition + if device == 'none': + device = '' + if not all: + # Differently from, say, Linux, we don't have a list of + # common fs types so the best we can do, AFAIK, is to + # filter by filesystem having a total size > 0. + if not disk_usage(mountpoint).total: + continue + ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) + retlist.append(ntuple) + return retlist + + +# ===================================================================== +# --- network +# ===================================================================== + + +net_io_counters = cext.net_io_counters +net_if_addrs = cext_posix.net_if_addrs + + +def net_connections(kind, _pid=-1): + """Return socket connections. If pid == -1 return system-wide + connections (as opposed to connections opened by one process only). + Only INET sockets are returned (UNIX are not). + """ + cmap = _common.conn_tmap.copy() + if _pid == -1: + cmap.pop('unix', 0) + if kind not in cmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in cmap]))) + families, types = _common.conn_tmap[kind] + rawlist = cext.net_connections(_pid) + ret = set() + for item in rawlist: + fd, fam, type_, laddr, raddr, status, pid = item + if fam not in families: + continue + if type_ not in types: + continue + status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type_ = socktype_to_enum(type_) + if _pid == -1: + nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid) + else: + nt = _common.pconn(fd, fam, type_, laddr, raddr, status) + ret.add(nt) + return list(ret) + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + ret = cext.net_if_stats() + for name, items in ret.items(): + isup, duplex, speed, mtu = items + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + +# ===================================================================== +# --- other system functions +# ===================================================================== + + +def boot_time(): + """The system boot time expressed in seconds since the epoch.""" + return cext.boot_time() + + +def users(): + """Return currently connected users as a list of namedtuples.""" + retlist = [] + rawlist = cext.users() + localhost = (':0.0', ':0') + for item in rawlist: + user, tty, hostname, tstamp, user_process = item + # note: the underlying C function includes entries about + # system boot, run level and others. We might want + # to use them in the future. + if not user_process: + continue + if hostname in localhost: + hostname = 'localhost' + nt = _common.suser(user, tty, hostname, tstamp) + retlist.append(nt) + return retlist + + +# ===================================================================== +# --- processes +# ===================================================================== + + +def pids(): + """Returns a list of PIDs currently running on the system.""" + return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] + + +def pid_exists(pid): + """Check for the existence of a unix pid.""" + return _psposix.pid_exists(pid) + + +def wrap_exceptions(fun): + """Call callable into a try/except clause and translate ENOENT, + EACCES and EPERM in NoSuchProcess or AccessDenied exceptions. + """ + + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except EnvironmentError as err: + if self.pid == 0: + if 0 in pids(): + raise AccessDenied(self.pid, self._name) + else: + raise + # ENOENT (no such file or directory) gets raised on open(). + # ESRCH (no such process) can get raised on read() if + # process is gone in meantime. + if err.errno in (errno.ENOENT, errno.ESRCH): + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + if err.errno in (errno.EPERM, errno.EACCES): + raise AccessDenied(self.pid, self._name) + raise + return wrapper + + +class Process(object): + """Wrapper class around underlying C implementation.""" + + __slots__ = ["pid", "_name", "_ppid", "_procfs_path"] + + def __init__(self, pid): + self.pid = pid + self._name = None + self._ppid = None + self._procfs_path = get_procfs_path() + + def oneshot_enter(self): + self._proc_name_and_args.cache_activate() + self._proc_basic_info.cache_activate() + self._proc_cred.cache_activate() + + def oneshot_exit(self): + self._proc_name_and_args.cache_deactivate() + self._proc_basic_info.cache_deactivate() + self._proc_cred.cache_deactivate() + + @memoize_when_activated + def _proc_name_and_args(self): + return cext.proc_name_and_args(self.pid, self._procfs_path) + + @memoize_when_activated + def _proc_basic_info(self): + return cext.proc_basic_info(self.pid, self._procfs_path) + + @memoize_when_activated + def _proc_cred(self): + return cext.proc_cred(self.pid, self._procfs_path) + + @wrap_exceptions + def name(self): + # note: max len == 15 + return self._proc_name_and_args()[0] + + @wrap_exceptions + def exe(self): + try: + return os.readlink( + "%s/%s/path/a.out" % (self._procfs_path, self.pid)) + except OSError: + pass # continue and guess the exe name from the cmdline + # Will be guessed later from cmdline but we want to explicitly + # invoke cmdline here in order to get an AccessDenied + # exception if the user has not enough privileges. + self.cmdline() + return "" + + @wrap_exceptions + def cmdline(self): + return self._proc_name_and_args()[1].split(' ') + + @wrap_exceptions + def create_time(self): + return self._proc_basic_info()[3] + + @wrap_exceptions + def num_threads(self): + return self._proc_basic_info()[5] + + @wrap_exceptions + def nice_get(self): + # For some reason getpriority(3) return ESRCH (no such process) + # for certain low-pid processes, no matter what (even as root). + # The process actually exists though, as it has a name, + # creation time, etc. + # The best thing we can do here appears to be raising AD. + # Note: tested on Solaris 11; on Open Solaris 5 everything is + # fine. + try: + return cext_posix.getpriority(self.pid) + except EnvironmentError as err: + # 48 is 'operation not supported' but errno does not expose + # it. It occurs for low system pids. + if err.errno in (errno.ENOENT, errno.ESRCH, 48): + if pid_exists(self.pid): + raise AccessDenied(self.pid, self._name) + raise + + @wrap_exceptions + def nice_set(self, value): + if self.pid in (2, 3): + # Special case PIDs: internally setpriority(3) return ESRCH + # (no such process), no matter what. + # The process actually exists though, as it has a name, + # creation time, etc. + raise AccessDenied(self.pid, self._name) + return cext_posix.setpriority(self.pid, value) + + @wrap_exceptions + def ppid(self): + self._ppid = self._proc_basic_info()[0] + return self._ppid + + @wrap_exceptions + def uids(self): + real, effective, saved, _, _, _ = self._proc_cred() + return _common.puids(real, effective, saved) + + @wrap_exceptions + def gids(self): + _, _, _, real, effective, saved = self._proc_cred() + return _common.puids(real, effective, saved) + + @wrap_exceptions + def cpu_times(self): + try: + times = cext.proc_cpu_times(self.pid, self._procfs_path) + except OSError as err: + if err.errno == errno.EOVERFLOW and not IS_64_BIT: + # We may get here if we attempt to query a 64bit process + # with a 32bit python. + # Error originates from read() and also tools like "cat" + # fail in the same way (!). + # Since there simply is no way to determine CPU times we + # return 0.0 as a fallback. See: + # https://github.com/giampaolo/psutil/issues/857 + times = (0.0, 0.0, 0.0, 0.0) + else: + raise + return _common.pcputimes(*times) + + @wrap_exceptions + def cpu_num(self): + return cext.proc_cpu_num(self.pid, self._procfs_path) + + @wrap_exceptions + def terminal(self): + procfs_path = self._procfs_path + hit_enoent = False + tty = wrap_exceptions( + self._proc_basic_info()[0]) + if tty != cext.PRNODEV: + for x in (0, 1, 2, 255): + try: + return os.readlink( + '%s/%d/path/%d' % (procfs_path, self.pid, x)) + except OSError as err: + if err.errno == errno.ENOENT: + hit_enoent = True + continue + raise + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (procfs_path, self.pid)) + + @wrap_exceptions + def cwd(self): + # /proc/PID/path/cwd may not be resolved by readlink() even if + # it exists (ls shows it). If that's the case and the process + # is still alive return None (we can return None also on BSD). + # Reference: http://goo.gl/55XgO + procfs_path = self._procfs_path + try: + return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid)) + except OSError as err: + if err.errno == errno.ENOENT: + os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD + return None + raise + + @wrap_exceptions + def memory_info(self): + ret = self._proc_basic_info() + rss, vms = ret[1] * 1024, ret[2] * 1024 + return pmem(rss, vms) + + memory_full_info = memory_info + + @wrap_exceptions + def status(self): + code = self._proc_basic_info()[6] + # XXX is '?' legit? (we're not supposed to return it anyway) + return PROC_STATUSES.get(code, '?') + + @wrap_exceptions + def threads(self): + procfs_path = self._procfs_path + ret = [] + tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid)) + hit_enoent = False + for tid in tids: + tid = int(tid) + try: + utime, stime = cext.query_process_thread( + self.pid, tid, procfs_path) + except EnvironmentError as err: + if err.errno == errno.EOVERFLOW and not IS_64_BIT: + # We may get here if we attempt to query a 64bit process + # with a 32bit python. + # Error originates from read() and also tools like "cat" + # fail in the same way (!). + # Since there simply is no way to determine CPU times we + # return 0.0 as a fallback. See: + # https://github.com/giampaolo/psutil/issues/857 + continue + # ENOENT == thread gone in meantime + if err.errno == errno.ENOENT: + hit_enoent = True + continue + raise + else: + nt = _common.pthread(tid, utime, stime) + ret.append(nt) + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (procfs_path, self.pid)) + return ret + + @wrap_exceptions + def open_files(self): + retlist = [] + hit_enoent = False + procfs_path = self._procfs_path + pathdir = '%s/%d/path' % (procfs_path, self.pid) + for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)): + path = os.path.join(pathdir, fd) + if os.path.islink(path): + try: + file = os.readlink(path) + except OSError as err: + # ENOENT == file which is gone in the meantime + if err.errno == errno.ENOENT: + hit_enoent = True + continue + raise + else: + if isfile_strict(file): + retlist.append(_common.popenfile(file, int(fd))) + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (procfs_path, self.pid)) + return retlist + + def _get_unix_sockets(self, pid): + """Get UNIX sockets used by process by parsing 'pfiles' output.""" + # TODO: rewrite this in C (...but the damn netstat source code + # does not include this part! Argh!!) + cmd = "pfiles %s" % pid + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + if PY3: + stdout, stderr = [x.decode(sys.stdout.encoding) + for x in (stdout, stderr)] + if p.returncode != 0: + if 'permission denied' in stderr.lower(): + raise AccessDenied(self.pid, self._name) + if 'no such process' in stderr.lower(): + raise NoSuchProcess(self.pid, self._name) + raise RuntimeError("%r command error\n%s" % (cmd, stderr)) + + lines = stdout.split('\n')[2:] + for i, line in enumerate(lines): + line = line.lstrip() + if line.startswith('sockname: AF_UNIX'): + path = line.split(' ', 2)[2] + type = lines[i - 2].strip() + if type == 'SOCK_STREAM': + type = socket.SOCK_STREAM + elif type == 'SOCK_DGRAM': + type = socket.SOCK_DGRAM + else: + type = -1 + yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE) + + @wrap_exceptions + def connections(self, kind='inet'): + ret = net_connections(kind, _pid=self.pid) + # The underlying C implementation retrieves all OS connections + # and filters them by PID. At this point we can't tell whether + # an empty list means there were no connections for process or + # process is no longer active so we force NSP in case the PID + # is no longer there. + if not ret: + # will raise NSP if process is gone + os.stat('%s/%s' % (self._procfs_path, self.pid)) + + # UNIX sockets + if kind in ('all', 'unix'): + ret.extend([_common.pconn(*conn) for conn in + self._get_unix_sockets(self.pid)]) + return ret + + nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked') + nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked') + + @wrap_exceptions + def memory_maps(self): + def toaddr(start, end): + return '%s-%s' % (hex(start)[2:].strip('L'), + hex(end)[2:].strip('L')) + + procfs_path = self._procfs_path + retlist = [] + try: + rawlist = cext.proc_memory_maps(self.pid, procfs_path) + except OSError as err: + if err.errno == errno.EOVERFLOW and not IS_64_BIT: + # We may get here if we attempt to query a 64bit process + # with a 32bit python. + # Error originates from read() and also tools like "cat" + # fail in the same way (!). + # Since there simply is no way to determine CPU times we + # return 0.0 as a fallback. See: + # https://github.com/giampaolo/psutil/issues/857 + return [] + else: + raise + hit_enoent = False + for item in rawlist: + addr, addrsize, perm, name, rss, anon, locked = item + addr = toaddr(addr, addrsize) + if not name.startswith('['): + try: + name = os.readlink( + '%s/%s/path/%s' % (procfs_path, self.pid, name)) + except OSError as err: + if err.errno == errno.ENOENT: + # sometimes the link may not be resolved by + # readlink() even if it exists (ls shows it). + # If that's the case we just return the + # unresolved link path. + # This seems an incosistency with /proc similar + # to: http://goo.gl/55XgO + name = '%s/%s/path/%s' % (procfs_path, self.pid, name) + hit_enoent = True + else: + raise + retlist.append((addr, perm, name, rss, anon, locked)) + if hit_enoent: + # raise NSP if the process disappeared on us + os.stat('%s/%s' % (procfs_path, self.pid)) + return retlist + + @wrap_exceptions + def num_fds(self): + return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) + + @wrap_exceptions + def num_ctx_switches(self): + return _common.pctxsw( + *cext.proc_num_ctx_switches(self.pid, self._procfs_path)) + + @wrap_exceptions + def wait(self, timeout=None): + try: + return _psposix.wait_pid(self.pid, timeout) + except _psposix.TimeoutExpired: + raise TimeoutExpired(timeout, self.pid, self._name) diff --git a/pipenv/vendor/psutil/_psutil_bsd.c b/pipenv/vendor/psutil/_psutil_bsd.c new file mode 100644 index 00000000..de748dcc --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_bsd.c @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil (OpenBSD). + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Platform-specific module methods for FreeBSD and OpenBSD. + + * OpenBSD references: + * - OpenBSD source code: http://anoncvs.spacehopper.org/openbsd-src/ + * + * OpenBSD / NetBSD: missing APIs compared to FreeBSD implementation: + * - psutil.net_connections() + * - psutil.Process.get/set_cpu_affinity() (not supported natively) + * - psutil.Process.memory_maps() + */ + +#if defined(PSUTIL_NETBSD) + #define _KMEMUSER +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for struct xsocket +#include +#include +// for xinpcb struct +#include +#include +#include +#include +#include +#include +#include +#include // for struct xtcpcb +#include // for TCP connection states +#include // for inet_ntop() + +#include + +#include // net io counters +#include +#include + +#include // process open files/connections +#include + +#include "_psutil_common.h" + +#ifdef PSUTIL_FREEBSD + #include "arch/bsd/freebsd.h" + #include "arch/bsd/freebsd_socks.h" + + #include + #include // get io counters + #include // process open files, shared libs (kinfo_getvmmap) + #if __FreeBSD_version < 900000 + #include // system users + #else + #include + #endif +#elif PSUTIL_OPENBSD + #include "arch/bsd/openbsd.h" + + #include + #include // for VREG + #define _KERNEL // for DTYPE_VNODE + #include + #undef _KERNEL + #include // for CPUSTATES & CP_* +#elif PSUTIL_NETBSD + #include "arch/bsd/netbsd.h" + #include "arch/bsd/netbsd_socks.h" + + #include + #include // for VREG + #include // for CPUSTATES & CP_* + #ifndef DTYPE_VNODE + #define DTYPE_VNODE 1 + #endif +#endif + + + +// convert a timeval struct to a double +#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + +#ifdef PSUTIL_FREEBSD + // convert a bintime struct to milliseconds + #define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * \ + (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000) +#endif + +#if defined(PSUTIL_OPENBSD) || defined (PSUTIL_NETBSD) + #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +#endif + + +/* + * Return a Python list of all the PIDs running on the system. + */ +static PyObject * +psutil_pids(PyObject *self, PyObject *args) { + kinfo_proc *proclist = NULL; + kinfo_proc *orig_address = NULL; + size_t num_processes; + size_t idx; + PyObject *py_retlist = PyList_New(0); + PyObject *py_pid = NULL; + + if (py_retlist == NULL) + return NULL; + + // TODO: RuntimeError is inappropriate here; we could return the + // original error instead. + if (psutil_get_proc_list(&proclist, &num_processes) != 0) { + if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + } + else { + PyErr_SetString(PyExc_RuntimeError, + "failed to retrieve process list"); + } + goto error; + } + + if (num_processes > 0) { + orig_address = proclist; // save so we can free it after we're done + for (idx = 0; idx < num_processes; idx++) { +#ifdef PSUTIL_FREEBSD + py_pid = Py_BuildValue("i", proclist->ki_pid); +#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) + py_pid = Py_BuildValue("i", proclist->p_pid); +#endif + if (!py_pid) + goto error; + if (PyList_Append(py_retlist, py_pid)) + goto error; + Py_DECREF(py_pid); + proclist++; + } + free(orig_address); + } + + return py_retlist; + +error: + Py_XDECREF(py_pid); + Py_DECREF(py_retlist); + if (orig_address != NULL) + free(orig_address); + return NULL; +} + + +/* + * Return a Python float indicating the system boot time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_boot_time(PyObject *self, PyObject *args) { + // fetch sysctl "kern.boottime" + static int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval boottime; + size_t len = sizeof(boottime); + + if (sysctl(request, 2, &boottime, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return Py_BuildValue("d", (double)boottime.tv_sec); +} + + +/* + * Collect different info about a process in one shot and return + * them as a big Python tuple. + */ +static PyObject * +psutil_proc_oneshot_info(PyObject *self, PyObject *args) { + long pid; + long rss; + long vms; + long memtext; + long memdata; + long memstack; + unsigned char oncpu; + kinfo_proc kp; + long pagesize = sysconf(_SC_PAGESIZE); + char str[1000]; + PyObject *py_name; + PyObject *py_retlist; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + + // Process +#ifdef PSUTIL_FREEBSD + sprintf(str, "%s", kp.ki_comm); +#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) + sprintf(str, "%s", kp.p_comm); +#endif +#if PY_MAJOR_VERSION >= 3 + py_name = PyUnicode_DecodeFSDefault(str); +#else + py_name = Py_BuildValue("s", str); +#endif + if (! py_name) { + // Likely a decoding error. We don't want to fail the whole + // operation. The python module may retry with proc_name(). + PyErr_Clear(); + py_name = Py_None; + } + + // Calculate memory. +#ifdef PSUTIL_FREEBSD + rss = (long)kp.ki_rssize * pagesize; + vms = (long)kp.ki_size; + memtext = (long)kp.ki_tsize * pagesize; + memdata = (long)kp.ki_dsize * pagesize; + memstack = (long)kp.ki_ssize * pagesize; +#else + rss = (long)kp.p_vm_rssize * pagesize; + #ifdef PSUTIL_OPENBSD + // VMS, this is how ps determines it on OpenBSD: + // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461 + // vms + vms = (long)(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize) * pagesize; + #elif PSUTIL_NETBSD + // VMS, this is how top determines it on NetBSD: + // ftp://ftp.iij.ad.jp/pub/NetBSD/NetBSD-release-6/src/external/bsd/ + // top/dist/machine/m_netbsd.c + vms = (long)kp.p_vm_msize * pagesize; + #endif + memtext = (long)kp.p_vm_tsize * pagesize; + memdata = (long)kp.p_vm_dsize * pagesize; + memstack = (long)kp.p_vm_ssize * pagesize; +#endif + +#ifdef PSUTIL_FREEBSD + // what CPU we're on; top was used as an example: + // https://svnweb.freebsd.org/base/head/usr.bin/top/machine.c? + // view=markup&pathrev=273835 + if (kp.ki_stat == SRUN && kp.ki_oncpu != NOCPU) + oncpu = kp.ki_oncpu; + else + oncpu = kp.ki_lastcpu; +#else + // On Net/OpenBSD we have kp.p_cpuid but it appears it's always + // set to KI_NOCPU. Even if it's not, ki_lastcpu does not exist + // so there's no way to determine where "sleeping" processes + // were. Not supported. + oncpu = -1; +#endif + + // Return a single big tuple with all process info. + py_retlist = Py_BuildValue( + "(lillllllidllllddddlllllbO)", +#ifdef PSUTIL_FREEBSD + // + (long)kp.ki_ppid, // (long) ppid + (int)kp.ki_stat, // (int) status + // UIDs + (long)kp.ki_ruid, // (long) real uid + (long)kp.ki_uid, // (long) effective uid + (long)kp.ki_svuid, // (long) saved uid + // GIDs + (long)kp.ki_rgid, // (long) real gid + (long)kp.ki_groups[0], // (long) effective gid + (long)kp.ki_svuid, // (long) saved gid + // + kp.ki_tdev, // (int) tty nr + PSUTIL_TV2DOUBLE(kp.ki_start), // (double) create time + // ctx switches + kp.ki_rusage.ru_nvcsw, // (long) ctx switches (voluntary) + kp.ki_rusage.ru_nivcsw, // (long) ctx switches (unvoluntary) + // IO count + kp.ki_rusage.ru_inblock, // (long) read io count + kp.ki_rusage.ru_oublock, // (long) write io count + // CPU times: convert from micro seconds to seconds. + PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime), // (double) user time + PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime), // (double) sys time + PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_utime), // (double) children utime + PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_stime), // (double) children stime + // memory + rss, // (long) rss + vms, // (long) vms + memtext, // (long) mem text + memdata, // (long) mem data + memstack, // (long) mem stack + // others + oncpu, // (unsigned char) the CPU we are on +#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) + // + (long)kp.p_ppid, // (long) ppid + (int)kp.p_stat, // (int) status + // UIDs + (long)kp.p_ruid, // (long) real uid + (long)kp.p_uid, // (long) effective uid + (long)kp.p_svuid, // (long) saved uid + // GIDs + (long)kp.p_rgid, // (long) real gid + (long)kp.p_groups[0], // (long) effective gid + (long)kp.p_svuid, // (long) saved gid + // + kp.p_tdev, // (int) tty nr + PSUTIL_KPT2DOUBLE(kp.p_ustart), // (double) create time + // ctx switches + kp.p_uru_nvcsw, // (long) ctx switches (voluntary) + kp.p_uru_nivcsw, // (long) ctx switches (unvoluntary) + // IO count + kp.p_uru_inblock, // (long) read io count + kp.p_uru_oublock, // (long) write io count + // CPU times: convert from micro seconds to seconds. + PSUTIL_KPT2DOUBLE(kp.p_uutime), // (double) user time + PSUTIL_KPT2DOUBLE(kp.p_ustime), // (double) sys time + // OpenBSD and NetBSD provide children user + system times summed + // together (no distinction). + kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch utime + kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch stime + // memory + rss, // (long) rss + vms, // (long) vms + memtext, // (long) mem text + memdata, // (long) mem data + memstack, // (long) mem stack + // others + oncpu, // (unsigned char) the CPU we are on +#endif + py_name // (pystr) name + ); + + if (py_retlist != NULL) { + // XXX shall we decref() also in case of Py_BuildValue() error? + Py_DECREF(py_name); + } + return py_retlist; +} + + +/* + * Return process name from kinfo_proc as a Python string. + */ +static PyObject * +psutil_proc_name(PyObject *self, PyObject *args) { + long pid; + kinfo_proc kp; + char str[1000]; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + +#ifdef PSUTIL_FREEBSD + sprintf(str, "%s", kp.ki_comm); +#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) + sprintf(str, "%s", kp.p_comm); +#endif + +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(str); +#else + return Py_BuildValue("s", str); +#endif +} + + +/* + * Return process cmdline as a Python list of cmdline arguments. + */ +static PyObject * +psutil_proc_cmdline(PyObject *self, PyObject *args) { + long pid; + PyObject *py_retlist = NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + py_retlist = psutil_get_cmdline(pid); + // psutil_get_cmdline() returns NULL only if psutil_cmd_args + // failed with ESRCH (no process with that PID) + if (NULL == py_retlist) + return PyErr_SetFromErrno(PyExc_OSError); + return Py_BuildValue("N", py_retlist); +} + + +/* + * Return the number of logical CPUs in the system. + * XXX this could be shared with OSX + */ +static PyObject * +psutil_cpu_count_logical(PyObject *self, PyObject *args) { + int mib[2]; + int ncpu; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", ncpu); +} + + +/* + * Return a Python tuple representing user, kernel and idle CPU times + */ +static PyObject * +psutil_cpu_times(PyObject *self, PyObject *args) { +#ifdef PSUTIL_NETBSD + u_int64_t cpu_time[CPUSTATES]; +#else + long cpu_time[CPUSTATES]; +#endif + size_t size = sizeof(cpu_time); + int ret; + +#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) + ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0); +#elif PSUTIL_OPENBSD + int mib[] = {CTL_KERN, KERN_CPTIME}; + ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0); +#endif + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC + ); +} + + + /* + * Return files opened by process as a list of (path, fd) tuples. + * TODO: this is broken as it may report empty paths. 'procstat' + * utility has the same problem see: + * https://github.com/giampaolo/psutil/issues/595 + */ +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD) +static PyObject * +psutil_proc_open_files(PyObject *self, PyObject *args) { + long pid; + int i, cnt; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + kinfo_proc kipp; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; +#ifdef PSUTIL_FREEBSD + if ((kif->kf_type == KF_TYPE_VNODE) && + (kif->kf_vnode_type == KF_VTYPE_VREG)) + { + py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); +#elif PSUTIL_OPENBSD + if ((kif->f_type == DTYPE_VNODE) && + (kif->v_type == VREG)) + { + py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); +#elif PSUTIL_NETBSD + if ((kif->ki_ftype == DTYPE_VNODE) && + (kif->ki_vtype == VREG)) + { + py_tuple = Py_BuildValue("(si)", "", kif->ki_fd); +#endif + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + free(freep); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + return NULL; +} +#endif + + +/* + * Return a list of tuples including device, mount point and fs type + * for all partitions mounted on the system. + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) { + int num; + int i; + long len; + uint64_t flags; + char opts[200]; +#ifdef PSUTIL_NETBSD + struct statvfs *fs = NULL; +#else + struct statfs *fs = NULL; +#endif + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + + // get the number of mount points + Py_BEGIN_ALLOW_THREADS +#ifdef PSUTIL_NETBSD + num = getvfsstat(NULL, 0, MNT_NOWAIT); +#else + num = getfsstat(NULL, 0, MNT_NOWAIT); +#endif + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + len = sizeof(*fs) * num; + fs = malloc(len); + if (fs == NULL) { + PyErr_NoMemory(); + goto error; + } + + Py_BEGIN_ALLOW_THREADS +#ifdef PSUTIL_NETBSD + num = getvfsstat(fs, len, MNT_NOWAIT); +#else + num = getfsstat(fs, len, MNT_NOWAIT); +#endif + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < num; i++) { + py_tuple = NULL; + opts[0] = 0; +#ifdef PSUTIL_NETBSD + flags = fs[i].f_flag; +#else + flags = fs[i].f_flags; +#endif + + // see sys/mount.h + if (flags & MNT_RDONLY) + strlcat(opts, "ro", sizeof(opts)); + else + strlcat(opts, "rw", sizeof(opts)); + if (flags & MNT_SYNCHRONOUS) + strlcat(opts, ",sync", sizeof(opts)); + if (flags & MNT_NOEXEC) + strlcat(opts, ",noexec", sizeof(opts)); + if (flags & MNT_NOSUID) + strlcat(opts, ",nosuid", sizeof(opts)); + if (flags & MNT_ASYNC) + strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_NOATIME) + strlcat(opts, ",noatime", sizeof(opts)); + if (flags & MNT_SOFTDEP) + strlcat(opts, ",softdep", sizeof(opts)); +#ifdef PSUTIL_FREEBSD + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); + if (flags & MNT_SUIDDIR) + strlcat(opts, ",suiddir", sizeof(opts)); + if (flags & MNT_SOFTDEP) + strlcat(opts, ",softdep", sizeof(opts)); + if (flags & MNT_NOSYMFOLLOW) + strlcat(opts, ",nosymfollow", sizeof(opts)); + if (flags & MNT_GJOURNAL) + strlcat(opts, ",gjournal", sizeof(opts)); + if (flags & MNT_MULTILABEL) + strlcat(opts, ",multilabel", sizeof(opts)); + if (flags & MNT_ACLS) + strlcat(opts, ",acls", sizeof(opts)); + if (flags & MNT_NOCLUSTERR) + strlcat(opts, ",noclusterr", sizeof(opts)); + if (flags & MNT_NOCLUSTERW) + strlcat(opts, ",noclusterw", sizeof(opts)); + if (flags & MNT_NFS4ACLS) + strlcat(opts, ",nfs4acls", sizeof(opts)); +#elif PSUTIL_NETBSD + if (flags & MNT_NODEV) + strlcat(opts, ",nodev", sizeof(opts)); + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); + if (flags & MNT_NOCOREDUMP) + strlcat(opts, ",nocoredump", sizeof(opts)); +#ifdef MNT_RELATIME + if (flags & MNT_RELATIME) + strlcat(opts, ",relatime", sizeof(opts)); +#endif + if (flags & MNT_IGNORE) + strlcat(opts, ",ignore", sizeof(opts)); +#ifdef MNT_DISCARD + if (flags & MNT_DISCARD) + strlcat(opts, ",discard", sizeof(opts)); +#endif +#ifdef MNT_EXTATTR + if (flags & MNT_EXTATTR) + strlcat(opts, ",extattr", sizeof(opts)); +#endif + if (flags & MNT_LOG) + strlcat(opts, ",log", sizeof(opts)); + if (flags & MNT_SYMPERM) + strlcat(opts, ",symperm", sizeof(opts)); + if (flags & MNT_NODEVMTIME) + strlcat(opts, ",nodevmtime", sizeof(opts)); +#endif + py_tuple = Py_BuildValue("(ssss)", + fs[i].f_mntfromname, // device + fs[i].f_mntonname, // mount point + fs[i].f_fstypename, // fs type + opts); // options + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + free(fs); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (fs != NULL) + free(fs); + return NULL; +} + + +/* + * Return a Python list of named tuples with overall network I/O information + */ +static PyObject * +psutil_net_io_counters(PyObject *self, PyObject *args) { + char *buf = NULL, *lim, *next; + struct if_msghdr *ifm; + int mib[6]; + size_t len; + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + if (py_retdict == NULL) + return NULL; + + mib[0] = CTL_NET; // networking subsystem + mib[1] = PF_ROUTE; // type of information + mib[2] = 0; // protocol (IPPROTO_xxx) + mib[3] = 0; // address family + mib[4] = NET_RT_IFLIST; // operation + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + lim = buf + len; + + for (next = buf; next < lim; ) { + py_ifc_info = NULL; + ifm = (struct if_msghdr *)next; + next += ifm->ifm_msglen; + + if (ifm->ifm_type == RTM_IFINFO) { + struct if_msghdr *if2m = (struct if_msghdr *)ifm; + struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); + char ifc_name[32]; + + strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen); + ifc_name[sdl->sdl_nlen] = 0; + // XXX: ignore usbus interfaces: + // http://lists.freebsd.org/pipermail/freebsd-current/ + // 2011-October/028752.html + // 'ifconfig -a' doesn't show them, nor do we. + if (strncmp(ifc_name, "usbus", 5) == 0) + continue; + + py_ifc_info = Py_BuildValue("(kkkkkkki)", + if2m->ifm_data.ifi_obytes, + if2m->ifm_data.ifi_ibytes, + if2m->ifm_data.ifi_opackets, + if2m->ifm_data.ifi_ipackets, + if2m->ifm_data.ifi_ierrors, + if2m->ifm_data.ifi_oerrors, + if2m->ifm_data.ifi_iqdrops, +#ifdef _IFI_OQDROPS + if2m->ifm_data.ifi_oqdrops +#else + 0 +#endif + ); + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + else { + continue; + } + } + + free(buf); + return py_retdict; + +error: + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (buf != NULL) + free(buf); + return NULL; +} + + +/* + * Return currently connected users as a list of tuples. + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + +#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || PSUTIL_OPENBSD + struct utmp ut; + FILE *fp; + + fp = fopen(_PATH_UTMP, "r"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + while (fread(&ut, sizeof(ut), 1, fp) == 1) { + if (*ut.ut_name == '\0') + continue; + py_tuple = Py_BuildValue( + "(sssf)", + ut.ut_name, // username + ut.ut_line, // tty + ut.ut_host, // hostname + (float)ut.ut_time); // start time + if (!py_tuple) { + fclose(fp); + goto error; + } + if (PyList_Append(py_retlist, py_tuple)) { + fclose(fp); + goto error; + } + Py_DECREF(py_tuple); + } + + fclose(fp); +#else + struct utmpx *utx; + + setutxent(); + while ((utx = getutxent()) != NULL) { + if (utx->ut_type != USER_PROCESS) + continue; + py_tuple = Py_BuildValue( + "(sssf)", + utx->ut_user, // username + utx->ut_line, // tty + utx->ut_host, // hostname + (float)utx->ut_tv.tv_sec // start time + ); + + if (!py_tuple) { + endutxent(); + goto error; + } + if (PyList_Append(py_retlist, py_tuple)) { + endutxent(); + goto error; + } + Py_DECREF(py_tuple); + } + + endutxent(); +#endif + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + return NULL; +} + + +/* + * define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = { + + // --- per-process functions + + {"proc_oneshot_info", psutil_proc_oneshot_info, METH_VARARGS, + "Return multiple info about a process"}, + {"proc_name", psutil_proc_name, METH_VARARGS, + "Return process name"}, +#if !defined(PSUTIL_NETBSD) + {"proc_connections", psutil_proc_connections, METH_VARARGS, + "Return connections opened by process"}, +#endif + {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, + "Return process cmdline as a list of cmdline arguments"}, + {"proc_threads", psutil_proc_threads, METH_VARARGS, + "Return process threads"}, +#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD) + {"proc_cwd", psutil_proc_cwd, METH_VARARGS, + "Return process current working directory."}, +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD) + {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, + "Return the number of file descriptors opened by this process"}, +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD) + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of (path, fd) tuples"}, +#endif + +#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) + {"proc_exe", psutil_proc_exe, METH_VARARGS, + "Return process pathname executable"}, + {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, + "Return number of threads used by process"}, +#if defined(PSUTIL_FREEBSD) + {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, + "Return a list of tuples for every process's memory map"}, + {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, + "Return process CPU affinity."}, + {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, + "Set process CPU affinity."}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Return an XML string to determine the number physical CPUs."}, +#endif +#endif + + // --- system-related functions + + {"pids", psutil_pids, METH_VARARGS, + "Returns a list of PIDs currently running on the system"}, + {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, + "Return number of logical CPUs on the system"}, + {"virtual_mem", psutil_virtual_mem, METH_VARARGS, + "Return system virtual memory usage statistics"}, + {"swap_mem", psutil_swap_mem, METH_VARARGS, + "Return swap mem stats"}, + {"cpu_times", psutil_cpu_times, METH_VARARGS, + "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, + {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, + "Return system per-cpu times as a list of tuples"}, + {"boot_time", psutil_boot_time, METH_VARARGS, + "Return the system boot time expressed in seconds since the epoch."}, + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return a list of tuples including device, mount point and " + "fs type for all partitions mounted on the system."}, + {"net_io_counters", psutil_net_io_counters, METH_VARARGS, + "Return dict of tuples of networks I/O information."}, + {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, + "Return a Python dict of tuples for disk I/O information"}, + {"users", psutil_users, METH_VARARGS, + "Return currently connected users as a list of tuples"}, + {"cpu_stats", psutil_cpu_stats, METH_VARARGS, + "Return CPU statistics"}, +#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) + {"net_connections", psutil_net_connections, METH_VARARGS, + "Return system-wide open connections."}, +#endif +#if defined(PSUTIL_FREEBSD) + {"sensors_battery", psutil_sensors_battery, METH_VARARGS, + "Return battery information."}, +#endif + {NULL, NULL, 0, NULL} +}; + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int +psutil_bsd_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef + moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_bsd", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_bsd_traverse, + psutil_bsd_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_bsd(void) + +#else +#define INITERROR return + +void init_psutil_bsd(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); +#endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + // process status constants + +#ifdef PSUTIL_FREEBSD + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); + PyModule_AddIntConstant(module, "SWAIT", SWAIT); + PyModule_AddIntConstant(module, "SLOCK", SLOCK); +#elif PSUTIL_OPENBSD + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused + PyModule_AddIntConstant(module, "SDEAD", SDEAD); + PyModule_AddIntConstant(module, "SONPROC", SONPROC); +#elif defined(PSUTIL_NETBSD) + PyModule_AddIntConstant(module, "SIDL", LSIDL); + PyModule_AddIntConstant(module, "SRUN", LSRUN); + PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP); + PyModule_AddIntConstant(module, "SSTOP", LSSTOP); + PyModule_AddIntConstant(module, "SZOMB", LSZOMB); + PyModule_AddIntConstant(module, "SDEAD", LSDEAD); + PyModule_AddIntConstant(module, "SONPROC", LSONPROC); + // unique to NetBSD + PyModule_AddIntConstant(module, "SSUSPENDED", LSSUSPENDED); +#endif + + // connection status constants + PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); + PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); + PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); + PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); + PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); + PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); + PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); + PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); + PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); + // PSUTIL_CONN_NONE + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); + + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_psutil_common.c b/pipenv/vendor/psutil/_psutil_common.c new file mode 100644 index 00000000..5d025739 --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_common.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Routines common to all platforms. + */ + +#ifdef PSUTIL_POSIX +#include +#include +#endif + +#include + + +/* + * Set OSError(errno=ESRCH, strerror="No such process") Python exception. + */ +PyObject * +NoSuchProcess(void) { + PyObject *exc; + char *msg = strerror(ESRCH); + exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg); + PyErr_SetObject(PyExc_OSError, exc); + Py_XDECREF(exc); + return NULL; +} + + +/* + * Set OSError(errno=EACCES, strerror="Permission denied") Python exception. + */ +PyObject * +AccessDenied(void) { + PyObject *exc; + char *msg = strerror(EACCES); + exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg); + PyErr_SetObject(PyExc_OSError, exc); + Py_XDECREF(exc); + return NULL; +} + + +#ifdef PSUTIL_POSIX +/* + * Check if PID exists. Return values: + * 1: exists + * 0: does not exist + * -1: error (Python exception is set) + */ +int +psutil_pid_exists(long pid) { + int ret; + + // No negative PID exists, plus -1 is an alias for sending signal + // too all processes except system ones. Not what we want. + if (pid < 0) + return 0; + + // As per "man 2 kill" PID 0 is an alias for sending the signal to + // every process in the process group of the calling process. + // Not what we want. Some platforms have PID 0, some do not. + // We decide that at runtime. + if (pid == 0) { +#if defined(PSUTIL_LINUX) || defined(PSUTIL_FREEBSD) + return 0; +#else + return 1; +#endif + } + +#if defined(PSUTIL_OSX) + ret = kill((pid_t)pid , 0); +#else + ret = kill(pid , 0); +#endif + + if (ret == 0) + return 1; + else { + if (errno == ESRCH) { + // ESRCH == No such process + return 0; + } + else if (errno == EPERM) { + // EPERM clearly indicates there's a process to deny + // access to. + return 1; + } + else { + // According to "man 2 kill" possible error values are + // (EINVAL, EPERM, ESRCH) therefore we should never get + // here. If we do let's be explicit in considering this + // an error. + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + } +} + + +/* + * Utility used for those syscalls which do not return a meaningful + * error that we can translate into an exception which makes sense. + * As such, we'll have to guess. + * On UNIX, if errno is set, we return that one (OSError). + * Else, if PID does not exist we assume the syscall failed because + * of that so we raise NoSuchProcess. + * If none of this is true we giveup and raise RuntimeError(msg). + * This will always set a Python exception and return NULL. + */ +int +psutil_raise_for_pid(long pid, char *msg) { + // Set exception to AccessDenied if pid exists else NoSuchProcess. + if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return 0; + } + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + PyErr_SetString(PyExc_RuntimeError, msg); + return 0; +} +#endif diff --git a/pipenv/vendor/psutil/_psutil_common.h b/pipenv/vendor/psutil/_psutil_common.h new file mode 100644 index 00000000..982c59c7 --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_common.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +PyObject* AccessDenied(void); +PyObject* NoSuchProcess(void); + +#ifdef PSUTIL_POSIX +int psutil_pid_exists(long pid); +void psutil_raise_for_pid(long pid, char *msg); +#endif diff --git a/pipenv/vendor/psutil/_psutil_linux.c b/pipenv/vendor/psutil/_psutil_linux.c new file mode 100644 index 00000000..0296dd54 --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_linux.c @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Linux-specific functions. + */ + +#ifndef _GNU_SOURCE + #define _GNU_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// see: https://github.com/giampaolo/psutil/issues/659 +#ifdef PSUTIL_ETHTOOL_MISSING_TYPES + #include + typedef __u64 u64; + typedef __u32 u32; + typedef __u16 u16; + typedef __u8 u8; +#endif +/* Avoid redefinition of struct sysinfo with musl libc */ +#define _LINUX_SYSINFO_H +#include + +/* The minimum number of CPUs allocated in a cpu_set_t */ +static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT; + +// Linux >= 2.6.13 +#define PSUTIL_HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set) + +// Linux >= 2.6.36 (supposedly) and glibc >= 13 +#define PSUTIL_HAVE_PRLIMIT \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \ + (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \ + defined(__NR_prlimit64) + +#if PSUTIL_HAVE_PRLIMIT + #define _FILE_OFFSET_BITS 64 + #include + #include +#endif + + +// May happen on old RedHat versions, see: +// https://github.com/giampaolo/psutil/issues/607 +#ifndef DUPLEX_UNKNOWN + #define DUPLEX_UNKNOWN 0xff +#endif + + +#if PSUTIL_HAVE_IOPRIO +enum { + IOPRIO_WHO_PROCESS = 1, +}; + +static inline int +ioprio_get(int which, int who) { + return syscall(__NR_ioprio_get, which, who); +} + +static inline int +ioprio_set(int which, int who, int ioprio) { + return syscall(__NR_ioprio_set, which, who, ioprio); +} + +#define IOPRIO_CLASS_SHIFT 13 +#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) +#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) +#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) + + +/* + * Return a (ioclass, iodata) Python tuple representing process I/O priority. + */ +static PyObject * +psutil_proc_ioprio_get(PyObject *self, PyObject *args) { + long pid; + int ioprio, ioclass, iodata; + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid); + if (ioprio == -1) + return PyErr_SetFromErrno(PyExc_OSError); + ioclass = IOPRIO_PRIO_CLASS(ioprio); + iodata = IOPRIO_PRIO_DATA(ioprio); + return Py_BuildValue("ii", ioclass, iodata); +} + + +/* + * A wrapper around ioprio_set(); sets process I/O priority. + * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE + * or 0. iodata goes from 0 to 7 depending on ioclass specified. + */ +static PyObject * +psutil_proc_ioprio_set(PyObject *self, PyObject *args) { + long pid; + int ioprio, ioclass, iodata; + int retval; + + if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) + return NULL; + ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata); + retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio); + if (retval == -1) + return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} +#endif + + +#if PSUTIL_HAVE_PRLIMIT +/* + * A wrapper around prlimit(2); sets process resource limits. + * This can be used for both get and set, in which case extra + * 'soft' and 'hard' args must be provided. + */ +static PyObject * +psutil_linux_prlimit(PyObject *self, PyObject *args) { + long pid; + int ret, resource; + struct rlimit old, new; + struct rlimit *newp = NULL; + PyObject *py_soft = NULL; + PyObject *py_hard = NULL; + + if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &py_soft, &py_hard)) + return NULL; + + // get + if (py_soft == NULL && py_hard == NULL) { + ret = prlimit(pid, resource, NULL, &old); + if (ret == -1) + return PyErr_SetFromErrno(PyExc_OSError); +#if defined(PSUTIL_HAVE_LONG_LONG) + if (sizeof(old.rlim_cur) > sizeof(long)) { + return Py_BuildValue("LL", + (PY_LONG_LONG)old.rlim_cur, + (PY_LONG_LONG)old.rlim_max); + } +#endif + return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max); + } + + // set + else { +#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT) + new.rlim_cur = PyLong_AsLongLong(py_soft); + if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred()) + return NULL; + new.rlim_max = PyLong_AsLongLong(py_hard); + if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred()) + return NULL; +#else + new.rlim_cur = PyLong_AsLong(py_soft); + if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred()) + return NULL; + new.rlim_max = PyLong_AsLong(py_hard); + if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred()) + return NULL; +#endif + newp = &new; + ret = prlimit(pid, resource, newp, &old); + if (ret == -1) + return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; + } +} +#endif + + +/* + * Return disk mounted partitions as a list of tuples including device, + * mount point and filesystem type + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) { + FILE *file = NULL; + struct mntent *entry; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + + // MOUNTED constant comes from mntent.h and it's == '/etc/mtab' + Py_BEGIN_ALLOW_THREADS + file = setmntent(MOUNTED, "r"); + Py_END_ALLOW_THREADS + if ((file == 0) || (file == NULL)) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, MOUNTED); + goto error; + } + + while ((entry = getmntent(file))) { + if (entry == NULL) { + PyErr_Format(PyExc_RuntimeError, "getmntent() syscall failed"); + goto error; + } + py_tuple = Py_BuildValue("(ssss)", + entry->mnt_fsname, // device + entry->mnt_dir, // mount point + entry->mnt_type, // fs type + entry->mnt_opts); // options + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + endmntent(file); + return py_retlist; + +error: + if (file != NULL) + endmntent(file); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + return NULL; +} + + +/* + * A wrapper around sysinfo(), return system memory usage statistics. + */ +static PyObject * +psutil_linux_sysinfo(PyObject *self, PyObject *args) { + struct sysinfo info; + + if (sysinfo(&info) != 0) + return PyErr_SetFromErrno(PyExc_OSError); + // note: boot time might also be determined from here + return Py_BuildValue( + "(kkkkkkI)", + info.totalram, // total + info.freeram, // free + info.bufferram, // buffer + info.sharedram, // shared + info.totalswap, // swap tot + info.freeswap, // swap free + info.mem_unit // multiplier + ); +} + + +/* + * Return process CPU affinity as a Python list + * The dual implementation exists because of: + * https://github.com/giampaolo/psutil/issues/536 + */ + +#ifdef CPU_ALLOC + +static PyObject * +psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { + int cpu, ncpus, count, cpucount_s; + long pid; + size_t setsize; + cpu_set_t *mask = NULL; + PyObject *py_list = NULL; + + if (!PyArg_ParseTuple(args, "l", &pid)) + return NULL; + ncpus = NCPUS_START; + while (1) { + setsize = CPU_ALLOC_SIZE(ncpus); + mask = CPU_ALLOC(ncpus); + if (mask == NULL) + return PyErr_NoMemory(); + if (sched_getaffinity(pid, setsize, mask) == 0) + break; + CPU_FREE(mask); + if (errno != EINVAL) + return PyErr_SetFromErrno(PyExc_OSError); + if (ncpus > INT_MAX / 2) { + PyErr_SetString(PyExc_OverflowError, "could not allocate " + "a large enough CPU set"); + return NULL; + } + ncpus = ncpus * 2; + } + + py_list = PyList_New(0); + if (py_list == NULL) + goto error; + + cpucount_s = CPU_COUNT_S(setsize, mask); + for (cpu = 0, count = cpucount_s; count; cpu++) { + if (CPU_ISSET_S(cpu, setsize, mask)) { +#if PY_MAJOR_VERSION >= 3 + PyObject *cpu_num = PyLong_FromLong(cpu); +#else + PyObject *cpu_num = PyInt_FromLong(cpu); +#endif + if (cpu_num == NULL) + goto error; + if (PyList_Append(py_list, cpu_num)) { + Py_DECREF(cpu_num); + goto error; + } + Py_DECREF(cpu_num); + --count; + } + } + CPU_FREE(mask); + return py_list; + +error: + if (mask) + CPU_FREE(mask); + Py_XDECREF(py_list); + return NULL; +} +#else + + +/* + * Alternative implementation in case CPU_ALLOC is not defined. + */ +static PyObject * +psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { + cpu_set_t cpuset; + unsigned int len = sizeof(cpu_set_t); + long pid; + int i; + PyObject* py_retlist = NULL; + PyObject *py_cpu_num = NULL; + + if (!PyArg_ParseTuple(args, "l", &pid)) + return NULL; + CPU_ZERO(&cpuset); + if (sched_getaffinity(pid, len, &cpuset) < 0) + return PyErr_SetFromErrno(PyExc_OSError); + + py_retlist = PyList_New(0); + if (py_retlist == NULL) + goto error; + for (i = 0; i < CPU_SETSIZE; ++i) { + if (CPU_ISSET(i, &cpuset)) { + py_cpu_num = Py_BuildValue("i", i); + if (py_cpu_num == NULL) + goto error; + if (PyList_Append(py_retlist, py_cpu_num)) + goto error; + Py_DECREF(py_cpu_num); + } + } + + return py_retlist; + +error: + Py_XDECREF(py_cpu_num); + Py_XDECREF(py_retlist); + return NULL; +} +#endif + +/* + * Set process CPU affinity; expects a bitmask + */ +static PyObject * +psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { + cpu_set_t cpu_set; + size_t len; + long pid; + int i, seq_len; + PyObject *py_cpu_set; + PyObject *py_cpu_seq = NULL; + + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; + + if (!PySequence_Check(py_cpu_set)) { + PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s", + Py_TYPE(py_cpu_set)->tp_name); + goto error; + } + + py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); + if (!py_cpu_seq) + goto error; + seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); + CPU_ZERO(&cpu_set); + for (i = 0; i < seq_len; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); +#if PY_MAJOR_VERSION >= 3 + long value = PyLong_AsLong(item); +#else + long value = PyInt_AsLong(item); +#endif + if ((value == -1) || PyErr_Occurred()) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, "invalid CPU value"); + goto error; + } + CPU_SET(value, &cpu_set); + } + + + len = sizeof(cpu_set); + if (sched_setaffinity(pid, len, &cpu_set)) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + Py_DECREF(py_cpu_seq); + Py_RETURN_NONE; + +error: + if (py_cpu_seq != NULL) + Py_DECREF(py_cpu_seq); + return NULL; +} + + +/* + * Return currently connected users as a list of tuples. + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) { + struct utmp *ut; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_user_proc = NULL; + + if (py_retlist == NULL) + return NULL; + setutent(); + while (NULL != (ut = getutent())) { + py_tuple = NULL; + py_user_proc = NULL; + if (ut->ut_type == USER_PROCESS) + py_user_proc = Py_True; + else + py_user_proc = Py_False; + py_tuple = Py_BuildValue( + "(sssfO)", + ut->ut_user, // username + ut->ut_line, // tty + ut->ut_host, // hostname + (float)ut->ut_tv.tv_sec, // tstamp + py_user_proc // (bool) user process + ); + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + endutent(); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_user_proc); + Py_DECREF(py_retlist); + endutent(); + return NULL; +} + + +/* + * Return stats about a particular network + * interface. References: + * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject* +psutil_net_if_duplex_speed(PyObject* self, PyObject* args) { + char *nic_name; + int sock = 0; + int ret; + int duplex; + int speed; + struct ifreq ifr; + struct ethtool_cmd ethcmd; + PyObject *py_retlist = NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + + // duplex and speed + memset(ðcmd, 0, sizeof ethcmd); + ethcmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (void *)ðcmd; + ret = ioctl(sock, SIOCETHTOOL, &ifr); + + if (ret != -1) { + duplex = ethcmd.duplex; + speed = ethcmd.speed; + } + else { + if ((errno == EOPNOTSUPP) || (errno == EINVAL)) { + // EOPNOTSUPP may occur in case of wi-fi cards. + // For EINVAL see: + // https://github.com/giampaolo/psutil/issues/797 + // #issuecomment-202999532 + duplex = DUPLEX_UNKNOWN; + speed = 0; + } + else { + goto error; + } + } + + close(sock); + py_retlist = Py_BuildValue("[ii]", duplex, speed); + if (!py_retlist) + goto error; + return py_retlist; + +error: + if (sock != -1) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = { + + // --- per-process functions + +#if PSUTIL_HAVE_IOPRIO + {"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS, + "Get process I/O priority"}, + {"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS, + "Set process I/O priority"}, +#endif + {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, + "Return process CPU affinity as a Python long (the bitmask)."}, + {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, + "Set process CPU affinity; expects a bitmask."}, + + // --- system related functions + + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return disk mounted partitions as a list of tuples including " + "device, mount point and filesystem type"}, + {"users", psutil_users, METH_VARARGS, + "Return currently connected users as a list of tuples"}, + {"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS, + "Return duplex and speed info about a NIC"}, + + // --- linux specific + + {"linux_sysinfo", psutil_linux_sysinfo, METH_VARARGS, + "A wrapper around sysinfo(), return system memory usage statistics"}, +#if PSUTIL_HAVE_PRLIMIT + {"linux_prlimit", psutil_linux_prlimit, METH_VARARGS, + "Get or set process resource limits."}, +#endif + + + {NULL, NULL, 0, NULL} +}; + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int +psutil_linux_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef + moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_linux", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_linux_traverse, + psutil_linux_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_linux(void) + +#else +#define INITERROR return + +void init_psutil_linux(void) +#endif +{ + PyObject *v; +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods); +#endif + + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); +#if PSUTIL_HAVE_PRLIMIT + PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS); + PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE); + PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU); + PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA); + PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE); + PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS); + PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK); + PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE); + PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC); + PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS); + PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK); + +#if defined(HAVE_LONG_LONG) + if (sizeof(RLIM_INFINITY) > sizeof(long)) { + v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY); + } else +#endif + { + v = PyLong_FromLong((long) RLIM_INFINITY); + } + if (v) { + PyModule_AddObject(module, "RLIM_INFINITY", v); + } + +#ifdef RLIMIT_MSGQUEUE + PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE); +#endif +#ifdef RLIMIT_NICE + PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE); +#endif +#ifdef RLIMIT_RTPRIO + PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO); +#endif +#ifdef RLIMIT_RTTIME + PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME); +#endif +#ifdef RLIMIT_SIGPENDING + PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING); +#endif +#endif + PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF); + PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL); + PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN); + + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_psutil_osx.c b/pipenv/vendor/psutil/_psutil_osx.c new file mode 100644 index 00000000..fb26dc9b --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_osx.c @@ -0,0 +1,1910 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * OS X platform-specific module methods for _psutil_osx + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "_psutil_common.h" +#include "arch/osx/process_info.h" + + +#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + + +/* + * A wrapper around host_statistics() invoked with HOST_VM_INFO. + */ +int +psutil_sys_vminfo(vm_statistics_data_t *vmstat) { + kern_return_t ret; + mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); + mach_port_t mport = mach_host_self(); + + ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)vmstat, &count); + if (ret != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "host_statistics(HOST_VM_INFO) syscall failed: %s", + mach_error_string(ret)); + return 0; + } + mach_port_deallocate(mach_task_self(), mport); + return 1; +} + + +/* + * Return a Python list of all the PIDs running on the system. + */ +static PyObject * +psutil_pids(PyObject *self, PyObject *args) { + kinfo_proc *proclist = NULL; + kinfo_proc *orig_address = NULL; + size_t num_processes; + size_t idx; + PyObject *py_pid = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + + if (psutil_get_proc_list(&proclist, &num_processes) != 0) { + if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + } + else { + PyErr_SetString(PyExc_RuntimeError, + "failed to retrieve process list"); + } + goto error; + } + + if (num_processes > 0) { + // save the address of proclist so we can free it later + orig_address = proclist; + for (idx = 0; idx < num_processes; idx++) { + py_pid = Py_BuildValue("i", proclist->kp_proc.p_pid); + if (! py_pid) + goto error; + if (PyList_Append(py_retlist, py_pid)) + goto error; + Py_DECREF(py_pid); + proclist++; + } + free(orig_address); + } + return py_retlist; + +error: + Py_XDECREF(py_pid); + Py_DECREF(py_retlist); + if (orig_address != NULL) + free(orig_address); + return NULL; +} + + +/* + * Return multiple process info as a Python tuple in one shot by + * using sysctl() and filling up a kinfo_proc struct. + * It should be possible to do this for all processes without + * incurring into permission (EPERM) errors. + */ +static PyObject * +psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) { + long pid; + struct kinfo_proc kp; + PyObject *py_name; + PyObject *py_retlist; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_get_kinfo_proc(pid, &kp) == -1) + return NULL; + +#if PY_MAJOR_VERSION >= 3 + py_name = PyUnicode_DecodeFSDefault(kp.kp_proc.p_comm); +#else + py_name = Py_BuildValue("s", kp.kp_proc.p_comm); +#endif + if (! py_name) { + // Likely a decoding error. We don't want to fail the whole + // operation. The python module may retry with proc_name(). + PyErr_Clear(); + py_name = Py_None; + } + + py_retlist = Py_BuildValue( + "lllllllidiO", + (long)kp.kp_eproc.e_ppid, // (long) ppid + (long)kp.kp_eproc.e_pcred.p_ruid, // (long) real uid + (long)kp.kp_eproc.e_ucred.cr_uid, // (long) effective uid + (long)kp.kp_eproc.e_pcred.p_svuid, // (long) saved uid + (long)kp.kp_eproc.e_pcred.p_rgid, // (long) real gid + (long)kp.kp_eproc.e_ucred.cr_groups[0], // (long) effective gid + (long)kp.kp_eproc.e_pcred.p_svgid, // (long) saved gid + kp.kp_eproc.e_tdev, // (int) tty nr + PSUTIL_TV2DOUBLE(kp.kp_proc.p_starttime), // (double) create time + (int)kp.kp_proc.p_stat, // (int) status + py_name // (pystr) name + ); + + if (py_retlist != NULL) { + // XXX shall we decref() also in case of Py_BuildValue() error? + Py_DECREF(py_name); + } + return py_retlist; +} + + +/* + * Return multiple process info as a Python tuple in one shot by + * using proc_pidinfo(PROC_PIDTASKINFO) and filling a proc_taskinfo + * struct. + * Contrarily from proc_kinfo above this function will return EACCES + * for PIDs owned by another user. + */ +static PyObject * +psutil_proc_pidtaskinfo_oneshot(PyObject *self, PyObject *args) { + long pid; + struct proc_taskinfo pti; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0) + return NULL; + + return Py_BuildValue( + "(ddKKkkkk)", + (float)pti.pti_total_user / 1000000000.0, // (float) cpu user time + (float)pti.pti_total_system / 1000000000.0, // (float) cpu sys time + // Note about memory: determining other mem stats on OSX is a mess: + // http://www.opensource.apple.com/source/top/top-67/libtop.c?txt + // I just give up. + // struct proc_regioninfo pri; + // psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri)) + pti.pti_resident_size, // (uns long long) rss + pti.pti_virtual_size, // (uns long long) vms + pti.pti_faults, // (uns long) number of page faults (pages) + pti.pti_pageins, // (uns long) number of actual pageins (pages) + pti.pti_threadnum, // (uns long) num threads + // Unvoluntary value seems not to be available; + // pti.pti_csw probably refers to the sum of the two; + // getrusage() numbers seems to confirm this theory. + pti.pti_csw // (uns long) voluntary ctx switches + ); +} + + +/* + * Return process name from kinfo_proc as a Python string. + */ +static PyObject * +psutil_proc_name(PyObject *self, PyObject *args) { + long pid; + struct kinfo_proc kp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_get_kinfo_proc(pid, &kp) == -1) + return NULL; +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(kp.kp_proc.p_comm); +#else + return Py_BuildValue("s", kp.kp_proc.p_comm); +#endif +} + + +/* + * Return process current working directory. + */ +static PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + long pid; + struct proc_vnodepathinfo pathinfo; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + if (psutil_proc_pidinfo( + pid, PROC_PIDVNODEPATHINFO, 0, &pathinfo, sizeof(pathinfo)) <= 0) + { + return NULL; + } + +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(pathinfo.pvi_cdir.vip_path); +#else + return Py_BuildValue("s", pathinfo.pvi_cdir.vip_path); +#endif +} + + +/* + * Return path of the process executable. + */ +static PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { + long pid; + char buf[PATH_MAX]; + int ret; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + errno = 0; + ret = proc_pidpath((pid_t)pid, &buf, sizeof(buf)); + if (ret == 0) { + if (pid == 0) + AccessDenied(); + else + psutil_raise_for_pid(pid, "proc_pidpath() syscall failed"); + return NULL; + } +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(buf); +#else + return Py_BuildValue("s", buf); +#endif +} + + +/* + * Return process cmdline as a Python list of cmdline arguments. + */ +static PyObject * +psutil_proc_cmdline(PyObject *self, PyObject *args) { + long pid; + PyObject *py_retlist = NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + // get the commandline, defined in arch/osx/process_info.c + py_retlist = psutil_get_cmdline(pid); + return py_retlist; +} + + +/* + * Return process environment as a Python string. + */ +static PyObject * +psutil_proc_environ(PyObject *self, PyObject *args) { + long pid; + PyObject *py_retdict = NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + // get the environment block, defined in arch/osx/process_info.c + py_retdict = psutil_get_environ(pid); + return py_retdict; +} + + +/* + * Return a list of tuples for every process memory maps. + * 'procstat' cmdline utility has been used as an example. + */ +static PyObject * +psutil_proc_memory_maps(PyObject *self, PyObject *args) { + char buf[PATH_MAX]; + char addr_str[34]; + char perms[8]; + int pagesize = getpagesize(); + long pid; + kern_return_t err = KERN_SUCCESS; + mach_port_t task = MACH_PORT_NULL; + uint32_t depth = 1; + vm_address_t address = 0; + vm_size_t size = 0; + + PyObject *py_tuple = NULL; + PyObject *py_list = PyList_New(0); + + if (py_list == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + err = task_for_pid(mach_task_self(), (pid_t)pid, &task); + if (err != KERN_SUCCESS) { + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); + goto error; + } + + while (1) { + py_tuple = NULL; + struct vm_region_submap_info_64 info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + err = vm_region_recurse_64(task, &address, &size, &depth, + (vm_region_info_64_t)&info, &count); + if (err == KERN_INVALID_ADDRESS) + break; + if (info.is_submap) { + depth++; + } + else { + // Free/Reset the char[]s to avoid weird paths + memset(buf, 0, sizeof(buf)); + memset(addr_str, 0, sizeof(addr_str)); + memset(perms, 0, sizeof(perms)); + + sprintf(addr_str, + "%016lx-%016lx", + (long unsigned int)address, + (long unsigned int)address + size); + sprintf(perms, "%c%c%c/%c%c%c", + (info.protection & VM_PROT_READ) ? 'r' : '-', + (info.protection & VM_PROT_WRITE) ? 'w' : '-', + (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', + (info.max_protection & VM_PROT_READ) ? 'r' : '-', + (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', + (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-'); + + // proc_regionfilename() return value seems meaningless + // so we do what we can in order to not continue in case + // of error. + errno = 0; + proc_regionfilename((pid_t)pid, address, buf, sizeof(buf)); + if ((errno != 0) || ((sizeof(buf)) <= 0)) { + psutil_raise_for_pid( + pid, "proc_regionfilename() syscall failed"); + goto error; + } + + if (info.share_mode == SM_COW && info.ref_count == 1) { + // Treat single reference SM_COW as SM_PRIVATE + info.share_mode = SM_PRIVATE; + } + + if (strlen(buf) == 0) { + switch (info.share_mode) { +// #ifdef SM_LARGE_PAGE + // case SM_LARGE_PAGE: + // Treat SM_LARGE_PAGE the same as SM_PRIVATE + // since they are not shareable and are wired. +// #endif + case SM_COW: + strcpy(buf, "[cow]"); + break; + case SM_PRIVATE: + strcpy(buf, "[prv]"); + break; + case SM_EMPTY: + strcpy(buf, "[nul]"); + break; + case SM_SHARED: + case SM_TRUESHARED: + strcpy(buf, "[shm]"); + break; + case SM_PRIVATE_ALIASED: + strcpy(buf, "[ali]"); + break; + case SM_SHARED_ALIASED: + strcpy(buf, "[s/a]"); + break; + default: + strcpy(buf, "[???]"); + } + } + + py_tuple = Py_BuildValue( + "sssIIIIIH", + addr_str, // "start-end"address + perms, // "rwx" permissions + buf, // path + info.pages_resident * pagesize, // rss + info.pages_shared_now_private * pagesize, // private + info.pages_swapped_out * pagesize, // swapped + info.pages_dirtied * pagesize, // dirtied + info.ref_count, // ref count + info.shadow_depth // shadow depth + ); + if (!py_tuple) + goto error; + if (PyList_Append(py_list, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + // increment address for the next map/file + address += size; + } + + if (task != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), task); + + return py_list; + +error: + if (task != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), task); + Py_XDECREF(py_tuple); + Py_DECREF(py_list); + return NULL; +} + + +/* + * Return the number of logical CPUs in the system. + * XXX this could be shared with BSD. + */ +static PyObject * +psutil_cpu_count_logical(PyObject *self, PyObject *args) { + /* + int mib[2]; + int ncpu; + size_t len; + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", ncpu); + */ + int num; + size_t size = sizeof(int); + + if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", num); +} + + +/* + * Return the number of physical CPUs in the system. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + int num; + size_t size = sizeof(int); + + if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", num); +} + + +/* + * Indicates if the given virtual address on the given architecture is in the + * shared VM region. + */ +bool +psutil_in_shared_region(mach_vm_address_t addr, cpu_type_t type) { + mach_vm_address_t base; + mach_vm_address_t size; + + switch (type) { + case CPU_TYPE_ARM: + base = SHARED_REGION_BASE_ARM; + size = SHARED_REGION_SIZE_ARM; + break; + case CPU_TYPE_I386: + base = SHARED_REGION_BASE_I386; + size = SHARED_REGION_SIZE_I386; + break; + case CPU_TYPE_X86_64: + base = SHARED_REGION_BASE_X86_64; + size = SHARED_REGION_SIZE_X86_64; + break; + default: + return false; + } + + return base <= addr && addr < (base + size); +} + + +/* + * Returns the USS (unique set size) of the process. Reference: + * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ + * nsMemoryReporterManager.cpp + */ +static PyObject * +psutil_proc_memory_uss(PyObject *self, PyObject *args) { + long pid; + int err; + size_t len; + cpu_type_t cpu_type; + size_t private_pages = 0; + mach_vm_size_t size = 0; + mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; + kern_return_t kr; + vm_size_t page_size; + mach_vm_address_t addr = MACH_VM_MIN_ADDRESS; + mach_port_t task = MACH_PORT_NULL; + vm_region_top_info_data_t info; + mach_port_t object_name; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + err = task_for_pid(mach_task_self(), (pid_t)pid, &task); + if (err != KERN_SUCCESS) { + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); + return NULL; + } + + len = sizeof(cpu_type); + if (sysctlbyname("sysctl.proc_cputype", &cpu_type, &len, NULL, 0) != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + // Roughly based on libtop_update_vm_regions in + // http://www.opensource.apple.com/source/top/top-100.1.2/libtop.c + for (addr = 0; ; addr += size) { + kr = mach_vm_region( + task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, + &info_count, &object_name); + if (kr == KERN_INVALID_ADDRESS) { + // Done iterating VM regions. + break; + } + else if (kr != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "mach_vm_region(VM_REGION_TOP_INFO) syscall failed"); + return NULL; + } + + if (psutil_in_shared_region(addr, cpu_type) && + info.share_mode != SM_PRIVATE) { + continue; + } + + switch (info.share_mode) { +#ifdef SM_LARGE_PAGE + case SM_LARGE_PAGE: + // NB: Large pages are not shareable and always resident. +#endif + case SM_PRIVATE: + private_pages += info.private_pages_resident; + private_pages += info.shared_pages_resident; + break; + case SM_COW: + private_pages += info.private_pages_resident; + if (info.ref_count == 1) { + // Treat copy-on-write pages as private if they only + // have one reference. + private_pages += info.shared_pages_resident; + } + break; + case SM_SHARED: + default: + break; + } + } + + mach_port_deallocate(mach_task_self(), task); + + if (host_page_size(mach_host_self(), &page_size) != KERN_SUCCESS) + page_size = PAGE_SIZE; + + return Py_BuildValue("K", private_pages * page_size); +} + + +/* + * Return system virtual memory stats. + * See: + * http://opensource.apple.com/source/system_cmds/system_cmds-498.2/ + * vm_stat.tproj/vm_stat.c + */ +static PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + int mib[2]; + uint64_t total; + size_t len = sizeof(total); + vm_statistics_data_t vm; + int pagesize = getpagesize(); + // physical mem + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + + // This is also available as sysctlbyname("hw.memsize"). + if (sysctl(mib, 2, &total, &len, NULL, 0)) { + if (errno != 0) + PyErr_SetFromErrno(PyExc_OSError); + else + PyErr_Format( + PyExc_RuntimeError, "sysctl(HW_MEMSIZE) syscall failed"); + return NULL; + } + + // vm + if (!psutil_sys_vminfo(&vm)) + return NULL; + + return Py_BuildValue( + "KKKKK", + total, + (unsigned long long) vm.active_count * pagesize, + (unsigned long long) vm.inactive_count * pagesize, + (unsigned long long) vm.wire_count * pagesize, + // this is how vm_stat cmd does it + (unsigned long long) (vm.free_count - vm.speculative_count) * pagesize + ); +} + + +/* + * Return stats about swap memory. + */ +static PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + int mib[2]; + size_t size; + struct xsw_usage totals; + vm_statistics_data_t vmstat; + int pagesize = getpagesize(); + + mib[0] = CTL_VM; + mib[1] = VM_SWAPUSAGE; + size = sizeof(totals); + if (sysctl(mib, 2, &totals, &size, NULL, 0) == -1) { + if (errno != 0) + PyErr_SetFromErrno(PyExc_OSError); + else + PyErr_Format( + PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) syscall failed"); + return NULL; + } + if (!psutil_sys_vminfo(&vmstat)) + return NULL; + + return Py_BuildValue( + "LLLKK", + totals.xsu_total, + totals.xsu_used, + totals.xsu_avail, + (unsigned long long)vmstat.pageins * pagesize, + (unsigned long long)vmstat.pageouts * pagesize); +} + + +/* + * Return a Python tuple representing user, kernel and idle CPU times + */ +static PyObject * +psutil_cpu_times(PyObject *self, PyObject *args) { + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + kern_return_t error; + host_cpu_load_info_data_t r_load; + + mach_port_t host_port = mach_host_self(); + error = host_statistics(host_port, HOST_CPU_LOAD_INFO, + (host_info_t)&r_load, &count); + if (error != KERN_SUCCESS) { + return PyErr_Format( + PyExc_RuntimeError, + "host_statistics(HOST_CPU_LOAD_INFO) syscall failed: %s", + mach_error_string(error)); + } + mach_port_deallocate(mach_task_self(), host_port); + + return Py_BuildValue( + "(dddd)", + (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK + ); +} + + +/* + * Return a Python list of tuple representing per-cpu times + */ +static PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + natural_t cpu_count; + natural_t i; + processor_info_array_t info_array; + mach_msg_type_number_t info_count; + kern_return_t error; + processor_cpu_load_info_data_t *cpu_load_info = NULL; + int ret; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + mach_port_t host_port = mach_host_self(); + error = host_processor_info(host_port, PROCESSOR_CPU_LOAD_INFO, + &cpu_count, &info_array, &info_count); + if (error != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "host_processor_info(PROCESSOR_CPU_LOAD_INFO) syscall failed: %s", + mach_error_string(error)); + goto error; + } + mach_port_deallocate(mach_task_self(), host_port); + + cpu_load_info = (processor_cpu_load_info_data_t *) info_array; + + for (i = 0; i < cpu_count; i++) { + py_cputime = Py_BuildValue( + "(dddd)", + (double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK, + (double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK, + (double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, + (double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK + ); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, + info_count * sizeof(int)); + if (ret != KERN_SUCCESS) + PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + if (cpu_load_info != NULL) { + ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, + info_count * sizeof(int)); + if (ret != KERN_SUCCESS) + PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); + } + return NULL; +} + + +/* + * Retrieve CPU frequency. + */ +static PyObject * +psutil_cpu_freq(PyObject *self, PyObject *args) { + int64_t curr; + int64_t min; + int64_t max; + size_t size = sizeof(int64_t); + + if (sysctlbyname("hw.cpufrequency", &curr, &size, NULL, 0)) + goto error; + if (sysctlbyname("hw.cpufrequency_min", &min, &size, NULL, 0)) + goto error; + if (sysctlbyname("hw.cpufrequency_max", &max, &size, NULL, 0)) + goto error; + + return Py_BuildValue( + "KKK", + curr / 1000 / 1000, + min / 1000 / 1000, + max / 1000 / 1000); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Return a Python float indicating the system boot time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_boot_time(PyObject *self, PyObject *args) { + // fetch sysctl "kern.boottime" + static int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval result; + size_t result_len = sizeof result; + time_t boot_time = 0; + + if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + boot_time = result.tv_sec; + return Py_BuildValue("f", (float)boot_time); +} + + +/* + * Return a list of tuples including device, mount point and fs type + * for all partitions mounted on the system. + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) { + int num; + int i; + int len; + uint64_t flags; + char opts[400]; + struct statfs *fs = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + + // get the number of mount points + Py_BEGIN_ALLOW_THREADS + num = getfsstat(NULL, 0, MNT_NOWAIT); + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + len = sizeof(*fs) * num; + fs = malloc(len); + if (fs == NULL) { + PyErr_NoMemory(); + goto error; + } + + Py_BEGIN_ALLOW_THREADS + num = getfsstat(fs, len, MNT_NOWAIT); + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < num; i++) { + opts[0] = 0; + flags = fs[i].f_flags; + + // see sys/mount.h + if (flags & MNT_RDONLY) + strlcat(opts, "ro", sizeof(opts)); + else + strlcat(opts, "rw", sizeof(opts)); + if (flags & MNT_SYNCHRONOUS) + strlcat(opts, ",sync", sizeof(opts)); + if (flags & MNT_NOEXEC) + strlcat(opts, ",noexec", sizeof(opts)); + if (flags & MNT_NOSUID) + strlcat(opts, ",nosuid", sizeof(opts)); + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); + if (flags & MNT_ASYNC) + strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_EXPORTED) + strlcat(opts, ",exported", sizeof(opts)); + if (flags & MNT_QUARANTINE) + strlcat(opts, ",quarantine", sizeof(opts)); + if (flags & MNT_LOCAL) + strlcat(opts, ",local", sizeof(opts)); + if (flags & MNT_QUOTA) + strlcat(opts, ",quota", sizeof(opts)); + if (flags & MNT_ROOTFS) + strlcat(opts, ",rootfs", sizeof(opts)); + if (flags & MNT_DOVOLFS) + strlcat(opts, ",dovolfs", sizeof(opts)); + if (flags & MNT_DONTBROWSE) + strlcat(opts, ",dontbrowse", sizeof(opts)); + if (flags & MNT_IGNORE_OWNERSHIP) + strlcat(opts, ",ignore-ownership", sizeof(opts)); + if (flags & MNT_AUTOMOUNTED) + strlcat(opts, ",automounted", sizeof(opts)); + if (flags & MNT_JOURNALED) + strlcat(opts, ",journaled", sizeof(opts)); + if (flags & MNT_NOUSERXATTR) + strlcat(opts, ",nouserxattr", sizeof(opts)); + if (flags & MNT_DEFWRITE) + strlcat(opts, ",defwrite", sizeof(opts)); + if (flags & MNT_MULTILABEL) + strlcat(opts, ",multilabel", sizeof(opts)); + if (flags & MNT_NOATIME) + strlcat(opts, ",noatime", sizeof(opts)); + if (flags & MNT_UPDATE) + strlcat(opts, ",update", sizeof(opts)); + if (flags & MNT_RELOAD) + strlcat(opts, ",reload", sizeof(opts)); + if (flags & MNT_FORCE) + strlcat(opts, ",force", sizeof(opts)); + if (flags & MNT_CMDFLAGS) + strlcat(opts, ",cmdflags", sizeof(opts)); + + py_tuple = Py_BuildValue( + "(ssss)", fs[i].f_mntfromname, // device + fs[i].f_mntonname, // mount point + fs[i].f_fstypename, // fs type + opts); // options + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + free(fs); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (fs != NULL) + free(fs); + return NULL; +} + + +/* + * Return process threads + */ +static PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + long pid; + int err, ret; + kern_return_t kr; + unsigned int info_count = TASK_BASIC_INFO_COUNT; + mach_port_t task = MACH_PORT_NULL; + struct task_basic_info tasks_info; + thread_act_port_array_t thread_list = NULL; + thread_info_data_t thinfo_basic; + thread_basic_info_t basic_info_th; + mach_msg_type_number_t thread_count, thread_info_count, j; + + PyObject *py_tuple = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + + // the argument passed should be a process id + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + // task_for_pid() requires special privileges + err = task_for_pid(mach_task_self(), (pid_t)pid, &task); + if (err != KERN_SUCCESS) { + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); + goto error; + } + + info_count = TASK_BASIC_INFO_COUNT; + err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, + &info_count); + if (err != KERN_SUCCESS) { + // errcode 4 is "invalid argument" (access denied) + if (err == 4) { + AccessDenied(); + } + else { + // otherwise throw a runtime error with appropriate error code + PyErr_Format(PyExc_RuntimeError, + "task_info(TASK_BASIC_INFO) syscall failed"); + } + goto error; + } + + err = task_threads(task, &thread_list, &thread_count); + if (err != KERN_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "task_threads() syscall failed"); + goto error; + } + + for (j = 0; j < thread_count; j++) { + py_tuple = NULL; + thread_info_count = THREAD_INFO_MAX; + kr = thread_info(thread_list[j], THREAD_BASIC_INFO, + (thread_info_t)thinfo_basic, &thread_info_count); + if (kr != KERN_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, + "thread_info(THREAD_BASIC_INFO) syscall failed"); + goto error; + } + + basic_info_th = (thread_basic_info_t)thinfo_basic; + py_tuple = Py_BuildValue( + "Iff", + j + 1, + (float)basic_info_th->user_time.microseconds / 1000000.0, + (float)basic_info_th->system_time.microseconds / 1000000.0 + ); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + ret = vm_deallocate(task, (vm_address_t)thread_list, + thread_count * sizeof(int)); + if (ret != KERN_SUCCESS) + PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); + + mach_port_deallocate(mach_task_self(), task); + + return py_retlist; + +error: + if (task != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), task); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (thread_list != NULL) { + ret = vm_deallocate(task, (vm_address_t)thread_list, + thread_count * sizeof(int)); + if (ret != KERN_SUCCESS) + PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); + } + return NULL; +} + + +/* + * Return process open files as a Python tuple. + * References: + * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd + * - /usr/include/sys/proc_info.h + */ +static PyObject * +psutil_proc_open_files(PyObject *self, PyObject *args) { + long pid; + int pidinfo_result; + int iterations; + int i; + unsigned long nb; + + struct proc_fdinfo *fds_pointer = NULL; + struct proc_fdinfo *fdp_pointer; + struct vnode_fdinfowithpath vi; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_path = NULL; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (pidinfo_result <= 0) + goto error; + + fds_pointer = malloc(pidinfo_result); + if (fds_pointer == NULL) { + PyErr_NoMemory(); + goto error; + } + pidinfo_result = psutil_proc_pidinfo( + pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); + if (pidinfo_result <= 0) + goto error; + + iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); + + for (i = 0; i < iterations; i++) { + py_tuple = NULL; + fdp_pointer = &fds_pointer[i]; + + if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { + errno = 0; + nb = proc_pidfdinfo((pid_t)pid, + fdp_pointer->proc_fd, + PROC_PIDFDVNODEPATHINFO, + &vi, + sizeof(vi)); + + // --- errors checking + if ((nb <= 0) || nb < sizeof(vi)) { + if ((errno == ENOENT) || (errno == EBADF)) { + // no such file or directory or bad file descriptor; + // let's assume the file has been closed or removed + continue; + } + else { + psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed"); + goto error; + } + } + // --- /errors checking + + // --- construct python list +#if PY_MAJOR_VERSION >= 3 + py_path = PyUnicode_DecodeFSDefault(vi.pvip.vip_path); +#else + py_path = Py_BuildValue("s", vi.pvip.vip_path); +#endif + if (! py_path) + goto error; + py_tuple = Py_BuildValue( + "(Oi)", + py_path, + (int)fdp_pointer->proc_fd); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_path); + // --- /construct python list + } + } + + free(fds_pointer); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_path); + Py_DECREF(py_retlist); + if (fds_pointer != NULL) + free(fds_pointer); + return NULL; // exception has already been set earlier +} + + +// a signaler for connections without an actual status +static int PSUTIL_CONN_NONE = 128; + +/* + * Return process TCP and UDP connections as a list of tuples. + * References: + * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 + * - /usr/include/sys/proc_info.h + */ +static PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) { + long pid; + int pidinfo_result; + int iterations; + int i; + unsigned long nb; + + struct proc_fdinfo *fds_pointer = NULL; + struct proc_fdinfo *fdp_pointer; + struct socket_fdinfo si; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + goto error; + + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + goto error; + } + + if (pid == 0) + return py_retlist; + pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (pidinfo_result <= 0) + goto error; + + fds_pointer = malloc(pidinfo_result); + if (fds_pointer == NULL) { + PyErr_NoMemory(); + goto error; + } + + pidinfo_result = psutil_proc_pidinfo( + pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); + if (pidinfo_result <= 0) + goto error; + + iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); + for (i = 0; i < iterations; i++) { + py_tuple = NULL; + py_laddr = NULL; + py_raddr = NULL; + fdp_pointer = &fds_pointer[i]; + + if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { + errno = 0; + nb = proc_pidfdinfo((pid_t)pid, fdp_pointer->proc_fd, + PROC_PIDFDSOCKETINFO, &si, sizeof(si)); + + // --- errors checking + if ((nb <= 0) || (nb < sizeof(si))) { + if (errno == EBADF) { + // let's assume socket has been closed + continue; + } + else { + psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed"); + goto error; + } + } + // --- /errors checking + + // + int fd, family, type, lport, rport, state; + char lip[200], rip[200]; + int inseq; + PyObject *py_family; + PyObject *py_type; + + fd = (int)fdp_pointer->proc_fd; + family = si.psi.soi_family; + type = si.psi.soi_type; + + // apply filters + py_family = PyLong_FromLong((long)family); + inseq = PySequence_Contains(py_af_filter, py_family); + Py_DECREF(py_family); + if (inseq == 0) + continue; + py_type = PyLong_FromLong((long)type); + inseq = PySequence_Contains(py_type_filter, py_type); + Py_DECREF(py_type); + if (inseq == 0) + continue; + + if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + if ((family == AF_INET) || (family == AF_INET6)) { + if (family == AF_INET) { + inet_ntop(AF_INET, + &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ + insi_laddr.ina_46.i46a_addr4, + lip, + sizeof(lip)); + inet_ntop(AF_INET, + &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr. \ + ina_46.i46a_addr4, + rip, + sizeof(rip)); + } + else { + inet_ntop(AF_INET6, + &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ + insi_laddr.ina_6, + lip, sizeof(lip)); + inet_ntop(AF_INET6, + &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ + insi_faddr.ina_6, + rip, sizeof(rip)); + } + + // check for inet_ntop failures + if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); + rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); + if (type == SOCK_STREAM) + state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state; + else + state = PSUTIL_CONN_NONE; + + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + + // construct the python list + py_tuple = Py_BuildValue( + "(iiiNNi)", fd, family, type, py_laddr, py_raddr, state); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + else if (family == AF_UNIX) { + // construct the python list + py_tuple = Py_BuildValue( + "(iiissi)", + fd, family, type, + si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path, + si.psi.soi_proto.pri_un.unsi_caddr.ua_sun.sun_path, + PSUTIL_CONN_NONE); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + } + + free(fds_pointer); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); + if (fds_pointer != NULL) + free(fds_pointer); + return NULL; +} + + +/* + * Return number of file descriptors opened by process. + */ +static PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int pidinfo_result; + int num; + struct proc_fdinfo *fds_pointer; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (pidinfo_result <= 0) + return PyErr_SetFromErrno(PyExc_OSError); + + fds_pointer = malloc(pidinfo_result); + if (fds_pointer == NULL) + return PyErr_NoMemory(); + pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, fds_pointer, + pidinfo_result); + if (pidinfo_result <= 0) { + free(fds_pointer); + return PyErr_SetFromErrno(PyExc_OSError); + } + + num = (pidinfo_result / PROC_PIDLISTFD_SIZE); + free(fds_pointer); + return Py_BuildValue("i", num); +} + + +/* + * Return a Python list of named tuples with overall network I/O information + */ +static PyObject * +psutil_net_io_counters(PyObject *self, PyObject *args) { + char *buf = NULL, *lim, *next; + struct if_msghdr *ifm; + int mib[6]; + size_t len; + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + + if (py_retdict == NULL) + return NULL; + + mib[0] = CTL_NET; // networking subsystem + mib[1] = PF_ROUTE; // type of information + mib[2] = 0; // protocol (IPPROTO_xxx) + mib[3] = 0; // address family + mib[4] = NET_RT_IFLIST2; // operation + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + lim = buf + len; + + for (next = buf; next < lim; ) { + ifm = (struct if_msghdr *)next; + next += ifm->ifm_msglen; + + if (ifm->ifm_type == RTM_IFINFO2) { + py_ifc_info = NULL; + struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm; + struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); + char ifc_name[32]; + + strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen); + ifc_name[sdl->sdl_nlen] = 0; + + py_ifc_info = Py_BuildValue( + "(KKKKKKKi)", + if2m->ifm_data.ifi_obytes, + if2m->ifm_data.ifi_ibytes, + if2m->ifm_data.ifi_opackets, + if2m->ifm_data.ifi_ipackets, + if2m->ifm_data.ifi_ierrors, + if2m->ifm_data.ifi_oerrors, + if2m->ifm_data.ifi_iqdrops, + 0); // dropout not supported + + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + else { + continue; + } + } + + free(buf); + return py_retdict; + +error: + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (buf != NULL) + free(buf); + return NULL; +} + + +/* + * Return a Python dict of tuples for disk I/O information + */ +static PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + CFDictionaryRef parent_dict; + CFDictionaryRef props_dict; + CFDictionaryRef stats_dict; + io_registry_entry_t parent; + io_registry_entry_t disk; + io_iterator_t disk_list; + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + + if (py_retdict == NULL) + return NULL; + + // Get list of disks + if (IOServiceGetMatchingServices(kIOMasterPortDefault, + IOServiceMatching(kIOMediaClass), + &disk_list) != kIOReturnSuccess) { + PyErr_SetString( + PyExc_RuntimeError, "unable to get the list of disks."); + goto error; + } + + // Iterate over disks + while ((disk = IOIteratorNext(disk_list)) != 0) { + py_disk_info = NULL; + parent_dict = NULL; + props_dict = NULL; + stats_dict = NULL; + + if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) + != kIOReturnSuccess) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the disk's parent."); + IOObjectRelease(disk); + goto error; + } + + if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) { + if (IORegistryEntryCreateCFProperties( + disk, + (CFMutableDictionaryRef *) &parent_dict, + kCFAllocatorDefault, + kNilOptions + ) != kIOReturnSuccess) + { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the parent's properties."); + IOObjectRelease(disk); + IOObjectRelease(parent); + goto error; + } + + if (IORegistryEntryCreateCFProperties( + parent, + (CFMutableDictionaryRef *) &props_dict, + kCFAllocatorDefault, + kNilOptions + ) != kIOReturnSuccess) + { + PyErr_SetString(PyExc_RuntimeError, + "unable to get the disk properties."); + CFRelease(props_dict); + IOObjectRelease(disk); + IOObjectRelease(parent); + goto error; + } + + const int kMaxDiskNameSize = 64; + CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue( + parent_dict, CFSTR(kIOBSDNameKey)); + char disk_name[kMaxDiskNameSize]; + + CFStringGetCString(disk_name_ref, + disk_name, + kMaxDiskNameSize, + CFStringGetSystemEncoding()); + + stats_dict = (CFDictionaryRef)CFDictionaryGetValue( + props_dict, CFSTR(kIOBlockStorageDriverStatisticsKey)); + + if (stats_dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Unable to get disk stats."); + goto error; + } + + CFNumberRef number; + int64_t reads = 0; + int64_t writes = 0; + int64_t read_bytes = 0; + int64_t write_bytes = 0; + int64_t read_time = 0; + int64_t write_time = 0; + + // Get disk reads/writes + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &reads); + } + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &writes); + } + + // Get disk bytes read/written + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes); + } + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes); + } + + // Get disk time spent reading/writing (nanoseconds) + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &read_time); + } + if ((number = (CFNumberRef)CFDictionaryGetValue( + stats_dict, + CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) + { + CFNumberGetValue(number, kCFNumberSInt64Type, &write_time); + } + + // Read/Write time on OS X comes back in nanoseconds and in psutil + // we've standardized on milliseconds so do the conversion. + py_disk_info = Py_BuildValue( + "(KKKKKK)", + reads, + writes, + read_bytes, + write_bytes, + read_time / 1000 / 1000, + write_time / 1000 / 1000); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + + CFRelease(parent_dict); + IOObjectRelease(parent); + CFRelease(props_dict); + IOObjectRelease(disk); + } + } + + IOObjectRelease (disk_list); + + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + return NULL; +} + + +/* + * Return currently connected users as a list of tuples. + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) { + struct utmpx *utx; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + while ((utx = getutxent()) != NULL) { + if (utx->ut_type != USER_PROCESS) + continue; + py_tuple = Py_BuildValue( + "(sssf)", + utx->ut_user, // username + utx->ut_line, // tty + utx->ut_host, // hostname + (float)utx->ut_tv.tv_sec // start time + ); + if (!py_tuple) { + endutxent(); + goto error; + } + if (PyList_Append(py_retlist, py_tuple)) { + endutxent(); + goto error; + } + Py_DECREF(py_tuple); + } + + endutxent(); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + return NULL; +} + + +/* + * Return CPU statistics. + */ +static PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + struct vmmeter vmstat; + kern_return_t ret; + mach_msg_type_number_t count = sizeof(vmstat) / sizeof(integer_t); + mach_port_t mport = mach_host_self(); + + ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)&vmstat, &count); + if (ret != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "host_statistics(HOST_VM_INFO) failed: %s", + mach_error_string(ret)); + return NULL; + } + mach_port_deallocate(mach_task_self(), mport); + + return Py_BuildValue( + "IIIII", + vmstat.v_swtch, // ctx switches + vmstat.v_intr, // interrupts + vmstat.v_soft, // software interrupts + vmstat.v_syscall, // syscalls + vmstat.v_trap // traps + ); +} + + + +/* + * define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = { + + // --- per-process functions + + {"proc_kinfo_oneshot", psutil_proc_kinfo_oneshot, METH_VARARGS, + "Return multiple process info."}, + {"proc_pidtaskinfo_oneshot", psutil_proc_pidtaskinfo_oneshot, METH_VARARGS, + "Return multiple process info."}, + {"proc_name", psutil_proc_name, METH_VARARGS, + "Return process name"}, + {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, + "Return process cmdline as a list of cmdline arguments"}, + {"proc_environ", psutil_proc_environ, METH_VARARGS, + "Return process environment data"}, + {"proc_exe", psutil_proc_exe, METH_VARARGS, + "Return path of the process executable"}, + {"proc_cwd", psutil_proc_cwd, METH_VARARGS, + "Return process current working directory."}, + {"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS, + "Return process USS memory"}, + {"proc_threads", psutil_proc_threads, METH_VARARGS, + "Return process threads as a list of tuples"}, + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of tuples"}, + {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, + "Return the number of fds opened by process."}, + {"proc_connections", psutil_proc_connections, METH_VARARGS, + "Get process TCP and UDP connections as a list of tuples"}, + {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, + "Return a list of tuples for every process's memory map"}, + + // --- system-related functions + + {"pids", psutil_pids, METH_VARARGS, + "Returns a list of PIDs currently running on the system"}, + {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, + "Return number of logical CPUs on the system"}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Return number of physical CPUs on the system"}, + {"virtual_mem", psutil_virtual_mem, METH_VARARGS, + "Return system virtual memory stats"}, + {"swap_mem", psutil_swap_mem, METH_VARARGS, + "Return stats about swap memory, in bytes"}, + {"cpu_times", psutil_cpu_times, METH_VARARGS, + "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, + {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, + "Return system per-cpu times as a list of tuples"}, + {"cpu_freq", psutil_cpu_freq, METH_VARARGS, + "Return cpu current frequency"}, + {"boot_time", psutil_boot_time, METH_VARARGS, + "Return the system boot time expressed in seconds since the epoch."}, + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return a list of tuples including device, mount point and " + "fs type for all partitions mounted on the system."}, + {"net_io_counters", psutil_net_io_counters, METH_VARARGS, + "Return dict of tuples of networks I/O information."}, + {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, + "Return dict of tuples of disks I/O information."}, + {"users", psutil_users, METH_VARARGS, + "Return currently connected users as a list of tuples"}, + {"cpu_stats", psutil_cpu_stats, METH_VARARGS, + "Return CPU statistics"}, + + {NULL, NULL, 0, NULL} +}; + + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int +psutil_osx_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_osx", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_osx_traverse, + psutil_osx_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_osx(void) + +#else +#define INITERROR return + +void +init_psutil_osx(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods); +#endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + // process status constants, defined in: + // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149 + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); + // connection status constants + PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); + PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); + PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); + PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); + PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); + PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); + PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); + PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); + PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); + + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_psutil_posix.c b/pipenv/vendor/psutil/_psutil_posix.c new file mode 100644 index 00000000..707c55a1 --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_posix.c @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions specific to all POSIX compliant platforms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PSUTIL_SUNOS10 + #include "arch/solaris/v10/ifaddrs.h" +#else + #include +#endif + +#if defined(PSUTIL_LINUX) + #include + #include +#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX) + #include + #include + #include + #include + #include + #include +#elif defined(PSUTIL_SUNOS) + #include + #include +#endif + + +/* + * Given a PID return process priority as a Python integer. + */ +static PyObject * +psutil_posix_getpriority(PyObject *self, PyObject *args) { + long pid; + int priority; + errno = 0; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + +#ifdef PSUTIL_OSX + priority = getpriority(PRIO_PROCESS, (id_t)pid); +#else + priority = getpriority(PRIO_PROCESS, pid); +#endif + if (errno != 0) + return PyErr_SetFromErrno(PyExc_OSError); + return Py_BuildValue("i", priority); +} + + +/* + * Given a PID and a value change process priority. + */ +static PyObject * +psutil_posix_setpriority(PyObject *self, PyObject *args) { + long pid; + int priority; + int retval; + + if (! PyArg_ParseTuple(args, "li", &pid, &priority)) + return NULL; + +#ifdef PSUTIL_OSX + retval = setpriority(PRIO_PROCESS, (id_t)pid, priority); +#else + retval = setpriority(PRIO_PROCESS, pid, priority); +#endif + if (retval == -1) + return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} + + +/* + * Translate a sockaddr struct into a Python string. + * Return None if address family is not AF_INET* or AF_PACKET. + */ +static PyObject * +psutil_convert_ipaddr(struct sockaddr *addr, int family) { + char buf[NI_MAXHOST]; + int err; + int addrlen; + size_t n; + size_t len; + const char *data; + char *ptr; + + if (addr == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else if (family == AF_INET || family == AF_INET6) { + if (family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else + addrlen = sizeof(struct sockaddr_in6); + err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, + NI_NUMERICHOST); + if (err != 0) { + // XXX we get here on FreeBSD when processing 'lo' / AF_INET6 + // broadcast. Not sure what to do other than returning None. + // ifconfig does not show anything BTW. + //PyErr_Format(PyExc_RuntimeError, gai_strerror(err)); + //return NULL; + Py_INCREF(Py_None); + return Py_None; + } + else { + return Py_BuildValue("s", buf); + } + } +#ifdef PSUTIL_LINUX + else if (family == AF_PACKET) { + struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr; + len = lladdr->sll_halen; + data = (const char *)lladdr->sll_addr; + } +#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX) + else if (addr->sa_family == AF_LINK) { + // Note: prior to Python 3.4 socket module does not expose + // AF_LINK so we'll do. + struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr; + len = dladdr->sdl_alen; + data = LLADDR(dladdr); + } +#endif + else { + // unknown family + Py_INCREF(Py_None); + return Py_None; + } + + // AF_PACKET or AF_LINK + if (len > 0) { + ptr = buf; + for (n = 0; n < len; ++n) { + sprintf(ptr, "%02x:", data[n] & 0xff); + ptr += 3; + } + *--ptr = '\0'; + return Py_BuildValue("s", buf); + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} + + +/* + * Return NICs information a-la ifconfig as a list of tuples. + * TODO: on Solaris we won't get any MAC address. + */ +static PyObject* +psutil_net_if_addrs(PyObject* self, PyObject* args) { + struct ifaddrs *ifaddr, *ifa; + int family; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_netmask = NULL; + PyObject *py_broadcast = NULL; + PyObject *py_ptp = NULL; + + if (py_retlist == NULL) + return NULL; + if (getifaddrs(&ifaddr) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + family = ifa->ifa_addr->sa_family; + py_address = psutil_convert_ipaddr(ifa->ifa_addr, family); + // If the primary address can't be determined just skip it. + // I've never seen this happen on Linux but I did on FreeBSD. + if (py_address == Py_None) + continue; + if (py_address == NULL) + goto error; + py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family); + if (py_netmask == NULL) + goto error; + + if (ifa->ifa_flags & IFF_BROADCAST) { + py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family); + Py_INCREF(Py_None); + py_ptp = Py_None; + } + else if (ifa->ifa_flags & IFF_POINTOPOINT) { + py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family); + Py_INCREF(Py_None); + py_broadcast = Py_None; + } + else { + Py_INCREF(Py_None); + Py_INCREF(Py_None); + py_broadcast = Py_None; + py_ptp = Py_None; + } + + if ((py_broadcast == NULL) || (py_ptp == NULL)) + goto error; + py_tuple = Py_BuildValue( + "(siOOOO)", + ifa->ifa_name, + family, + py_address, + py_netmask, + py_broadcast, + py_ptp + ); + + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_address); + Py_DECREF(py_netmask); + Py_DECREF(py_broadcast); + Py_DECREF(py_ptp); + } + + freeifaddrs(ifaddr); + return py_retlist; + +error: + if (ifaddr != NULL) + freeifaddrs(ifaddr); + Py_DECREF(py_retlist); + Py_XDECREF(py_tuple); + Py_XDECREF(py_address); + Py_XDECREF(py_netmask); + Py_XDECREF(py_broadcast); + Py_XDECREF(py_ptp); + return NULL; +} + + +/* + * Return NIC MTU. References: + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject * +psutil_net_if_mtu(PyObject *self, PyObject *args) { + char *nic_name; + int sock = 0; + int ret; +#ifdef PSUTIL_SUNOS10 + struct lifreq lifr; +#else + struct ifreq ifr; +#endif + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + +#ifdef PSUTIL_SUNOS10 + strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name)); + ret = ioctl(sock, SIOCGIFMTU, &lifr); +#else + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFMTU, &ifr); +#endif + if (ret == -1) + goto error; + close(sock); + +#ifdef PSUTIL_SUNOS10 + return Py_BuildValue("i", lifr.lifr_mtu); +#else + return Py_BuildValue("i", ifr.ifr_mtu); +#endif + +error: + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Inspect NIC flags, returns a bool indicating whether the NIC is + * running. References: + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject * +psutil_net_if_flags(PyObject *self, PyObject *args) { + char *nic_name; + int sock = 0; + int ret; + struct ifreq ifr; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + goto error; + + close(sock); + if ((ifr.ifr_flags & IFF_UP) != 0) + return Py_BuildValue("O", Py_True); + else + return Py_BuildValue("O", Py_False); + +error: + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * net_if_stats() OSX/BSD implementation. + */ +#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) + +int psutil_get_nic_speed(int ifm_active) { + // Determine NIC speed. Taken from: + // http://www.i-scream.org/libstatgrab/ + // Assuming only ETHER devices + switch(IFM_TYPE(ifm_active)) { + case IFM_ETHER: + switch(IFM_SUBTYPE(ifm_active)) { +#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \ + || (IFM_10G_LR != IFM_HPNA_1)) + // HomePNA 1.0 (1Mb/s) + case(IFM_HPNA_1): + return 1; +#endif + // 10 Mbit + case(IFM_10_T): // 10BaseT - RJ45 + case(IFM_10_2): // 10Base2 - Thinnet + case(IFM_10_5): // 10Base5 - AUI + case(IFM_10_STP): // 10BaseT over shielded TP + case(IFM_10_FL): // 10baseFL - Fiber + return 10; + // 100 Mbit + case(IFM_100_TX): // 100BaseTX - RJ45 + case(IFM_100_FX): // 100BaseFX - Fiber + case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3 + case(IFM_100_VG): // 100VG-AnyLAN + case(IFM_100_T2): // 100BaseT2 + return 100; + // 1000 Mbit + case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber + case(IFM_1000_LX): // 1000baseLX - single-mode fiber + case(IFM_1000_CX): // 1000baseCX - 150ohm STP +#if defined(IFM_1000_TX) && !defined(PSUTIL_OPENBSD) + // FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h + case(IFM_1000_TX): +#endif +#ifdef IFM_1000_FX + case(IFM_1000_FX): +#endif +#ifdef IFM_1000_T + case(IFM_1000_T): +#endif + return 1000; +#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \ + || defined(IFM_10G_T) +#ifdef IFM_10G_SR + case(IFM_10G_SR): +#endif +#ifdef IFM_10G_LR + case(IFM_10G_LR): +#endif +#ifdef IFM_10G_CX4 + case(IFM_10G_CX4): +#endif +#ifdef IFM_10G_TWINAX + case(IFM_10G_TWINAX): +#endif +#ifdef IFM_10G_TWINAX_LONG + case(IFM_10G_TWINAX_LONG): +#endif +#ifdef IFM_10G_T + case(IFM_10G_T): +#endif + return 10000; +#endif +#if defined(IFM_2500_SX) +#ifdef IFM_2500_SX + case(IFM_2500_SX): +#endif + return 2500; +#endif // any 2.5GBit stuff... + // We don't know what it is + default: + return 0; + } + break; + +#ifdef IFM_TOKEN + case IFM_TOKEN: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9 + case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45 + return 4; + case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9 + case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45 + return 16; +#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100) +#ifdef IFM_TOK_STP100 + case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9 +#endif +#ifdef IFM_TOK_UTP100 + case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45 +#endif + return 100; +#endif + // We don't know what it is + default: + return 0; + } + break; +#endif + +#ifdef IFM_FDDI + case IFM_FDDI: + switch(IFM_SUBTYPE(ifm_active)) { + // We don't know what it is + default: + return 0; + } + break; +#endif + case IFM_IEEE80211: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps + case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps + return 1; + case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps + case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps + return 2; + case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps + return 5; + case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps + return 11; + case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps + return 22; + // We don't know what it is + default: + return 0; + } + break; + + default: + return 0; + } +} + + +/* + * Return stats about a particular network interface. + * References: + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject * +psutil_net_if_duplex_speed(PyObject *self, PyObject *args) { + char *nic_name; + int sock = 0; + int ret; + int duplex; + int speed; + struct ifreq ifr; + struct ifmediareq ifmed; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + + // speed / duplex + memset(&ifmed, 0, sizeof(struct ifmediareq)); + strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name)); + ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed); + if (ret == -1) { + speed = 0; + duplex = 0; + } + else { + speed = psutil_get_nic_speed(ifmed.ifm_active); + if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active) + duplex = 2; + else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active) + duplex = 1; + else + duplex = 0; + } + + close(sock); + return Py_BuildValue("[ii]", duplex, speed); + +error: + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} +#endif // net_if_stats() OSX/BSD implementation + + +/* + * define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = { + {"getpriority", psutil_posix_getpriority, METH_VARARGS, + "Return process priority"}, + {"setpriority", psutil_posix_setpriority, METH_VARARGS, + "Set process priority"}, + {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, + "Retrieve NICs information"}, + {"net_if_mtu", psutil_net_if_mtu, METH_VARARGS, + "Retrieve NIC MTU"}, + {"net_if_flags", psutil_net_if_flags, METH_VARARGS, + "Retrieve NIC flags"}, +#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) + {"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS, + "Return NIC stats."}, +#endif + {NULL, NULL, 0, NULL} +}; + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + + +static int +psutil_posix_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_posix", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_posix_traverse, + psutil_posix_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_posix(void) + +#else +#define INITERROR return + +void init_psutil_posix(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); +#endif + +#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) + PyModule_AddIntConstant(module, "AF_LINK", AF_LINK); +#endif + + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_psutil_posix.h b/pipenv/vendor/psutil/_psutil_posix.h new file mode 100644 index 00000000..86708f4b --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_posix.h @@ -0,0 +1,5 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ diff --git a/pipenv/vendor/psutil/_psutil_sunos.c b/pipenv/vendor/psutil/_psutil_sunos.c new file mode 100644 index 00000000..48767add --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_sunos.c @@ -0,0 +1,1539 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions specific to Sun OS Solaris platforms. + * + * Thanks to Justin Venus who originally wrote a consistent part of + * this in Cython which I later on translated in C. + */ + + +#include + +// fix for "Cannot use procfs in the large file compilation environment" +// error, see: +// http://sourceware.org/ml/gdb-patches/2010-11/msg00336.html +#undef _FILE_OFFSET_BITS +#define _STRUCTURED_PROC 1 + +// fix compilation issue on SunOS 5.10, see: +// https://github.com/giampaolo/psutil/issues/421 +#define NEW_MIB_COMPLIANT + +#include +#include +#include +#include +#include +#include // for MNTTAB +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PSUTIL_TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec) +#ifndef EXPER_IP_AND_ALL_IRES +#define EXPER_IP_AND_ALL_IRES (1024+4) +#endif +// a signaler for connections without an actual status +static int PSUTIL_CONN_NONE = 128; + + +/* + * Read a file content and fills a C structure with it. + */ +int +psutil_file_to_struct(char *path, void *fstruct, size_t size) { + int fd; + size_t nbytes; + fd = open(path, O_RDONLY); + if (fd == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + return 0; + } + nbytes = read(fd, fstruct, size); + if (nbytes == -1) { + close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return 0; + } + if (nbytes != size) { + close(fd); + PyErr_SetString( + PyExc_RuntimeError, "read() file structure size mismatch"); + return 0; + } + close(fd); + return nbytes; +} + + +/* + * Return process ppid, rss, vms, ctime, nice, nthreads, status and tty + * as a Python tuple. + */ +static PyObject * +psutil_proc_basic_info(PyObject *self, PyObject *args) { + int pid; + char path[1000]; + psinfo_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + + sprintf(path, "%s/%i/psinfo", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + return Py_BuildValue("ikkdiiik", + info.pr_ppid, // parent pid + info.pr_rssize, // rss + info.pr_size, // vms + PSUTIL_TV2DOUBLE(info.pr_start), // create time + info.pr_lwp.pr_nice, // nice + info.pr_nlwp, // no. of threads + info.pr_lwp.pr_state, // status code + info.pr_ttydev // tty nr + ); +} + + +/* + * Return process name and args as a Python tuple. + */ +static PyObject * +psutil_proc_name_and_args(PyObject *self, PyObject *args) { + int pid; + char path[1000]; + psinfo_t info; + const char *procfs_path; + PyObject *py_name; + PyObject *py_args; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/psinfo", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + +#if PY_MAJOR_VERSION >= 3 + py_name = PyUnicode_DecodeFSDefault(info.pr_fname); + if (!py_name) + return NULL; + py_args = PyUnicode_DecodeFSDefault(info.pr_psargs); + if (!py_args) + return NULL; + return Py_BuildValue("OO", py_name, py_args); +#else + return Py_BuildValue("ss", info.pr_fname, info.pr_psargs); +#endif +} + + +/* + * Return process user and system CPU times as a Python tuple. + */ +static PyObject * +psutil_proc_cpu_times(PyObject *self, PyObject *args) { + int pid; + char path[1000]; + pstatus_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/status", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + // results are more precise than os.times() + return Py_BuildValue( + "(dddd)", + PSUTIL_TV2DOUBLE(info.pr_utime), + PSUTIL_TV2DOUBLE(info.pr_stime), + PSUTIL_TV2DOUBLE(info.pr_cutime), + PSUTIL_TV2DOUBLE(info.pr_cstime) + ); +} + + +/* + * Return what CPU the process is running on. + */ +static PyObject * +psutil_proc_cpu_num(PyObject *self, PyObject *args) { + int fd = NULL; + int pid; + char path[1000]; + struct prheader header; + struct lwpsinfo *lwp; + char *lpsinfo = NULL; + char *ptr = NULL; + int nent; + int size; + int proc_num; + size_t nbytes; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + + sprintf(path, "%s/%i/lpsinfo", procfs_path, pid); + fd = open(path, O_RDONLY); + if (fd == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + return NULL; + } + + // read header + nbytes = pread(fd, &header, sizeof(header), 0); + if (nbytes == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (nbytes != sizeof(header)) { + PyErr_SetString( + PyExc_RuntimeError, "read() file structure size mismatch"); + goto error; + } + + // malloc + nent = header.pr_nent; + size = header.pr_entsize * nent; + ptr = lpsinfo = malloc(size); + if (lpsinfo == NULL) { + PyErr_NoMemory(); + goto error; + } + + // read the rest + nbytes = pread(fd, lpsinfo, size, sizeof(header)); + if (nbytes == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (nbytes != size) { + PyErr_SetString( + PyExc_RuntimeError, "read() file structure size mismatch"); + goto error; + } + + // done + lwp = (lwpsinfo_t *)ptr; + proc_num = lwp->pr_onpro; + close(fd); + free(ptr); + free(lpsinfo); + return Py_BuildValue("i", proc_num); + +error: + if (fd != NULL) + close(fd); + if (ptr != NULL) + free(ptr); + if (lpsinfo != NULL) + free(lpsinfo); + return NULL; +} + + +/* + * Return process uids/gids as a Python tuple. + */ +static PyObject * +psutil_proc_cred(PyObject *self, PyObject *args) { + int pid; + char path[1000]; + prcred_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/cred", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + return Py_BuildValue("iiiiii", + info.pr_ruid, info.pr_euid, info.pr_suid, + info.pr_rgid, info.pr_egid, info.pr_sgid); +} + + +/* + * Return process uids/gids as a Python tuple. + */ +static PyObject * +psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { + int pid; + char path[1000]; + prusage_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/usage", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + return Py_BuildValue("kk", info.pr_vctx, info.pr_ictx); +} + + +/* + * Process IO counters. + * + * Commented out and left here as a reminder. Apparently we cannot + * retrieve process IO stats because: + * - 'pr_ioch' is a sum of chars read and written, with no distinction + * - 'pr_inblk' and 'pr_oublk', which should be the number of bytes + * read and written, hardly increase and according to: + * http://www.brendangregg.com/Perf/paper_diskubyp1.pdf + * ...they should be meaningless anyway. + * +static PyObject* +proc_io_counters(PyObject* self, PyObject* args) { + int pid; + char path[1000]; + prusage_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/usage", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + + // On Solaris we only have 'pr_ioch' which accounts for bytes read + // *and* written. + // 'pr_inblk' and 'pr_oublk' should be expressed in blocks of + // 8KB according to: + // http://www.brendangregg.com/Perf/paper_diskubyp1.pdf (pag. 8) + return Py_BuildValue("kkkk", + info.pr_ioch, + info.pr_ioch, + info.pr_inblk, + info.pr_oublk); +} + */ + + +/* + * Return information about a given process thread. + */ +static PyObject * +psutil_proc_query_thread(PyObject *self, PyObject *args) { + int pid, tid; + char path[1000]; + lwpstatus_t info; + const char *procfs_path; + + if (! PyArg_ParseTuple(args, "iis", &pid, &tid, &procfs_path)) + return NULL; + sprintf(path, "%s/%i/lwp/%i/lwpstatus", procfs_path, pid, tid); + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) + return NULL; + return Py_BuildValue("dd", + PSUTIL_TV2DOUBLE(info.pr_utime), + PSUTIL_TV2DOUBLE(info.pr_stime)); +} + + +/* + * Return information about system virtual memory. + */ +static PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { +// XXX (arghhh!) +// total/free swap mem: commented out as for some reason I can't +// manage to get the same results shown by "swap -l", despite the +// code below is exactly the same as: +// http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ +// cmd/swap/swap.c +// We're going to parse "swap -l" output from Python (sigh!) + +/* + struct swaptable *st; + struct swapent *swapent; + int i; + struct stat64 statbuf; + char *path; + char fullpath[MAXPATHLEN+1]; + int num; + + if ((num = swapctl(SC_GETNSWP, NULL)) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (num == 0) { + PyErr_SetString(PyExc_RuntimeError, "no swap devices configured"); + return NULL; + } + if ((st = malloc(num * sizeof(swapent_t) + sizeof (int))) == NULL) { + PyErr_SetString(PyExc_RuntimeError, "malloc failed"); + return NULL; + } + if ((path = malloc(num * MAXPATHLEN)) == NULL) { + PyErr_SetString(PyExc_RuntimeError, "malloc failed"); + return NULL; + } + swapent = st->swt_ent; + for (i = 0; i < num; i++, swapent++) { + swapent->ste_path = path; + path += MAXPATHLEN; + } + st->swt_n = num; + if ((num = swapctl(SC_LIST, st)) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + swapent = st->swt_ent; + long t = 0, f = 0; + for (i = 0; i < num; i++, swapent++) { + int diskblks_per_page =(int)(sysconf(_SC_PAGESIZE) >> DEV_BSHIFT); + t += (long)swapent->ste_pages; + f += (long)swapent->ste_free; + } + + free(st); + return Py_BuildValue("(kk)", t, f); +*/ + + kstat_ctl_t *kc; + kstat_t *k; + cpu_stat_t *cpu; + int cpu_count = 0; + int flag = 0; + uint_t sin = 0; + uint_t sout = 0; + + kc = kstat_open(); + if (kc == NULL) + return PyErr_SetFromErrno(PyExc_OSError);; + + k = kc->kc_chain; + while (k != NULL) { + if ((strncmp(k->ks_name, "cpu_stat", 8) == 0) && \ + (kstat_read(kc, k, NULL) != -1) ) + { + flag = 1; + cpu = (cpu_stat_t *) k->ks_data; + sin += cpu->cpu_vminfo.pgswapin; // num pages swapped in + sout += cpu->cpu_vminfo.pgswapout; // num pages swapped out + } + cpu_count += 1; + k = k->ks_next; + } + kstat_close(kc); + if (!flag) { + PyErr_SetString(PyExc_RuntimeError, "no swap device was found"); + return NULL; + } + return Py_BuildValue("(II)", sin, sout); +} + + +/* + * Return users currently connected on the system. + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) { + struct utmpx *ut; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_user_proc = NULL; + + if (py_retlist == NULL) + return NULL; + + while (NULL != (ut = getutxent())) { + if (ut->ut_type == USER_PROCESS) + py_user_proc = Py_True; + else + py_user_proc = Py_False; + py_tuple = Py_BuildValue( + "(sssfO)", + ut->ut_user, // username + ut->ut_line, // tty + ut->ut_host, // hostname + (float)ut->ut_tv.tv_sec, // tstamp + py_user_proc); // (bool) user process + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + endutent(); + + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (ut != NULL) + endutent(); + return NULL; +} + + +/* + * Return disk mounted partitions as a list of tuples including device, + * mount point and filesystem type. + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) { + FILE *file; + struct mnttab mt; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + + file = fopen(MNTTAB, "rb"); + if (file == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + while (getmntent(file, &mt) == 0) { + py_tuple = Py_BuildValue( + "(ssss)", + mt.mnt_special, // device + mt.mnt_mountp, // mount point + mt.mnt_fstype, // fs type + mt.mnt_mntopts); // options + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + + } + fclose(file); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (file != NULL) + fclose(file); + return NULL; +} + + +/* + * Return system-wide CPU times. + */ +static PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + kstat_ctl_t *kc; + kstat_t *ksp; + cpu_stat_t cs; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + kc = kstat_open(); + if (kc == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_module, "cpu_stat") == 0) { + if (kstat_read(kc, ksp, &cs) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + py_cputime = Py_BuildValue("ffff", + (float)cs.cpu_sysinfo.cpu[CPU_USER], + (float)cs.cpu_sysinfo.cpu[CPU_KERNEL], + (float)cs.cpu_sysinfo.cpu[CPU_IDLE], + (float)cs.cpu_sysinfo.cpu[CPU_WAIT]); + if (py_cputime == NULL) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + py_cputime = NULL; + } + } + + kstat_close(kc); + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + if (kc != NULL) + kstat_close(kc); + return NULL; +} + + +/* + * Return disk IO statistics. + */ +static PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_io_t kio; + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + + if (py_retdict == NULL) + return NULL; + kc = kstat_open(); + if (kc == NULL) { + PyErr_SetFromErrno(PyExc_OSError);; + goto error; + } + ksp = kc->kc_chain; + while (ksp != NULL) { + if (ksp->ks_type == KSTAT_TYPE_IO) { + if (strcmp(ksp->ks_class, "disk") == 0) { + if (kstat_read(kc, ksp, &kio) == -1) { + kstat_close(kc); + return PyErr_SetFromErrno(PyExc_OSError);; + } + py_disk_info = Py_BuildValue( + "(IIKKLL)", + kio.reads, + kio.writes, + kio.nread, + kio.nwritten, + kio.rtime / 1000 / 1000, // from nano to milli secs + kio.wtime / 1000 / 1000 // from nano to milli secs + ); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, ksp->ks_name, + py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + } + ksp = ksp->ks_next; + } + kstat_close(kc); + + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (kc != NULL) + kstat_close(kc); + return NULL; +} + + +/* + * Return process memory mappings. + */ +static PyObject * +psutil_proc_memory_maps(PyObject *self, PyObject *args) { + int pid; + int fd = -1; + char path[1000]; + char perms[10]; + char *name; + struct stat st; + pstatus_t status; + + prxmap_t *xmap = NULL, *p; + off_t size; + size_t nread; + int nmap; + uintptr_t pr_addr_sz; + uintptr_t stk_base_sz, brk_base_sz; + const char *procfs_path; + + PyObject *py_tuple = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) + goto error; + + sprintf(path, "%s/%i/status", procfs_path, pid); + if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) + goto error; + + sprintf(path, "%s/%i/xmap", procfs_path, pid); + if (stat(path, &st) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + size = st.st_size; + + fd = open(path, O_RDONLY); + if (fd == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + xmap = (prxmap_t *)malloc(size); + if (xmap == NULL) { + PyErr_NoMemory(); + goto error; + } + + nread = pread(fd, xmap, size, 0); + nmap = nread / sizeof(prxmap_t); + p = xmap; + + while (nmap) { + nmap -= 1; + if (p == NULL) { + p += 1; + continue; + } + + perms[0] = '\0'; + pr_addr_sz = p->pr_vaddr + p->pr_size; + + // perms + sprintf(perms, "%c%c%c%c%c%c", p->pr_mflags & MA_READ ? 'r' : '-', + p->pr_mflags & MA_WRITE ? 'w' : '-', + p->pr_mflags & MA_EXEC ? 'x' : '-', + p->pr_mflags & MA_SHARED ? 's' : '-', + p->pr_mflags & MA_NORESERVE ? 'R' : '-', + p->pr_mflags & MA_RESERVED1 ? '*' : ' '); + + // name + if (strlen(p->pr_mapname) > 0) { + name = p->pr_mapname; + } + else { + if ((p->pr_mflags & MA_ISM) || (p->pr_mflags & MA_SHM)) { + name = "[shmid]"; + } + else { + stk_base_sz = status.pr_stkbase + status.pr_stksize; + brk_base_sz = status.pr_brkbase + status.pr_brksize; + + if ((pr_addr_sz > status.pr_stkbase) && + (p->pr_vaddr < stk_base_sz)) { + name = "[stack]"; + } + else if ((p->pr_mflags & MA_ANON) && \ + (pr_addr_sz > status.pr_brkbase) && \ + (p->pr_vaddr < brk_base_sz)) { + name = "[heap]"; + } + else { + name = "[anon]"; + } + } + } + + py_tuple = Py_BuildValue( + "iisslll", + p->pr_vaddr, + pr_addr_sz, + perms, + name, + (long)p->pr_rss * p->pr_pagesize, + (long)p->pr_anon * p->pr_pagesize, + (long)p->pr_locked * p->pr_pagesize); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + + // increment pointer + p += 1; + } + + close(fd); + free(xmap); + return py_retlist; + +error: + if (fd != -1) + close(fd); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (xmap != NULL) + free(xmap); + return NULL; +} + + +/* + * Return a list of tuples for network I/O statistics. + */ +static PyObject * +psutil_net_io_counters(PyObject *self, PyObject *args) { + kstat_ctl_t *kc = NULL; + kstat_t *ksp; + kstat_named_t *rbytes, *wbytes, *rpkts, *wpkts, *ierrs, *oerrs; + int ret; + int sock = -1; + struct lifreq ifr; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + + if (py_retdict == NULL) + return NULL; + kc = kstat_open(); + if (kc == NULL) + goto error; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + ksp = kc->kc_chain; + while (ksp != NULL) { + if (ksp->ks_type != KSTAT_TYPE_NAMED) + goto next; + if (strcmp(ksp->ks_class, "net") != 0) + goto next; + // skip 'lo' (localhost) because it doesn't have the statistics we need + // and it makes kstat_data_lookup() fail + if (strcmp(ksp->ks_module, "lo") == 0) + goto next; + + // check if this is a network interface by sending a ioctl + strncpy(ifr.lifr_name, ksp->ks_name, sizeof(ifr.lifr_name)); + ret = ioctl(sock, SIOCGLIFFLAGS, &ifr); + if (ret == -1) + goto next; + + if (kstat_read(kc, ksp, NULL) == -1) { + errno = 0; + goto next; + } + + rbytes = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes"); + wbytes = (kstat_named_t *)kstat_data_lookup(ksp, "obytes"); + rpkts = (kstat_named_t *)kstat_data_lookup(ksp, "ipackets"); + wpkts = (kstat_named_t *)kstat_data_lookup(ksp, "opackets"); + ierrs = (kstat_named_t *)kstat_data_lookup(ksp, "ierrors"); + oerrs = (kstat_named_t *)kstat_data_lookup(ksp, "oerrors"); + + if ((rbytes == NULL) || (wbytes == NULL) || (rpkts == NULL) || + (wpkts == NULL) || (ierrs == NULL) || (oerrs == NULL)) + { + PyErr_SetString(PyExc_RuntimeError, "kstat_data_lookup() failed"); + goto error; + } + + if (rbytes->data_type == KSTAT_DATA_UINT64) + { + py_ifc_info = Py_BuildValue("(KKKKIIii)", + wbytes->value.ui64, + rbytes->value.ui64, + wpkts->value.ui64, + rpkts->value.ui64, + ierrs->value.ui32, + oerrs->value.ui32, + 0, // dropin not supported + 0 // dropout not supported + ); + } + else + { + py_ifc_info = Py_BuildValue("(IIIIIIii)", + wbytes->value.ui32, + rbytes->value.ui32, + wpkts->value.ui32, + rpkts->value.ui32, + ierrs->value.ui32, + oerrs->value.ui32, + 0, // dropin not supported + 0 // dropout not supported + ); + } + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + goto next; + +next: + ksp = ksp->ks_next; + } + + kstat_close(kc); + close(sock); + return py_retdict; + +error: + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (kc != NULL) + kstat_close(kc); + if (sock != -1) { + close(sock); + } + return NULL; +} + + +/* + * Return TCP and UDP connections opened by process. + * UNIX sockets are excluded. + * + * Thanks to: + * https://github.com/DavidGriffith/finx/blob/master/ + * nxsensor-3.5.0-1/src/sysdeps/solaris.c + * ...and: + * https://hg.java.net/hg/solaris~on-src/file/tip/usr/src/cmd/ + * cmd-inet/usr.bin/netstat/netstat.c + */ +static PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + long pid; + int sd = 0; + mib2_tcpConnEntry_t *tp = NULL; + mib2_udpEntry_t *ude; +#if defined(AF_INET6) + mib2_tcp6ConnEntry_t *tp6; + mib2_udp6Entry_t *ude6; +#endif + char buf[512]; + int i, flags, getcode, num_ent, state; + char lip[200], rip[200]; + int lport, rport; + int processed_pid; + int databuf_init = 0; + struct strbuf ctlbuf, databuf; + struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; + struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; + struct T_error_ack *tea = (struct T_error_ack *)buf; + struct opthdr *mibhdr; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + sd = open("/dev/arp", O_RDWR); + if (sd == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/dev/arp"); + goto error; + } + + /* + XXX - These 2 are used in ifconfig.c but they seem unnecessary + ret = ioctl(sd, I_PUSH, "tcp"); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + ret = ioctl(sd, I_PUSH, "udp"); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + */ + + // OK, this mess is basically copied and pasted from nxsensor project + // which copied and pasted it from netstat source code, mibget() + // function. Also see: + // http://stackoverflow.com/questions/8723598/ + tor->PRIM_type = T_SVR4_OPTMGMT_REQ; + tor->OPT_offset = sizeof (struct T_optmgmt_req); + tor->OPT_length = sizeof (struct opthdr); + tor->MGMT_flags = T_CURRENT; + mibhdr = (struct opthdr *)&tor[1]; + mibhdr->level = EXPER_IP_AND_ALL_IRES; + mibhdr->name = 0; + mibhdr->len = 0; + + ctlbuf.buf = buf; + ctlbuf.len = tor->OPT_offset + tor->OPT_length; + flags = 0; // request to be sent in non-priority + + if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + mibhdr = (struct opthdr *)&toa[1]; + ctlbuf.maxlen = sizeof (buf); + + for (;;) { + flags = 0; + getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags); + + if (getcode != MOREDATA || + ctlbuf.len < sizeof (struct T_optmgmt_ack) || + toa->PRIM_type != T_OPTMGMT_ACK || + toa->MGMT_flags != T_SUCCESS) + { + break; + } + if (ctlbuf.len >= sizeof (struct T_error_ack) && + tea->PRIM_type == T_ERROR_ACK) + { + PyErr_SetString(PyExc_RuntimeError, "ERROR_ACK"); + goto error; + } + if (getcode == 0 && + ctlbuf.len >= sizeof (struct T_optmgmt_ack) && + toa->PRIM_type == T_OPTMGMT_ACK && + toa->MGMT_flags == T_SUCCESS) + { + PyErr_SetString(PyExc_RuntimeError, "ERROR_T_OPTMGMT_ACK"); + goto error; + } + + databuf.maxlen = mibhdr->len; + databuf.len = 0; + databuf.buf = (char *)malloc((int)mibhdr->len); + if (!databuf.buf) { + PyErr_NoMemory(); + goto error; + } + databuf_init = 1; + + flags = 0; + getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags); + if (getcode < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // TCPv4 + if (mibhdr->level == MIB2_TCP && mibhdr->name == MIB2_TCP_13) { + tp = (mib2_tcpConnEntry_t *)databuf.buf; + num_ent = mibhdr->len / sizeof(mib2_tcpConnEntry_t); + for (i = 0; i < num_ent; i++, tp++) { + processed_pid = tp->tcpConnCreationProcess; + if (pid != -1 && processed_pid != pid) + continue; + // construct local/remote addresses + inet_ntop(AF_INET, &tp->tcpConnLocalAddress, lip, sizeof(lip)); + inet_ntop(AF_INET, &tp->tcpConnRemAddress, rip, sizeof(rip)); + lport = tp->tcpConnLocalPort; + rport = tp->tcpConnRemPort; + + // contruct python tuple/list + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else { + py_raddr = Py_BuildValue("()"); + } + if (!py_raddr) + goto error; + state = tp->tcpConnEntryInfo.ce_state; + + // add item + py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM, + py_laddr, py_raddr, state, + processed_pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } +#if defined(AF_INET6) + // TCPv6 + else if (mibhdr->level == MIB2_TCP6 && mibhdr->name == MIB2_TCP6_CONN) + { + tp6 = (mib2_tcp6ConnEntry_t *)databuf.buf; + num_ent = mibhdr->len / sizeof(mib2_tcp6ConnEntry_t); + + for (i = 0; i < num_ent; i++, tp6++) { + processed_pid = tp6->tcp6ConnCreationProcess; + if (pid != -1 && processed_pid != pid) + continue; + // construct local/remote addresses + inet_ntop(AF_INET6, &tp6->tcp6ConnLocalAddress, lip, sizeof(lip)); + inet_ntop(AF_INET6, &tp6->tcp6ConnRemAddress, rip, sizeof(rip)); + lport = tp6->tcp6ConnLocalPort; + rport = tp6->tcp6ConnRemPort; + + // contruct python tuple/list + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + state = tp6->tcp6ConnEntryInfo.ce_state; + + // add item + py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM, + py_laddr, py_raddr, state, processed_pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } +#endif + // UDPv4 + else if (mibhdr->level == MIB2_UDP || mibhdr->level == MIB2_UDP_ENTRY) { + ude = (mib2_udpEntry_t *)databuf.buf; + num_ent = mibhdr->len / sizeof(mib2_udpEntry_t); + for (i = 0; i < num_ent; i++, ude++) { + processed_pid = ude->udpCreationProcess; + if (pid != -1 && processed_pid != pid) + continue; + // XXX Very ugly hack! It seems we get here only the first + // time we bump into a UDPv4 socket. PID is a very high + // number (clearly impossible) and the address does not + // belong to any valid interface. Not sure what else + // to do other than skipping. + if (processed_pid > 131072) + continue; + inet_ntop(AF_INET, &ude->udpLocalAddress, lip, sizeof(lip)); + lport = ude->udpLocalPort; + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_DGRAM, + py_laddr, py_raddr, PSUTIL_CONN_NONE, + processed_pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } +#if defined(AF_INET6) + // UDPv6 + else if (mibhdr->level == MIB2_UDP6 || + mibhdr->level == MIB2_UDP6_ENTRY) + { + ude6 = (mib2_udp6Entry_t *)databuf.buf; + num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t); + for (i = 0; i < num_ent; i++, ude6++) { + processed_pid = ude6->udp6CreationProcess; + if (pid != -1 && processed_pid != pid) + continue; + inet_ntop(AF_INET6, &ude6->udp6LocalAddress, lip, sizeof(lip)); + lport = ude6->udp6LocalPort; + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM, + py_laddr, py_raddr, PSUTIL_CONN_NONE, + processed_pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } +#endif + free(databuf.buf); + } + + close(sd); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); + if (databuf_init == 1) + free(databuf.buf); + if (sd != 0) + close(sd); + return NULL; +} + + +static PyObject * +psutil_boot_time(PyObject *self, PyObject *args) { + float boot_time = 0.0; + struct utmpx *ut; + + while (NULL != (ut = getutxent())) { + if (ut->ut_type == BOOT_TIME) { + boot_time = (float)ut->ut_tv.tv_sec; + break; + } + } + endutent(); + if (boot_time != 0.0) { + return Py_BuildValue("f", boot_time); + } + else { + PyErr_SetString(PyExc_RuntimeError, "can't determine boot time"); + return NULL; + } +} + + +/* + * Return the number of physical CPU cores on the system. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + kstat_ctl_t *kc; + kstat_t *ksp; + int ncpus = 0; + + kc = kstat_open(); + if (kc == NULL) + goto error; + ksp = kstat_lookup(kc, "cpu_info", -1, NULL); + if (ksp == NULL) + goto error; + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_module, "cpu_info") != 0) + continue; + if (kstat_read(kc, ksp, NULL) == -1) + goto error; + ncpus += 1; + } + + kstat_close(kc); + if (ncpus > 0) + return Py_BuildValue("i", ncpus); + else + goto error; + +error: + // mimic os.cpu_count() + if (kc != NULL) + kstat_close(kc); + Py_RETURN_NONE; +} + + +/* + * Return stats about a particular network + * interface. References: + * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject* +psutil_net_if_stats(PyObject* self, PyObject* args) { + kstat_ctl_t *kc = NULL; + kstat_t *ksp; + kstat_named_t *knp; + int ret; + int sock = -1; + int duplex; + int speed; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + PyObject *py_is_up = NULL; + + if (py_retdict == NULL) + return NULL; + kc = kstat_open(); + if (kc == NULL) + goto error; + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_class, "net") == 0) { + struct lifreq ifr; + + kstat_read(kc, ksp, NULL); + if (ksp->ks_type != KSTAT_TYPE_NAMED) + continue; + if (strcmp(ksp->ks_class, "net") != 0) + continue; + + strncpy(ifr.lifr_name, ksp->ks_name, sizeof(ifr.lifr_name)); + ret = ioctl(sock, SIOCGLIFFLAGS, &ifr); + if (ret == -1) + continue; // not a network interface + + // is up? + if ((ifr.lifr_flags & IFF_UP) != 0) { + if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) { + if (knp->value.ui32 != 0u) + py_is_up = Py_True; + else + py_is_up = Py_False; + } + else { + py_is_up = Py_True; + } + } + else { + py_is_up = Py_False; + } + Py_INCREF(py_is_up); + + // duplex + duplex = 0; // unknown + if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) { + if (knp->value.ui32 == 1) + duplex = 1; // half + else if (knp->value.ui32 == 2) + duplex = 2; // full + } + + // speed + if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) + // expressed in bits per sec, we want mega bits per sec + speed = (int)knp->value.ui64 / 1000000; + else + speed = 0; + + // mtu + ret = ioctl(sock, SIOCGLIFMTU, &ifr); + if (ret == -1) + goto error; + + py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed, + ifr.lifr_mtu); + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + } + + close(sock); + kstat_close(kc); + return py_retdict; + +error: + Py_XDECREF(py_is_up); + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (sock != -1) + close(sock); + if (kc != NULL) + kstat_close(kc); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Return CPU statistics. + */ +static PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + kstat_ctl_t *kc; + kstat_t *ksp; + cpu_stat_t cs; + unsigned int ctx_switches = 0; + unsigned int interrupts = 0; + unsigned int traps = 0; + unsigned int syscalls = 0; + + kc = kstat_open(); + if (kc == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_module, "cpu_stat") == 0) { + if (kstat_read(kc, ksp, &cs) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + // voluntary + involuntary + ctx_switches += cs.cpu_sysinfo.pswitch + cs.cpu_sysinfo.inv_swtch; + interrupts += cs.cpu_sysinfo.intr; + traps += cs.cpu_sysinfo.trap; + syscalls += cs.cpu_sysinfo.syscall; + } + } + + kstat_close(kc); + return Py_BuildValue( + "IIII", ctx_switches, interrupts, syscalls, traps); + +error: + if (kc != NULL) + kstat_close(kc); + return NULL; +} + + +/* + * define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = { + + // --- process-related functions + {"proc_basic_info", psutil_proc_basic_info, METH_VARARGS, + "Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"}, + {"proc_name_and_args", psutil_proc_name_and_args, METH_VARARGS, + "Return process name and args."}, + {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, + "Return process user and system CPU times."}, + {"proc_cred", psutil_proc_cred, METH_VARARGS, + "Return process uids/gids."}, + {"query_process_thread", psutil_proc_query_thread, METH_VARARGS, + "Return info about a process thread"}, + {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, + "Return process memory mappings"}, + {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, + "Return the number of context switches performed by process"}, + {"proc_cpu_num", psutil_proc_cpu_num, METH_VARARGS, + "Return what CPU the process is on"}, + + // --- system-related functions + {"swap_mem", psutil_swap_mem, METH_VARARGS, + "Return information about system swap memory."}, + {"users", psutil_users, METH_VARARGS, + "Return currently connected users."}, + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return disk partitions."}, + {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, + "Return system per-CPU times."}, + {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, + "Return a Python dict of tuples for disk I/O statistics."}, + {"net_io_counters", psutil_net_io_counters, METH_VARARGS, + "Return a Python dict of tuples for network I/O statistics."}, + {"boot_time", psutil_boot_time, METH_VARARGS, + "Return system boot time in seconds since the EPOCH."}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Return the number of physical CPUs on the system."}, + {"net_connections", psutil_net_connections, METH_VARARGS, + "Return TCP and UDP syste-wide open connections."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats (isup, duplex, speed, mtu)"}, + {"cpu_stats", psutil_cpu_stats, METH_VARARGS, + "Return CPU statistics"}, + + {NULL, NULL, 0, NULL} +}; + + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_sunos_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int +psutil_sunos_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_sunos", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_sunos_traverse, + psutil_sunos_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_sunos(void) + +#else +#define INITERROR return + +void init_psutil_sunos(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_sunos", PsutilMethods); +#endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SONPROC", SONPROC); + PyModule_AddIntConstant(module, "SWAIT", SWAIT); + + PyModule_AddIntConstant(module, "PRNODEV", PRNODEV); // for process tty + + PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); + PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); + PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); + PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); + PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); + PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); + PyModule_AddIntConstant(module, "TCPS_SYN_RCVD", TCPS_SYN_RCVD); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); + PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); + PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); + // sunos specific + PyModule_AddIntConstant(module, "TCPS_IDLE", TCPS_IDLE); + // sunos specific + PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND); + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); + + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_psutil_windows.c b/pipenv/vendor/psutil/_psutil_windows.c new file mode 100644 index 00000000..430f518e --- /dev/null +++ b/pipenv/vendor/psutil/_psutil_windows.c @@ -0,0 +1,3775 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Windows platform-specific module methods for _psutil_windows + */ + +// Fixes clash between winsock2.h and windows.h +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above +#include +#endif +#include +#include +#include +#include + +// Link with Iphlpapi.lib +#pragma comment(lib, "IPHLPAPI.lib") + +#include "_psutil_common.h" +#include "arch/windows/security.h" +#include "arch/windows/process_info.h" +#include "arch/windows/process_handles.h" +#include "arch/windows/ntextapi.h" +#include "arch/windows/inet_ntop.h" +#include "arch/windows/services.h" + +#ifdef __MINGW32__ +#include "arch/windows/glpi.h" +#endif + + +/* + * ============================================================================ + * Utilities + * ============================================================================ + */ + + // a flag for connections without an actual status +static int PSUTIL_CONN_NONE = 128; + +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) +#define LO_T ((float)1e-7) +#define HI_T (LO_T*4294967296.0) +#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) +#ifndef AF_INET6 +#define AF_INET6 23 +#endif +#define _psutil_conn_decref_objs() \ + Py_DECREF(_AF_INET); \ + Py_DECREF(_AF_INET6);\ + Py_DECREF(_SOCK_STREAM);\ + Py_DECREF(_SOCK_DGRAM); + +typedef BOOL (WINAPI *LPFN_GLPI) + (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + +// fix for mingw32, see +// https://github.com/giampaolo/psutil/issues/351#c2 +typedef struct _DISK_PERFORMANCE_WIN_2008 { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + DWORD ReadCount; + DWORD WriteCount; + DWORD QueueDepth; + DWORD SplitCount; + LARGE_INTEGER QueryTime; + DWORD StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE_WIN_2008; + +// --- network connections mingw32 support +#ifndef _IPRTRMIB_H +#if (_WIN32_WINNT < 0x0600) // Windows XP +typedef struct _MIB_TCP6ROW_OWNER_PID { + UCHAR ucLocalAddr[16]; + DWORD dwLocalScopeId; + DWORD dwLocalPort; + UCHAR ucRemoteAddr[16]; + DWORD dwRemoteScopeId; + DWORD dwRemotePort; + DWORD dwState; + DWORD dwOwningPid; +} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; + +typedef struct _MIB_TCP6TABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; +} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; +#endif +#endif + +#ifndef __IPHLPAPI_H__ +typedef struct in6_addr { + union { + UCHAR Byte[16]; + USHORT Word[8]; + } u; +} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; + +typedef enum _UDP_TABLE_CLASS { + UDP_TABLE_BASIC, + UDP_TABLE_OWNER_PID, + UDP_TABLE_OWNER_MODULE +} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; + +typedef struct _MIB_UDPROW_OWNER_PID { + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwOwningPid; +} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; + +typedef struct _MIB_UDPTABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_UDPROW_OWNER_PID table[ANY_SIZE]; +} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; +#endif + +#if (_WIN32_WINNT < 0x0600) // Windows XP +typedef struct _MIB_UDP6ROW_OWNER_PID { + UCHAR ucLocalAddr[16]; + DWORD dwLocalScopeId; + DWORD dwLocalPort; + DWORD dwOwningPid; +} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; + +typedef struct _MIB_UDP6TABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; +} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; +#endif + +typedef struct _PROCESSOR_POWER_INFORMATION { + ULONG Number; + ULONG MaxMhz; + ULONG CurrentMhz; + ULONG MhzLimit; + ULONG MaxIdleState; + ULONG CurrentIdleState; +} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION; + + +PIP_ADAPTER_ADDRESSES +psutil_get_nic_addresses() { + // allocate a 15 KB buffer to start with + int outBufLen = 15000; + DWORD dwRetVal = 0; + ULONG attempts = 0; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + + do { + pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); + if (pAddresses == NULL) { + PyErr_NoMemory(); + return NULL; + } + + dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, + &outBufLen); + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = NULL; + } + else { + break; + } + + attempts++; + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); + + if (dwRetVal != NO_ERROR) { + PyErr_SetString( + PyExc_RuntimeError, "GetAdaptersAddresses() syscall failed."); + return NULL; + } + + return pAddresses; +} + + +/* + * ============================================================================ + * Public Python API + * ============================================================================ + */ + + +static ULONGLONG (*psutil_GetTickCount64)(void) = NULL; + +/* + * Return a Python float representing the system uptime expressed in seconds + * since the epoch. + */ +static PyObject * +psutil_boot_time(PyObject *self, PyObject *args) { +#if (_WIN32_WINNT >= 0x0600) // Windows Vista + ULONGLONG uptime; +#else + double uptime; +#endif + time_t pt; + FILETIME fileTime; + long long ll; + HINSTANCE hKernel32; + psutil_GetTickCount64 = NULL; + + GetSystemTimeAsFileTime(&fileTime); + + /* + HUGE thanks to: + http://johnstewien.spaces.live.com/blog/cns!E6885DB5CEBABBC8!831.entry + + This function converts the FILETIME structure to the 32 bit + Unix time structure. + The time_t is a 32-bit value for the number of seconds since + January 1, 1970. A FILETIME is a 64-bit for the number of + 100-nanosecond periods since January 1, 1601. Convert by + subtracting the number of 100-nanosecond period betwee 01-01-1970 + and 01-01-1601, from time_t the divide by 1e+7 to get to the same + base granularity. + */ + ll = (((LONGLONG)(fileTime.dwHighDateTime)) << 32) \ + + fileTime.dwLowDateTime; + pt = (time_t)((ll - 116444736000000000ull) / 10000000ull); + + // GetTickCount64() is Windows Vista+ only. Dinamically load + // GetTickCount64() at runtime. We may have used + // "#if (_WIN32_WINNT >= 0x0600)" pre-processor but that way + // the produced exe/wheels cannot be used on Windows XP, see: + // https://github.com/giampaolo/psutil/issues/811#issuecomment-230639178 + hKernel32 = GetModuleHandleW(L"KERNEL32"); + psutil_GetTickCount64 = (void*)GetProcAddress(hKernel32, "GetTickCount64"); + if (psutil_GetTickCount64 != NULL) { + // Windows >= Vista + uptime = psutil_GetTickCount64() / (ULONGLONG)1000.00f; + } + else { + // Windows XP. + // GetTickCount() time will wrap around to zero if the + // system is run continuously for 49.7 days. + uptime = GetTickCount() / 1000.00f; + } + + return Py_BuildValue("d", (double)pt - (double)uptime); +} + + +/* + * Return 1 if PID exists in the current process list, else 0. + */ +static PyObject * +psutil_pid_exists(PyObject *self, PyObject *args) { + long pid; + int status; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + status = psutil_pid_is_running(pid); + if (-1 == status) + return NULL; // exception raised in psutil_pid_is_running() + return PyBool_FromLong(status); +} + + +/* + * Return a Python list of all the PIDs running on the system. + */ +static PyObject * +psutil_pids(PyObject *self, PyObject *args) { + DWORD *proclist = NULL; + DWORD numberOfReturnedPIDs; + DWORD i; + PyObject *py_pid = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + proclist = psutil_get_pids(&numberOfReturnedPIDs); + if (proclist == NULL) + goto error; + + for (i = 0; i < numberOfReturnedPIDs; i++) { + py_pid = Py_BuildValue("I", proclist[i]); + if (!py_pid) + goto error; + if (PyList_Append(py_retlist, py_pid)) + goto error; + Py_DECREF(py_pid); + } + + // free C array allocated for PIDs + free(proclist); + return py_retlist; + +error: + Py_XDECREF(py_pid); + Py_DECREF(py_retlist); + if (proclist != NULL) + free(proclist); + return NULL; +} + + +/* + * Kill a process given its PID. + */ +static PyObject * +psutil_proc_kill(PyObject *self, PyObject *args) { + HANDLE hProcess; + long pid; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (pid == 0) + return AccessDenied(); + + hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); + if (hProcess == NULL) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + // see https://github.com/giampaolo/psutil/issues/24 + NoSuchProcess(); + } + else { + PyErr_SetFromWindowsErr(0); + } + return NULL; + } + + // kill the process + if (! TerminateProcess(hProcess, 0)) { + PyErr_SetFromWindowsErr(0); + CloseHandle(hProcess); + return NULL; + } + + CloseHandle(hProcess); + Py_RETURN_NONE; +} + + +/* + * Wait for process to terminate and return its exit code. + */ +static PyObject * +psutil_proc_wait(PyObject *self, PyObject *args) { + HANDLE hProcess; + DWORD ExitCode; + DWORD retVal; + long pid; + long timeout; + + if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) + return NULL; + if (pid == 0) + return AccessDenied(); + + hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, + FALSE, pid); + if (hProcess == NULL) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + // no such process; we do not want to raise NSP but + // return None instead. + Py_RETURN_NONE; + } + else { + PyErr_SetFromWindowsErr(0); + return NULL; + } + } + + // wait until the process has terminated + Py_BEGIN_ALLOW_THREADS + retVal = WaitForSingleObject(hProcess, timeout); + Py_END_ALLOW_THREADS + + if (retVal == WAIT_FAILED) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(GetLastError()); + } + if (retVal == WAIT_TIMEOUT) { + CloseHandle(hProcess); + return Py_BuildValue("l", WAIT_TIMEOUT); + } + + // get the exit code; note: subprocess module (erroneously?) uses + // what returned by WaitForSingleObject + if (GetExitCodeProcess(hProcess, &ExitCode) == 0) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(GetLastError()); + } + CloseHandle(hProcess); +#if PY_MAJOR_VERSION >= 3 + return PyLong_FromLong((long) ExitCode); +#else + return PyInt_FromLong((long) ExitCode); +#endif +} + + +/* + * Return a Python tuple (user_time, kernel_time) + */ +static PyObject * +psutil_proc_cpu_times(PyObject *self, PyObject *args) { + long pid; + HANDLE hProcess; + FILETIME ftCreate, ftExit, ftKernel, ftUser; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) + return NULL; + if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { + CloseHandle(hProcess); + if (GetLastError() == ERROR_ACCESS_DENIED) { + // usually means the process has died so we throw a NoSuchProcess + // here + return NoSuchProcess(); + } + else { + PyErr_SetFromWindowsErr(0); + return NULL; + } + } + + CloseHandle(hProcess); + + /* + * User and kernel times are represented as a FILETIME structure + * wich contains a 64-bit value representing the number of + * 100-nanosecond intervals since January 1, 1601 (UTC): + * http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx + * To convert it into a float representing the seconds that the + * process has executed in user/kernel mode I borrowed the code + * below from Python's Modules/posixmodule.c + */ + return Py_BuildValue( + "(dd)", + (double)(ftUser.dwHighDateTime * 429.4967296 + \ + ftUser.dwLowDateTime * 1e-7), + (double)(ftKernel.dwHighDateTime * 429.4967296 + \ + ftKernel.dwLowDateTime * 1e-7) + ); +} + + +/* + * Return a Python float indicating the process create time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_proc_create_time(PyObject *self, PyObject *args) { + long pid; + long long unix_time; + DWORD exitCode; + HANDLE hProcess; + BOOL ret; + FILETIME ftCreate, ftExit, ftKernel, ftUser; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + // special case for PIDs 0 and 4, return system boot time + if (0 == pid || 4 == pid) + return psutil_boot_time(NULL, NULL); + + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) + return NULL; + if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { + CloseHandle(hProcess); + if (GetLastError() == ERROR_ACCESS_DENIED) { + // usually means the process has died so we throw a + // NoSuchProcess here + return NoSuchProcess(); + } + else { + PyErr_SetFromWindowsErr(0); + return NULL; + } + } + + // Make sure the process is not gone as OpenProcess alone seems to be + // unreliable in doing so (it seems a previous call to p.wait() makes + // it unreliable). + // This check is important as creation time is used to make sure the + // process is still running. + ret = GetExitCodeProcess(hProcess, &exitCode); + CloseHandle(hProcess); + if (ret != 0) { + if (exitCode != STILL_ACTIVE) + return NoSuchProcess(); + } + else { + // Ignore access denied as it means the process is still alive. + // For all other errors, we want an exception. + if (GetLastError() != ERROR_ACCESS_DENIED) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + } + + /* + Convert the FILETIME structure to a Unix time. + It's the best I could find by googling and borrowing code here and there. + The time returned has a precision of 1 second. + */ + unix_time = ((LONGLONG)ftCreate.dwHighDateTime) << 32; + unix_time += ftCreate.dwLowDateTime - 116444736000000000LL; + unix_time /= 10000000; + return Py_BuildValue("d", (double)unix_time); +} + + + +/* + * Return the number of logical CPUs. + */ +static PyObject * +psutil_cpu_count_logical(PyObject *self, PyObject *args) { + SYSTEM_INFO system_info; + system_info.dwNumberOfProcessors = 0; + + GetSystemInfo(&system_info); + if (system_info.dwNumberOfProcessors == 0) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("I", system_info.dwNumberOfProcessors); +} + + +/* + * Return the number of physical CPU cores. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + LPFN_GLPI glpi; + DWORD rc; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; + DWORD length = 0; + DWORD offset = 0; + int ncpus = 0; + + glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), + "GetLogicalProcessorInformation"); + if (glpi == NULL) + goto return_none; + + while (1) { + rc = glpi(buffer, &length); + if (rc == FALSE) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if (buffer) + free(buffer); + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( + length); + if (NULL == buffer) { + PyErr_NoMemory(); + return NULL; + } + } + else { + goto return_none; + } + } + else { + break; + } + } + + ptr = buffer; + while (offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= length) { + if (ptr->Relationship == RelationProcessorCore) + ncpus += 1; + offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + ptr++; + } + + free(buffer); + if (ncpus == 0) + goto return_none; + else + return Py_BuildValue("i", ncpus); + +return_none: + // mimic os.cpu_count() + if (buffer != NULL) + free(buffer); + Py_RETURN_NONE; +} + + +/* + * Return process cmdline as a Python list of cmdline arguments. + */ +static PyObject * +psutil_proc_cmdline(PyObject *self, PyObject *args) { + long pid; + int pid_return; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if ((pid == 0) || (pid == 4)) + return Py_BuildValue("[]"); + + pid_return = psutil_pid_is_running(pid); + if (pid_return == 0) + return NoSuchProcess(); + if (pid_return == -1) + return NULL; + + return psutil_get_cmdline(pid); +} + + +/* + * Return process cmdline as a Python list of cmdline arguments. + */ +static PyObject * +psutil_proc_environ(PyObject *self, PyObject *args) { + long pid; + int pid_return; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if ((pid == 0) || (pid == 4)) + return Py_BuildValue("s", ""); + + pid_return = psutil_pid_is_running(pid); + if (pid_return == 0) + return NoSuchProcess(); + if (pid_return == -1) + return NULL; + + return psutil_get_environ(pid); +} + + +/* + * Return process executable path. + */ +static PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { + long pid; + HANDLE hProcess; + wchar_t exe[MAX_PATH]; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); + if (NULL == hProcess) + return NULL; + if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { + CloseHandle(hProcess); + PyErr_SetFromWindowsErr(0); + return NULL; + } + CloseHandle(hProcess); + return Py_BuildValue("u", exe); +} + + +/* + * Return process base name. + * Note: psutil_proc_exe() is attempted first because it's faster + * but it raise AccessDenied for processes owned by other users + * in which case we fall back on using this. + */ +static PyObject * +psutil_proc_name(PyObject *self, PyObject *args) { + long pid; + int ok; + PROCESSENTRY32W pentry; + HANDLE hSnapShot; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); + if (hSnapShot == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + pentry.dwSize = sizeof(PROCESSENTRY32W); + ok = Process32FirstW(hSnapShot, &pentry); + if (! ok) { + CloseHandle(hSnapShot); + PyErr_SetFromWindowsErr(0); + return NULL; + } + while (ok) { + if (pentry.th32ProcessID == pid) { + CloseHandle(hSnapShot); + return PyUnicode_FromWideChar( + pentry.szExeFile, wcslen(pentry.szExeFile)); + } + ok = Process32NextW(hSnapShot, &pentry); + } + + CloseHandle(hSnapShot); + NoSuchProcess(); + return NULL; +} + + +/* + * Return process memory information as a Python tuple. + */ +static PyObject * +psutil_proc_memory_info(PyObject *self, PyObject *args) { + HANDLE hProcess; + DWORD pid; +#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 + PROCESS_MEMORY_COUNTERS_EX cnt; +#else + PROCESS_MEMORY_COUNTERS cnt; +#endif + SIZE_T private = 0; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + hProcess = psutil_handle_from_pid(pid); + if (NULL == hProcess) + return NULL; + + if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, + sizeof(cnt))) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(0); + } + +#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 + private = cnt.PrivateUsage; +#endif + + CloseHandle(hProcess); + + // PROCESS_MEMORY_COUNTERS values are defined as SIZE_T which on 64bits + // is an (unsigned long long) and on 32bits is an (unsigned int). + // "_WIN64" is defined if we're running a 64bit Python interpreter not + // exclusively if the *system* is 64bit. +#if defined(_WIN64) + return Py_BuildValue( + "(kKKKKKKKKK)", + cnt.PageFaultCount, // unsigned long + (unsigned long long)cnt.PeakWorkingSetSize, + (unsigned long long)cnt.WorkingSetSize, + (unsigned long long)cnt.QuotaPeakPagedPoolUsage, + (unsigned long long)cnt.QuotaPagedPoolUsage, + (unsigned long long)cnt.QuotaPeakNonPagedPoolUsage, + (unsigned long long)cnt.QuotaNonPagedPoolUsage, + (unsigned long long)cnt.PagefileUsage, + (unsigned long long)cnt.PeakPagefileUsage, + (unsigned long long)private); +#else + return Py_BuildValue( + "(kIIIIIIIII)", + cnt.PageFaultCount, // unsigned long + (unsigned int)cnt.PeakWorkingSetSize, + (unsigned int)cnt.WorkingSetSize, + (unsigned int)cnt.QuotaPeakPagedPoolUsage, + (unsigned int)cnt.QuotaPagedPoolUsage, + (unsigned int)cnt.QuotaPeakNonPagedPoolUsage, + (unsigned int)cnt.QuotaNonPagedPoolUsage, + (unsigned int)cnt.PagefileUsage, + (unsigned int)cnt.PeakPagefileUsage, + (unsigned int)private); +#endif +} + + + +/** + * Returns the USS of the process. + * Reference: + * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ + * nsMemoryReporterManager.cpp + */ +static PyObject * +psutil_proc_memory_uss(PyObject *self, PyObject *args) +{ + DWORD pid; + HANDLE proc; + PSAPI_WORKING_SET_INFORMATION tmp; + DWORD tmp_size = sizeof(tmp); + size_t entries; + size_t private_pages; + size_t i; + DWORD info_array_size; + PSAPI_WORKING_SET_INFORMATION* info_array; + SYSTEM_INFO system_info; + PyObject* py_result = NULL; + unsigned long long total = 0; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + proc = psutil_handle_from_pid(pid); + if (proc == NULL) + return NULL; + + // Determine how many entries we need. + memset(&tmp, 0, tmp_size); + if (!QueryWorkingSet(proc, &tmp, tmp_size)) { + // NB: QueryWorkingSet is expected to fail here due to the + // buffer being too small. + if (tmp.NumberOfEntries == 0) { + PyErr_SetFromWindowsErr(0); + goto done; + } + } + + // Fudge the size in case new entries are added between calls. + entries = tmp.NumberOfEntries * 2; + + if (!entries) { + goto done; + } + + info_array_size = tmp_size + (entries * sizeof(PSAPI_WORKING_SET_BLOCK)); + info_array = (PSAPI_WORKING_SET_INFORMATION*)malloc(info_array_size); + if (!info_array) { + PyErr_NoMemory(); + goto done; + } + + if (!QueryWorkingSet(proc, info_array, info_array_size)) { + PyErr_SetFromWindowsErr(0); + goto done; + } + + entries = (size_t)info_array->NumberOfEntries; + private_pages = 0; + for (i = 0; i < entries; i++) { + // Count shared pages that only one process is using as private. + if (!info_array->WorkingSetInfo[i].Shared || + info_array->WorkingSetInfo[i].ShareCount <= 1) { + private_pages++; + } + } + + // GetSystemInfo has no return value. + GetSystemInfo(&system_info); + total = private_pages * system_info.dwPageSize; + py_result = Py_BuildValue("K", total); + +done: + if (proc) { + CloseHandle(proc); + } + + if (info_array) { + free(info_array); + } + + return py_result; +} + + +/* + * Return a Python integer indicating the total amount of physical memory + * in bytes. + */ +static PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + + if (! GlobalMemoryStatusEx(&memInfo)) + return PyErr_SetFromWindowsErr(0); + return Py_BuildValue("(LLLLLL)", + memInfo.ullTotalPhys, // total + memInfo.ullAvailPhys, // avail + memInfo.ullTotalPageFile, // total page file + memInfo.ullAvailPageFile, // avail page file + memInfo.ullTotalVirtual, // total virtual + memInfo.ullAvailVirtual); // avail virtual +} + + +/* + * Retrieves system CPU timing information as a (user, system, idle) + * tuple. On a multiprocessor system, the values returned are the + * sum of the designated times across all processors. + */ +static PyObject * +psutil_cpu_times(PyObject *self, PyObject *args) { + float idle, kernel, user, system; + FILETIME idle_time, kernel_time, user_time; + + if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) + return PyErr_SetFromWindowsErr(0); + + idle = (float)((HI_T * idle_time.dwHighDateTime) + \ + (LO_T * idle_time.dwLowDateTime)); + user = (float)((HI_T * user_time.dwHighDateTime) + \ + (LO_T * user_time.dwLowDateTime)); + kernel = (float)((HI_T * kernel_time.dwHighDateTime) + \ + (LO_T * kernel_time.dwLowDateTime)); + + // Kernel time includes idle time. + // We return only busy kernel time subtracting idle time from + // kernel time. + system = (kernel - idle); + return Py_BuildValue("(fff)", user, system, idle); +} + + +/* + * Same as above but for all system CPUs. + */ +static PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + // NtQuerySystemInformation stuff + typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + + float idle, kernel, systemt, user, interrupt, dpc; + NTSTATUS status; + _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; + SYSTEM_INFO si; + UINT i; + PyObject *py_tuple = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + + // obtain NtQuerySystemInformation + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + if (hNtDll == NULL) { + PyErr_SetFromWindowsErr(0); + goto error; + } + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + if (NtQuerySystemInformation == NULL) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // retrives number of processors + GetSystemInfo(&si); + + // allocates an array of _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION + // structures, one per processor + sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + if (sppi == NULL) { + PyErr_NoMemory(); + goto error; + } + + // gets cpu time informations + status = NtQuerySystemInformation( + SystemProcessorPerformanceInformation, + sppi, + si.dwNumberOfProcessors * sizeof + (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), + NULL); + if (status != 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // computes system global times summing each + // processor value + idle = user = kernel = interrupt = dpc = 0; + for (i = 0; i < si.dwNumberOfProcessors; i++) { + py_tuple = NULL; + user = (float)((HI_T * sppi[i].UserTime.HighPart) + + (LO_T * sppi[i].UserTime.LowPart)); + idle = (float)((HI_T * sppi[i].IdleTime.HighPart) + + (LO_T * sppi[i].IdleTime.LowPart)); + kernel = (float)((HI_T * sppi[i].KernelTime.HighPart) + + (LO_T * sppi[i].KernelTime.LowPart)); + interrupt = (float)((HI_T * sppi[i].InterruptTime.HighPart) + + (LO_T * sppi[i].InterruptTime.LowPart)); + dpc = (float)((HI_T * sppi[i].DpcTime.HighPart) + + (LO_T * sppi[i].DpcTime.LowPart)); + + // kernel time includes idle time on windows + // we return only busy kernel time subtracting + // idle time from kernel time + systemt = kernel - idle; + py_tuple = Py_BuildValue( + "(ddddd)", + user, + systemt, + idle, + interrupt, + dpc + ); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + free(sppi); + FreeLibrary(hNtDll); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (sppi) + free(sppi); + if (hNtDll) + FreeLibrary(hNtDll); + return NULL; +} + + +/* + * Return process current working directory as a Python string. + */ + +static PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + long pid; + int pid_return; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + pid_return = psutil_pid_is_running(pid); + if (pid_return == 0) + return NoSuchProcess(); + if (pid_return == -1) + return NULL; + + return psutil_get_cwd(pid); +} + + +/* + * Resume or suspends a process + */ +int +psutil_proc_suspend_or_resume(DWORD pid, int suspend) { + // a huge thanks to http://www.codeproject.com/KB/threads/pausep.aspx + HANDLE hThreadSnap = NULL; + THREADENTRY32 te32 = {0}; + + if (pid == 0) { + AccessDenied(); + return FALSE; + } + + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + return FALSE; + } + + // Fill in the size of the structure before using it + te32.dwSize = sizeof(THREADENTRY32); + + if (! Thread32First(hThreadSnap, &te32)) { + PyErr_SetFromWindowsErr(0); + CloseHandle(hThreadSnap); + return FALSE; + } + + // Walk the thread snapshot to find all threads of the process. + // If the thread belongs to the process, add its information + // to the display list. + do + { + if (te32.th32OwnerProcessID == pid) + { + HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, + te32.th32ThreadID); + if (hThread == NULL) { + PyErr_SetFromWindowsErr(0); + CloseHandle(hThread); + CloseHandle(hThreadSnap); + return FALSE; + } + if (suspend == 1) + { + if (SuspendThread(hThread) == (DWORD) - 1) { + PyErr_SetFromWindowsErr(0); + CloseHandle(hThread); + CloseHandle(hThreadSnap); + return FALSE; + } + } + else + { + if (ResumeThread(hThread) == (DWORD) - 1) { + PyErr_SetFromWindowsErr(0); + CloseHandle(hThread); + CloseHandle(hThreadSnap); + return FALSE; + } + } + CloseHandle(hThread); + } + } while (Thread32Next(hThreadSnap, &te32)); + + CloseHandle(hThreadSnap); + return TRUE; +} + + +static PyObject * +psutil_proc_suspend(PyObject *self, PyObject *args) { + long pid; + int suspend = 1; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (! psutil_proc_suspend_or_resume(pid, suspend)) + return NULL; + Py_RETURN_NONE; +} + + +static PyObject * +psutil_proc_resume(PyObject *self, PyObject *args) { + long pid; + int suspend = 0; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (! psutil_proc_suspend_or_resume(pid, suspend)) + return NULL; + Py_RETURN_NONE; +} + + +static PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + HANDLE hThread; + THREADENTRY32 te32 = {0}; + long pid; + int pid_return; + int rc; + FILETIME ftDummy, ftKernel, ftUser; + HANDLE hThreadSnap = NULL; + PyObject *py_tuple = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (pid == 0) { + // raise AD instead of returning 0 as procexp is able to + // retrieve useful information somehow + AccessDenied(); + goto error; + } + + pid_return = psutil_pid_is_running(pid); + if (pid_return == 0) { + NoSuchProcess(); + goto error; + } + if (pid_return == -1) + goto error; + + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // Fill in the size of the structure before using it + te32.dwSize = sizeof(THREADENTRY32); + + if (! Thread32First(hThreadSnap, &te32)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // Walk the thread snapshot to find all threads of the process. + // If the thread belongs to the process, increase the counter. + do { + if (te32.th32OwnerProcessID == pid) { + py_tuple = NULL; + hThread = NULL; + hThread = OpenThread(THREAD_QUERY_INFORMATION, + FALSE, te32.th32ThreadID); + if (hThread == NULL) { + // thread has disappeared on us + continue; + } + + rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, + &ftUser); + if (rc == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + /* + * User and kernel times are represented as a FILETIME structure + * wich contains a 64-bit value representing the number of + * 100-nanosecond intervals since January 1, 1601 (UTC): + * http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx + * To convert it into a float representing the seconds that the + * process has executed in user/kernel mode I borrowed the code + * below from Python's Modules/posixmodule.c + */ + py_tuple = Py_BuildValue( + "kdd", + te32.th32ThreadID, + (double)(ftUser.dwHighDateTime * 429.4967296 + \ + ftUser.dwLowDateTime * 1e-7), + (double)(ftKernel.dwHighDateTime * 429.4967296 + \ + ftKernel.dwLowDateTime * 1e-7)); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + + CloseHandle(hThread); + } + } while (Thread32Next(hThreadSnap, &te32)); + + CloseHandle(hThreadSnap); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (hThread != NULL) + CloseHandle(hThread); + if (hThreadSnap != NULL) + CloseHandle(hThreadSnap); + return NULL; +} + + +static PyObject * +psutil_proc_open_files(PyObject *self, PyObject *args) { + long pid; + HANDLE processHandle; + DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; + PyObject *py_retlist; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + processHandle = psutil_handle_from_pid_waccess(pid, access); + if (processHandle == NULL) + return NULL; + py_retlist = psutil_get_open_files(pid, processHandle); + CloseHandle(processHandle); + if (py_retlist == NULL) + return PyErr_SetFromWindowsErr(0); + return py_retlist; +} + + +/* + Accept a filename's drive in native format like "\Device\HarddiskVolume1\" + and return the corresponding drive letter (e.g. "C:\\"). + If no match is found return an empty string. +*/ +static PyObject * +psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) { + LPCTSTR lpDevicePath; + TCHAR d = TEXT('A'); + TCHAR szBuff[5]; + + if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) + return NULL; + + while (d <= TEXT('Z')) { + TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')}; + TCHAR szTarget[512] = {0}; + if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) { + if (_tcscmp(lpDevicePath, szTarget) == 0) { + _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d); + return Py_BuildValue("s", szBuff); + } + } + d++; + } + return Py_BuildValue("s", ""); +} + + +/* + * Return process username as a "DOMAIN//USERNAME" string. + */ +static PyObject * +psutil_proc_username(PyObject *self, PyObject *args) { + long pid; + HANDLE processHandle; + HANDLE tokenHandle; + PTOKEN_USER user; + ULONG bufferSize; + PTSTR name; + ULONG nameSize; + PTSTR domainName; + ULONG domainNameSize; + SID_NAME_USE nameUse; + PTSTR fullName; + PyObject *py_unicode; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + processHandle = psutil_handle_from_pid_waccess( + pid, PROCESS_QUERY_INFORMATION); + if (processHandle == NULL) + return NULL; + + if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) { + CloseHandle(processHandle); + return PyErr_SetFromWindowsErr(0); + } + + CloseHandle(processHandle); + + // Get the user SID. + + bufferSize = 0x100; + user = malloc(bufferSize); + if (user == NULL) + return PyErr_NoMemory(); + + if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, + &bufferSize)) + { + free(user); + user = malloc(bufferSize); + if (user == NULL) { + CloseHandle(tokenHandle); + return PyErr_NoMemory(); + } + if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, + &bufferSize)) + { + free(user); + CloseHandle(tokenHandle); + return PyErr_SetFromWindowsErr(0); + } + } + + CloseHandle(tokenHandle); + + // resolve the SID to a name + nameSize = 0x100; + domainNameSize = 0x100; + + name = malloc(nameSize * sizeof(TCHAR)); + if (name == NULL) + return PyErr_NoMemory(); + domainName = malloc(domainNameSize * sizeof(TCHAR)); + if (domainName == NULL) + return PyErr_NoMemory(); + + if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName, + &domainNameSize, &nameUse)) + { + free(name); + free(domainName); + name = malloc(nameSize * sizeof(TCHAR)); + if (name == NULL) + return PyErr_NoMemory(); + domainName = malloc(domainNameSize * sizeof(TCHAR)); + if (domainName == NULL) + return PyErr_NoMemory(); + if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, + domainName, &domainNameSize, &nameUse)) + { + free(name); + free(domainName); + free(user); + + return PyErr_SetFromWindowsErr(0); + } + } + + nameSize = _tcslen(name); + domainNameSize = _tcslen(domainName); + + // build the full username string + fullName = malloc((domainNameSize + 1 + nameSize + 1) * sizeof(TCHAR)); + if (fullName == NULL) { + free(name); + free(domainName); + free(user); + return PyErr_NoMemory(); + } + memcpy(fullName, domainName, domainNameSize); + fullName[domainNameSize] = '\\'; + memcpy(&fullName[domainNameSize + 1], name, nameSize); + fullName[domainNameSize + 1 + nameSize] = '\0'; + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + py_unicode = PyUnicode_DecodeLocaleAndSize( + fullName, _tcslen(fullName), "surrogateescape"); +#else + py_unicode = PyUnicode_Decode( + fullName, _tcslen(fullName), Py_FileSystemDefaultEncoding, "replace"); +#endif + + free(fullName); + free(name); + free(domainName); + free(user); + + return py_unicode; +} + + +typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, + TCP_TABLE_CLASS, ULONG); + + +// https://msdn.microsoft.com/library/aa365928.aspx +static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call, + ULONG address_family, + PVOID * data, DWORD * size) +{ + // Due to other processes being active on the machine, it's possible + // that the size of the table increases between the moment where we + // query the size and the moment where we query the data. Therefore, it's + // important to call this in a loop to retry if that happens. + // + // Also, since we may loop a theoretically unbounded number of times here, + // release the GIL while we're doing this. + DWORD error = ERROR_INSUFFICIENT_BUFFER; + *size = 0; + *data = NULL; + Py_BEGIN_ALLOW_THREADS; + error = call(NULL, size, FALSE, address_family, + TCP_TABLE_OWNER_PID_ALL, 0); + while (error == ERROR_INSUFFICIENT_BUFFER) + { + *data = malloc(*size); + if (*data == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + continue; + } + error = call(*data, size, FALSE, address_family, + TCP_TABLE_OWNER_PID_ALL, 0); + if (error != NO_ERROR) { + free(*data); + *data = NULL; + } + } + Py_END_ALLOW_THREADS; + return error; +} + + +typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG, + UDP_TABLE_CLASS, ULONG); + + +// https://msdn.microsoft.com/library/aa365930.aspx +static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call, + ULONG address_family, + PVOID * data, DWORD * size) +{ + // Due to other processes being active on the machine, it's possible + // that the size of the table increases between the moment where we + // query the size and the moment where we query the data. Therefore, it's + // important to call this in a loop to retry if that happens. + // + // Also, since we may loop a theoretically unbounded number of times here, + // release the GIL while we're doing this. + DWORD error = ERROR_INSUFFICIENT_BUFFER; + *size = 0; + *data = NULL; + Py_BEGIN_ALLOW_THREADS; + error = call(NULL, size, FALSE, address_family, + UDP_TABLE_OWNER_PID, 0); + while (error == ERROR_INSUFFICIENT_BUFFER) + { + *data = malloc(*size); + if (*data == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + continue; + } + error = call(*data, size, FALSE, address_family, + UDP_TABLE_OWNER_PID, 0); + if (error != NO_ERROR) { + free(*data); + *data = NULL; + } + } + Py_END_ALLOW_THREADS; + return error; +} + + +/* + * Return a list of network connections opened by a process + */ +static PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + static long null_address[4] = { 0, 0, 0, 0 }; + unsigned long pid; + typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(struct in_addr *, PSTR); + _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; + typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR); + _RtlIpv6AddressToStringA rtlIpv6AddressToStringA; + _GetExtendedTcpTable getExtendedTcpTable; + _GetExtendedUdpTable getExtendedUdpTable; + PVOID table = NULL; + DWORD tableSize; + DWORD error; + PMIB_TCPTABLE_OWNER_PID tcp4Table; + PMIB_UDPTABLE_OWNER_PID udp4Table; + PMIB_TCP6TABLE_OWNER_PID tcp6Table; + PMIB_UDP6TABLE_OWNER_PID udp6Table; + ULONG i; + CHAR addressBufferLocal[65]; + CHAR addressBufferRemote[65]; + + PyObject *py_retlist; + PyObject *py_conn_tuple = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_addr_tuple_local = NULL; + PyObject *py_addr_tuple_remote = NULL; + PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); + PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); + PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); + PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); + + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + { + _psutil_conn_decref_objs(); + return NULL; + } + + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + _psutil_conn_decref_objs(); + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + return NULL; + } + + if (pid != -1) { + if (psutil_pid_is_running(pid) == 0) { + _psutil_conn_decref_objs(); + return NoSuchProcess(); + } + } + + // Import some functions. + { + HMODULE ntdll; + HMODULE iphlpapi; + + ntdll = LoadLibrary(TEXT("ntdll.dll")); + rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress( + ntdll, "RtlIpv4AddressToStringA"); + rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress( + ntdll, "RtlIpv6AddressToStringA"); + /* TODO: Check these two function pointers */ + + iphlpapi = LoadLibrary(TEXT("iphlpapi.dll")); + getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi, + "GetExtendedTcpTable"); + getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi, + "GetExtendedUdpTable"); + FreeLibrary(ntdll); + FreeLibrary(iphlpapi); + } + + if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) { + PyErr_SetString(PyExc_NotImplementedError, + "feature not supported on this Windows version"); + _psutil_conn_decref_objs(); + return NULL; + } + + py_retlist = PyList_New(0); + if (py_retlist == NULL) { + _psutil_conn_decref_objs(); + return NULL; + } + + // TCP IPv4 + + if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + + error = __GetExtendedTcpTable(getExtendedTcpTable, + AF_INET, &table, &tableSize); + if (error == ERROR_NOT_ENOUGH_MEMORY) { + PyErr_NoMemory(); + goto error; + } + + if (error == NO_ERROR) + { + tcp4Table = table; + + for (i = 0; i < tcp4Table->dwNumEntries; i++) + { + if (pid != -1) { + if (tcp4Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (tcp4Table->table[i].dwLocalAddr != 0 || + tcp4Table->table[i].dwLocalPort != 0) + { + struct in_addr addr; + + addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; + rtlIpv4AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + // On Windows <= XP, remote addr is filled even if socket + // is in LISTEN mode in which case we just ignore it. + if ((tcp4Table->table[i].dwRemoteAddr != 0 || + tcp4Table->table[i].dwRemotePort != 0) && + (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) + { + struct in_addr addr; + + addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; + rtlIpv4AddressToStringA(&addr, addressBufferRemote); + py_addr_tuple_remote = Py_BuildValue( + "(si)", + addressBufferRemote, + BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); + } + else + { + py_addr_tuple_remote = PyTuple_New(0); + } + + if (py_addr_tuple_remote == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET, + SOCK_STREAM, + py_addr_tuple_local, + py_addr_tuple_remote, + tcp4Table->table[i].dwState, + tcp4Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_DECREF(py_conn_tuple); + } + } + else { + PyErr_SetFromWindowsErr(error); + goto error; + } + + free(table); + table = NULL; + tableSize = 0; + } + + // TCP IPv6 + if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + + error = __GetExtendedTcpTable(getExtendedTcpTable, + AF_INET6, &table, &tableSize); + if (error == ERROR_NOT_ENOUGH_MEMORY) { + PyErr_NoMemory(); + goto error; + } + + if (error == NO_ERROR) + { + tcp6Table = table; + + for (i = 0; i < tcp6Table->dwNumEntries; i++) + { + if (pid != -1) { + if (tcp6Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) + != 0 || tcp6Table->table[i].dwLocalPort != 0) + { + struct in6_addr addr; + + memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); + rtlIpv6AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + // On Windows <= XP, remote addr is filled even if socket + // is in LISTEN mode in which case we just ignore it. + if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) + != 0 || + tcp6Table->table[i].dwRemotePort != 0) && + (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) + { + struct in6_addr addr; + + memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); + rtlIpv6AddressToStringA(&addr, addressBufferRemote); + py_addr_tuple_remote = Py_BuildValue( + "(si)", + addressBufferRemote, + BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); + } + else { + py_addr_tuple_remote = PyTuple_New(0); + } + + if (py_addr_tuple_remote == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET6, + SOCK_STREAM, + py_addr_tuple_local, + py_addr_tuple_remote, + tcp6Table->table[i].dwState, + tcp6Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_DECREF(py_conn_tuple); + } + } + else { + PyErr_SetFromWindowsErr(error); + goto error; + } + + free(table); + table = NULL; + tableSize = 0; + } + + // UDP IPv4 + + if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + error = __GetExtendedUdpTable(getExtendedUdpTable, + AF_INET, &table, &tableSize); + if (error == ERROR_NOT_ENOUGH_MEMORY) { + PyErr_NoMemory(); + goto error; + } + + if (error == NO_ERROR) + { + udp4Table = table; + + for (i = 0; i < udp4Table->dwNumEntries; i++) + { + if (pid != -1) { + if (udp4Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (udp4Table->table[i].dwLocalAddr != 0 || + udp4Table->table[i].dwLocalPort != 0) + { + struct in_addr addr; + + addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; + rtlIpv4AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET, + SOCK_DGRAM, + py_addr_tuple_local, + PyTuple_New(0), + PSUTIL_CONN_NONE, + udp4Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_DECREF(py_conn_tuple); + } + } + else { + PyErr_SetFromWindowsErr(error); + goto error; + } + + free(table); + table = NULL; + tableSize = 0; + } + + // UDP IPv6 + + if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + error = __GetExtendedUdpTable(getExtendedUdpTable, + AF_INET6, &table, &tableSize); + if (error == ERROR_NOT_ENOUGH_MEMORY) { + PyErr_NoMemory(); + goto error; + } + + if (error == NO_ERROR) + { + udp6Table = table; + + for (i = 0; i < udp6Table->dwNumEntries; i++) { + if (pid != -1) { + if (udp6Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) + != 0 || udp6Table->table[i].dwLocalPort != 0) + { + struct in6_addr addr; + + memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); + rtlIpv6AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET6, + SOCK_DGRAM, + py_addr_tuple_local, + PyTuple_New(0), + PSUTIL_CONN_NONE, + udp6Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_DECREF(py_conn_tuple); + } + } + else { + PyErr_SetFromWindowsErr(error); + goto error; + } + + free(table); + table = NULL; + tableSize = 0; + } + + _psutil_conn_decref_objs(); + return py_retlist; + +error: + _psutil_conn_decref_objs(); + Py_XDECREF(py_conn_tuple); + Py_XDECREF(py_addr_tuple_local); + Py_XDECREF(py_addr_tuple_remote); + Py_DECREF(py_retlist); + if (table != NULL) + free(table); + return NULL; +} + + +/* + * Get process priority as a Python integer. + */ +static PyObject * +psutil_proc_priority_get(PyObject *self, PyObject *args) { + long pid; + DWORD priority; + HANDLE hProcess; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) + return NULL; + priority = GetPriorityClass(hProcess); + CloseHandle(hProcess); + if (priority == 0) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + return Py_BuildValue("i", priority); +} + + +/* + * Set process priority. + */ +static PyObject * +psutil_proc_priority_set(PyObject *self, PyObject *args) { + long pid; + int priority; + int retval; + HANDLE hProcess; + DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; + + if (! PyArg_ParseTuple(args, "li", &pid, &priority)) + return NULL; + hProcess = psutil_handle_from_pid_waccess(pid, access); + if (hProcess == NULL) + return NULL; + retval = SetPriorityClass(hProcess, priority); + CloseHandle(hProcess); + if (retval == 0) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + Py_RETURN_NONE; +} + + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista +/* + * Get process IO priority as a Python integer. + */ +static PyObject * +psutil_proc_io_priority_get(PyObject *self, PyObject *args) { + long pid; + HANDLE hProcess; + PULONG IoPriority; + + _NtQueryInformationProcess NtQueryInformationProcess = + (_NtQueryInformationProcess)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) + return NULL; + + NtQueryInformationProcess( + hProcess, + ProcessIoPriority, + &IoPriority, + sizeof(ULONG), + NULL + ); + CloseHandle(hProcess); + return Py_BuildValue("i", IoPriority); +} + + +/* + * Set process IO priority. + */ +static PyObject * +psutil_proc_io_priority_set(PyObject *self, PyObject *args) { + long pid; + int prio; + HANDLE hProcess; + + _NtSetInformationProcess NtSetInformationProcess = + (_NtSetInformationProcess)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "NtSetInformationProcess"); + + if (NtSetInformationProcess == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "couldn't get NtSetInformationProcess syscall"); + return NULL; + } + + if (! PyArg_ParseTuple(args, "li", &pid, &prio)) + return NULL; + hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_ALL_ACCESS); + if (hProcess == NULL) + return NULL; + + NtSetInformationProcess( + hProcess, + ProcessIoPriority, + (PVOID)&prio, + sizeof((PVOID)prio) + ); + + CloseHandle(hProcess); + Py_RETURN_NONE; +} +#endif + + +/* + * Return a Python tuple referencing process I/O counters. + */ +static PyObject * +psutil_proc_io_counters(PyObject *self, PyObject *args) { + DWORD pid; + HANDLE hProcess; + IO_COUNTERS IoCounters; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid(pid); + if (NULL == hProcess) + return NULL; + if (! GetProcessIoCounters(hProcess, &IoCounters)) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(0); + } + CloseHandle(hProcess); + return Py_BuildValue("(KKKKKK)", + IoCounters.ReadOperationCount, + IoCounters.WriteOperationCount, + IoCounters.ReadTransferCount, + IoCounters.WriteTransferCount, + IoCounters.OtherOperationCount, + IoCounters.OtherTransferCount); +} + + +/* + * Return process CPU affinity as a bitmask + */ +static PyObject * +psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { + DWORD pid; + HANDLE hProcess; + DWORD_PTR proc_mask; + DWORD_PTR system_mask; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) { + return NULL; + } + if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(0); + } + + CloseHandle(hProcess); +#ifdef _WIN64 + return Py_BuildValue("K", (unsigned long long)proc_mask); +#else + return Py_BuildValue("k", (unsigned long)proc_mask); +#endif +} + + +/* + * Set process CPU affinity + */ +static PyObject * +psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { + DWORD pid; + HANDLE hProcess; + DWORD dwDesiredAccess = \ + PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; + DWORD_PTR mask; + +#ifdef _WIN64 + if (! PyArg_ParseTuple(args, "lK", &pid, &mask)) +#else + if (! PyArg_ParseTuple(args, "lk", &pid, &mask)) +#endif + { + return NULL; + } + hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); + if (hProcess == NULL) + return NULL; + + if (SetProcessAffinityMask(hProcess, mask) == 0) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(0); + } + + CloseHandle(hProcess); + Py_RETURN_NONE; +} + + +/* + * Return True if one of the process threads is in a waiting or + * suspended status. + */ +static PyObject * +psutil_proc_is_suspended(PyObject *self, PyObject *args) { + DWORD pid; + ULONG i; + PSYSTEM_PROCESS_INFORMATION process; + PVOID buffer; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (! psutil_get_proc_info(pid, &process, &buffer)) { + return NULL; + } + for (i = 0; i < process->NumberOfThreads; i++) { + if (process->Threads[i].ThreadState != Waiting || + process->Threads[i].WaitReason != Suspended) + { + free(buffer); + Py_RETURN_FALSE; + } + } + free(buffer); + Py_RETURN_TRUE; +} + + +/* + * Return path's disk total and free as a Python tuple. + */ +static PyObject * +psutil_disk_usage(PyObject *self, PyObject *args) { + BOOL retval; + ULARGE_INTEGER _, total, free; + char *path; + + if (PyArg_ParseTuple(args, "u", &path)) { + Py_BEGIN_ALLOW_THREADS + retval = GetDiskFreeSpaceExW((LPCWSTR)path, &_, &total, &free); + Py_END_ALLOW_THREADS + goto return_; + } + + // on Python 2 we also want to accept plain strings other + // than Unicode +#if PY_MAJOR_VERSION <= 2 + PyErr_Clear(); // drop the argument parsing error + if (PyArg_ParseTuple(args, "s", &path)) { + Py_BEGIN_ALLOW_THREADS + retval = GetDiskFreeSpaceEx(path, &_, &total, &free); + Py_END_ALLOW_THREADS + goto return_; + } +#endif + + return NULL; + +return_: + if (retval == 0) + return PyErr_SetFromWindowsErr(0); + else + return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); +} + + +/* + * Return a Python list of named tuples with overall network I/O information + */ +static PyObject * +psutil_net_io_counters(PyObject *self, PyObject *args) { + DWORD dwRetVal = 0; + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + MIB_IF_ROW2 *pIfRow = NULL; +#else // Windows XP + MIB_IFROW *pIfRow = NULL; +#endif + + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + PyObject *py_retdict = PyDict_New(); + PyObject *py_nic_info = NULL; + PyObject *py_nic_name = NULL; + + if (py_retdict == NULL) + return NULL; + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) + goto error; + pCurrAddresses = pAddresses; + + while (pCurrAddresses) { + py_nic_name = NULL; + py_nic_info = NULL; + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2)); +#else // Windows XP + pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); +#endif + + if (pIfRow == NULL) { + PyErr_NoMemory(); + goto error; + } + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2)); + pIfRow->InterfaceIndex = pCurrAddresses->IfIndex; + dwRetVal = GetIfEntry2(pIfRow); +#else // Windows XP + pIfRow->dwIndex = pCurrAddresses->IfIndex; + dwRetVal = GetIfEntry(pIfRow); +#endif + + if (dwRetVal != NO_ERROR) { + PyErr_SetString(PyExc_RuntimeError, + "GetIfEntry() or GetIfEntry2() syscalls failed."); + goto error; + } + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + py_nic_info = Py_BuildValue("(KKKKKKKK)", + pIfRow->OutOctets, + pIfRow->InOctets, + pIfRow->OutUcastPkts, + pIfRow->InUcastPkts, + pIfRow->InErrors, + pIfRow->OutErrors, + pIfRow->InDiscards, + pIfRow->OutDiscards); +#else // Windows XP + py_nic_info = Py_BuildValue("(kkkkkkkk)", + pIfRow->dwOutOctets, + pIfRow->dwInOctets, + pIfRow->dwOutUcastPkts, + pIfRow->dwInUcastPkts, + pIfRow->dwInErrors, + pIfRow->dwOutErrors, + pIfRow->dwInDiscards, + pIfRow->dwOutDiscards); +#endif + + if (!py_nic_info) + goto error; + + py_nic_name = PyUnicode_FromWideChar( + pCurrAddresses->FriendlyName, + wcslen(pCurrAddresses->FriendlyName)); + + if (py_nic_name == NULL) + goto error; + if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) + goto error; + Py_XDECREF(py_nic_name); + Py_XDECREF(py_nic_info); + + free(pIfRow); + pCurrAddresses = pCurrAddresses->Next; + } + + free(pAddresses); + return py_retdict; + +error: + Py_XDECREF(py_nic_name); + Py_XDECREF(py_nic_info); + Py_DECREF(py_retdict); + if (pAddresses != NULL) + free(pAddresses); + if (pIfRow != NULL) + free(pIfRow); + return NULL; +} + + +/* + * Return a Python dict of tuples for disk I/O information + */ +static PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + DISK_PERFORMANCE_WIN_2008 diskPerformance; + DWORD dwSize; + HANDLE hDevice = NULL; + char szDevice[MAX_PATH]; + char szDeviceDisplay[MAX_PATH]; + int devNum; + PyObject *py_retdict = PyDict_New(); + PyObject *py_tuple = NULL; + + if (py_retdict == NULL) + return NULL; + // Apparently there's no way to figure out how many times we have + // to iterate in order to find valid drives. + // Let's assume 32, which is higher than 26, the number of letters + // in the alphabet (from A:\ to Z:\). + for (devNum = 0; devNum <= 32; ++devNum) { + py_tuple = NULL; + sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum); + hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + + if (hDevice == INVALID_HANDLE_VALUE) + continue; + if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, + &diskPerformance, sizeof(diskPerformance), + &dwSize, NULL)) + { + sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); + py_tuple = Py_BuildValue( + "(IILLKK)", + diskPerformance.ReadCount, + diskPerformance.WriteCount, + diskPerformance.BytesRead, + diskPerformance.BytesWritten, + (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000, + (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000); + if (!py_tuple) + goto error; + if (PyDict_SetItemString(py_retdict, szDeviceDisplay, + py_tuple)) + { + goto error; + } + Py_XDECREF(py_tuple); + } + else { + // XXX we might get here with ERROR_INSUFFICIENT_BUFFER when + // compiling with mingw32; not sure what to do. + // return PyErr_SetFromWindowsErr(0); + ;; + } + + CloseHandle(hDevice); + } + + return py_retdict; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retdict); + if (hDevice != NULL) + CloseHandle(hDevice); + return NULL; +} + + +static char *psutil_get_drive_type(int type) { + switch (type) { + case DRIVE_FIXED: + return "fixed"; + case DRIVE_CDROM: + return "cdrom"; + case DRIVE_REMOVABLE: + return "removable"; + case DRIVE_UNKNOWN: + return "unknown"; + case DRIVE_NO_ROOT_DIR: + return "unmounted"; + case DRIVE_REMOTE: + return "remote"; + case DRIVE_RAMDISK: + return "ramdisk"; + default: + return "?"; + } +} + + +#ifndef _ARRAYSIZE +#define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + +/* + * Return disk partitions as a list of tuples such as + * (drive_letter, drive_letter, type, "") + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) { + DWORD num_bytes; + char drive_strings[255]; + char *drive_letter = drive_strings; + int all; + int type; + int ret; + char opts[20]; + LPTSTR fs_type[MAX_PATH + 1] = { 0 }; + DWORD pflags = 0; + PyObject *py_all; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) { + return NULL; + } + + // avoid to visualize a message box in case something goes wrong + // see https://github.com/giampaolo/psutil/issues/264 + SetErrorMode(SEM_FAILCRITICALERRORS); + + if (! PyArg_ParseTuple(args, "O", &py_all)) + goto error; + all = PyObject_IsTrue(py_all); + + Py_BEGIN_ALLOW_THREADS + num_bytes = GetLogicalDriveStrings(254, drive_letter); + Py_END_ALLOW_THREADS + + if (num_bytes == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + while (*drive_letter != 0) { + py_tuple = NULL; + opts[0] = 0; + fs_type[0] = 0; + + Py_BEGIN_ALLOW_THREADS + type = GetDriveType(drive_letter); + Py_END_ALLOW_THREADS + + // by default we only show hard drives and cd-roms + if (all == 0) { + if ((type == DRIVE_UNKNOWN) || + (type == DRIVE_NO_ROOT_DIR) || + (type == DRIVE_REMOTE) || + (type == DRIVE_RAMDISK)) { + goto next; + } + // floppy disk: skip it by default as it introduces a + // considerable slowdown. + if ((type == DRIVE_REMOVABLE) && + (strcmp(drive_letter, "A:\\") == 0)) { + goto next; + } + } + + ret = GetVolumeInformation( + (LPCTSTR)drive_letter, NULL, _ARRAYSIZE(drive_letter), + NULL, NULL, &pflags, (LPTSTR)fs_type, _ARRAYSIZE(fs_type)); + if (ret == 0) { + // We might get here in case of a floppy hard drive, in + // which case the error is (21, "device not ready"). + // Let's pretend it didn't happen as we already have + // the drive name and type ('removable'). + strcat_s(opts, _countof(opts), ""); + SetLastError(0); + } + else { + if (pflags & FILE_READ_ONLY_VOLUME) + strcat_s(opts, _countof(opts), "ro"); + else + strcat_s(opts, _countof(opts), "rw"); + if (pflags & FILE_VOLUME_IS_COMPRESSED) + strcat_s(opts, _countof(opts), ",compressed"); + } + + if (strlen(opts) > 0) + strcat_s(opts, _countof(opts), ","); + strcat_s(opts, _countof(opts), psutil_get_drive_type(type)); + + py_tuple = Py_BuildValue( + "(ssss)", + drive_letter, + drive_letter, + fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS + opts); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + goto next; + +next: + drive_letter = strchr(drive_letter, 0) + 1; + } + + SetErrorMode(0); + return py_retlist; + +error: + SetErrorMode(0); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + return NULL; +} + +/* + * Return a Python dict of tuples for disk I/O information + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) { + HANDLE hServer = WTS_CURRENT_SERVER_HANDLE; + LPTSTR buffer_user = NULL; + LPTSTR buffer_addr = NULL; + PWTS_SESSION_INFO sessions = NULL; + DWORD count; + DWORD i; + DWORD sessionId; + DWORD bytes; + PWTS_CLIENT_ADDRESS address; + char address_str[50]; + long long unix_time; + + PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; + WINSTATION_INFO station_info; + HINSTANCE hInstWinSta = NULL; + ULONG returnLen; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_buffer_user_encoded = NULL; + + if (py_retlist == NULL) + return NULL; + + hInstWinSta = LoadLibraryA("winsta.dll"); + WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) \ + GetProcAddress(hInstWinSta, "WinStationQueryInformationW"); + + if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + for (i = 0; i < count; i++) { + py_address = NULL; + py_tuple = NULL; + sessionId = sessions[i].SessionId; + if (buffer_user != NULL) + WTSFreeMemory(buffer_user); + if (buffer_addr != NULL) + WTSFreeMemory(buffer_addr); + + buffer_user = NULL; + buffer_addr = NULL; + + // username + bytes = 0; + if (WTSQuerySessionInformation(hServer, sessionId, WTSUserName, + &buffer_user, &bytes) == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + if (bytes == 1) + continue; + + // address + bytes = 0; + if (WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress, + &buffer_addr, &bytes) == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + address = (PWTS_CLIENT_ADDRESS)buffer_addr; + if (address->AddressFamily == 0) { // AF_INET + sprintf_s(address_str, + _countof(address_str), + "%u.%u.%u.%u", + address->Address[0], + address->Address[1], + address->Address[2], + address->Address[3]); + py_address = Py_BuildValue("s", address_str); + if (!py_address) + goto error; + } + else { + py_address = Py_None; + } + + // login time + if (!WinStationQueryInformationW(hServer, + sessionId, + WinStationInformation, + &station_info, + sizeof(station_info), + &returnLen)) + { + goto error; + } + + unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; + unix_time += \ + station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; + unix_time /= 10000000; + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + py_buffer_user_encoded = PyUnicode_DecodeLocaleAndSize( + buffer_user, _tcslen(buffer_user), "surrogateescape"); +#else + py_buffer_user_encoded = PyUnicode_Decode( + buffer_user, _tcslen(buffer_user), Py_FileSystemDefaultEncoding, + "replace"); +#endif + + if (py_buffer_user_encoded == NULL) + goto error; + py_tuple = Py_BuildValue("OOd", py_buffer_user_encoded, py_address, + (double)unix_time); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_XDECREF(py_buffer_user_encoded); + Py_XDECREF(py_address); + Py_XDECREF(py_tuple); + } + + WTSFreeMemory(sessions); + WTSFreeMemory(buffer_user); + WTSFreeMemory(buffer_addr); + FreeLibrary(hInstWinSta); + return py_retlist; + +error: + Py_XDECREF(py_buffer_user_encoded); + Py_XDECREF(py_tuple); + Py_XDECREF(py_address); + Py_DECREF(py_retlist); + + if (hInstWinSta != NULL) + FreeLibrary(hInstWinSta); + if (sessions != NULL) + WTSFreeMemory(sessions); + if (buffer_user != NULL) + WTSFreeMemory(buffer_user); + if (buffer_addr != NULL) + WTSFreeMemory(buffer_addr); + return NULL; +} + + +/* + * Return the number of handles opened by process. + */ +static PyObject * +psutil_proc_num_handles(PyObject *self, PyObject *args) { + DWORD pid; + HANDLE hProcess; + DWORD handleCount; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hProcess = psutil_handle_from_pid(pid); + if (NULL == hProcess) + return NULL; + if (! GetProcessHandleCount(hProcess, &handleCount)) { + CloseHandle(hProcess); + return PyErr_SetFromWindowsErr(0); + } + CloseHandle(hProcess); + return Py_BuildValue("k", handleCount); +} + + +/* + * Get various process information by using NtQuerySystemInformation. + * We use this as a fallback when faster functions fail with access + * denied. This is slower because it iterates over all processes. + * Returned tuple includes the following process info: + * + * - num_threads() + * - ctx_switches() + * - num_handles() (fallback) + * - cpu_times() (fallback) + * - create_time() (fallback) + * - io_counters() (fallback) + * - memory_info() (fallback) + */ +static PyObject * +psutil_proc_info(PyObject *self, PyObject *args) { + DWORD pid; + PSYSTEM_PROCESS_INFORMATION process; + PVOID buffer; + ULONG i; + ULONG ctx_switches = 0; + double user_time; + double kernel_time; + long long create_time; + SIZE_T mem_private; + PyObject *py_retlist; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (! psutil_get_proc_info(pid, &process, &buffer)) + return NULL; + + for (i = 0; i < process->NumberOfThreads; i++) + ctx_switches += process->Threads[i].ContextSwitches; + user_time = (double)process->UserTime.HighPart * 429.4967296 + \ + (double)process->UserTime.LowPart * 1e-7; + kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \ + (double)process->KernelTime.LowPart * 1e-7; + // Convert the LARGE_INTEGER union to a Unix time. + // It's the best I could find by googling and borrowing code here + // and there. The time returned has a precision of 1 second. + if (0 == pid || 4 == pid) { + // the python module will translate this into BOOT_TIME later + create_time = 0; + } + else { + create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; + create_time += process->CreateTime.LowPart - 116444736000000000LL; + create_time /= 10000000; + } + +#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 + mem_private = process->PrivatePageCount; +#else + mem_private = 0; +#endif + + py_retlist = Py_BuildValue( +#if defined(_WIN64) + "kkdddiKKKKKK" "kKKKKKKKKK", +#else + "kkdddiKKKKKK" "kIIIIIIIII", +#endif + process->HandleCount, // num handles + ctx_switches, // num ctx switches + user_time, // cpu user time + kernel_time, // cpu kernel time + (double)create_time, // create time + (int)process->NumberOfThreads, // num threads + // IO counters + process->ReadOperationCount.QuadPart, // io rcount + process->WriteOperationCount.QuadPart, // io wcount + process->ReadTransferCount.QuadPart, // io rbytes + process->WriteTransferCount.QuadPart, // io wbytes + process->OtherOperationCount.QuadPart, // io others count + process->OtherTransferCount.QuadPart, // io others bytes + // memory + process->PageFaultCount, // num page faults + process->PeakWorkingSetSize, // peak wset + process->WorkingSetSize, // wset + process->QuotaPeakPagedPoolUsage, // peak paged pool + process->QuotaPagedPoolUsage, // paged pool + process->QuotaPeakNonPagedPoolUsage, // peak non paged pool + process->QuotaNonPagedPoolUsage, // non paged pool + process->PagefileUsage, // pagefile + process->PeakPagefileUsage, // peak pagefile + mem_private // private + ); + + free(buffer); + return py_retlist; +} + + +static char *get_region_protection_string(ULONG protection) { + switch (protection & 0xff) { + case PAGE_NOACCESS: + return ""; + case PAGE_READONLY: + return "r"; + case PAGE_READWRITE: + return "rw"; + case PAGE_WRITECOPY: + return "wc"; + case PAGE_EXECUTE: + return "x"; + case PAGE_EXECUTE_READ: + return "xr"; + case PAGE_EXECUTE_READWRITE: + return "xrw"; + case PAGE_EXECUTE_WRITECOPY: + return "xwc"; + default: + return "?"; + } +} + + +/* + * Return a list of process's memory mappings. + */ +static PyObject * +psutil_proc_memory_maps(PyObject *self, PyObject *args) { +#ifdef _WIN64 + MEMORY_BASIC_INFORMATION64 basicInfo; +#else + MEMORY_BASIC_INFORMATION basicInfo; +#endif + DWORD pid; + HANDLE hProcess = NULL; + PVOID baseAddress; + PVOID previousAllocationBase; + CHAR mappedFileName[MAX_PATH]; + SYSTEM_INFO system_info; + LPVOID maxAddr; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + hProcess = psutil_handle_from_pid(pid); + if (NULL == hProcess) + goto error; + + GetSystemInfo(&system_info); + maxAddr = system_info.lpMaximumApplicationAddress; + baseAddress = NULL; + previousAllocationBase = NULL; + + while (VirtualQueryEx(hProcess, baseAddress, &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION))) + { + py_tuple = NULL; + if (baseAddress > maxAddr) + break; + if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName, + sizeof(mappedFileName))) + { +#ifdef _WIN64 + py_tuple = Py_BuildValue( + "(KssI)", + (unsigned long long)baseAddress, +#else + py_tuple = Py_BuildValue( + "(kssI)", + (unsigned long)baseAddress, +#endif + get_region_protection_string(basicInfo.Protect), + mappedFileName, + basicInfo.RegionSize); + + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + previousAllocationBase = basicInfo.AllocationBase; + baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; + } + + CloseHandle(hProcess); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (hProcess != NULL) + CloseHandle(hProcess); + return NULL; +} + + +/* + * Return a {pid:ppid, ...} dict for all running processes. + */ +static PyObject * +psutil_ppid_map(PyObject *self, PyObject *args) { + PyObject *py_pid = NULL; + PyObject *py_ppid = NULL; + PyObject *py_retdict = PyDict_New(); + HANDLE handle = NULL; + PROCESSENTRY32 pe = {0}; + pe.dwSize = sizeof(PROCESSENTRY32); + + if (py_retdict == NULL) + return NULL; + handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (handle == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + Py_DECREF(py_retdict); + return NULL; + } + + if (Process32First(handle, &pe)) { + do { + py_pid = Py_BuildValue("I", pe.th32ProcessID); + if (py_pid == NULL) + goto error; + py_ppid = Py_BuildValue("I", pe.th32ParentProcessID); + if (py_ppid == NULL) + goto error; + if (PyDict_SetItem(py_retdict, py_pid, py_ppid)) + goto error; + Py_DECREF(py_pid); + Py_DECREF(py_ppid); + } while (Process32Next(handle, &pe)); + } + + CloseHandle(handle); + return py_retdict; + +error: + Py_XDECREF(py_pid); + Py_XDECREF(py_ppid); + Py_DECREF(py_retdict); + CloseHandle(handle); + return NULL; +} + + +/* + * Return NICs addresses. + */ + +static PyObject * +psutil_net_if_addrs(PyObject *self, PyObject *args) { + unsigned int i = 0; + ULONG family; + PCTSTR intRet; + PCTSTR netmaskIntRet; + char *ptr; + char buff[100]; + DWORD bufflen = 100; + char netmask_buff[100]; + DWORD netmask_bufflen = 100; + DWORD dwRetVal = 0; +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + ULONG converted_netmask; + UINT netmask_bits; + struct in_addr in_netmask; +#endif + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_mac_address = NULL; + PyObject *py_nic_name = NULL; + PyObject *py_netmask = NULL; + + if (py_retlist == NULL) + return NULL; + + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) + goto error; + pCurrAddresses = pAddresses; + + while (pCurrAddresses) { + pUnicast = pCurrAddresses->FirstUnicastAddress; + + netmaskIntRet = NULL; + py_nic_name = NULL; + py_nic_name = PyUnicode_FromWideChar( + pCurrAddresses->FriendlyName, + wcslen(pCurrAddresses->FriendlyName)); + if (py_nic_name == NULL) + goto error; + + // MAC address + if (pCurrAddresses->PhysicalAddressLength != 0) { + ptr = buff; + *ptr = '\0'; + for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) { + if (i == (pCurrAddresses->PhysicalAddressLength - 1)) { + sprintf_s(ptr, _countof(buff), "%.2X\n", + (int)pCurrAddresses->PhysicalAddress[i]); + } + else { + sprintf_s(ptr, _countof(buff), "%.2X-", + (int)pCurrAddresses->PhysicalAddress[i]); + } + ptr += 3; + } + *--ptr = '\0'; + +#if PY_MAJOR_VERSION >= 3 + py_mac_address = PyUnicode_FromString(buff); +#else + py_mac_address = PyString_FromString(buff); +#endif + if (py_mac_address == NULL) + goto error; + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + py_tuple = Py_BuildValue( + "(OiOOOO)", + py_nic_name, + -1, // this will be converted later to AF_LINK + py_mac_address, + Py_None, // netmask (not supported) + Py_None, // broadcast (not supported) + Py_None // ptp (not supported on Windows) + ); + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_mac_address); + } + + // find out the IP address associated with the NIC + if (pUnicast != NULL) { + for (i = 0; pUnicast != NULL; i++) { + family = pUnicast->Address.lpSockaddr->sa_family; + if (family == AF_INET) { + struct sockaddr_in *sa_in = (struct sockaddr_in *) + pUnicast->Address.lpSockaddr; + intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, + bufflen); +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + netmask_bits = pUnicast->OnLinkPrefixLength; + dwRetVal = ConvertLengthToIpv4Mask(netmask_bits, &converted_netmask); + if (dwRetVal == NO_ERROR) { + in_netmask.s_addr = converted_netmask; + netmaskIntRet = inet_ntop(AF_INET, &in_netmask, netmask_buff, + netmask_bufflen); + } +#endif + } + else if (family == AF_INET6) { + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) + pUnicast->Address.lpSockaddr; + intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr), + buff, bufflen); + } + else { + // we should never get here + pUnicast = pUnicast->Next; + continue; + } + + if (intRet == NULL) { + PyErr_SetFromWindowsErr(GetLastError()); + goto error; + } +#if PY_MAJOR_VERSION >= 3 + py_address = PyUnicode_FromString(buff); +#else + py_address = PyString_FromString(buff); +#endif + if (py_address == NULL) + goto error; + + if (netmaskIntRet != NULL) { +#if PY_MAJOR_VERSION >= 3 + py_netmask = PyUnicode_FromString(netmask_buff); +#else + py_netmask = PyString_FromString(netmask_buff); +#endif + } else { + Py_INCREF(Py_None); + py_netmask = Py_None; + } + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + py_tuple = Py_BuildValue( + "(OiOOOO)", + py_nic_name, + family, + py_address, + py_netmask, + Py_None, // broadcast (not supported) + Py_None // ptp (not supported on Windows) + ); + + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_address); + Py_DECREF(py_netmask); + + pUnicast = pUnicast->Next; + } + } + Py_DECREF(py_nic_name); + pCurrAddresses = pCurrAddresses->Next; + } + + free(pAddresses); + return py_retlist; + +error: + if (pAddresses) + free(pAddresses); + Py_DECREF(py_retlist); + Py_XDECREF(py_tuple); + Py_XDECREF(py_address); + Py_XDECREF(py_nic_name); + Py_XDECREF(py_netmask); + return NULL; +} + + +/* + * Provides stats about NIC interfaces installed on the system. + * TODO: get 'duplex' (currently it's hard coded to '2', aka + 'full duplex') + */ +static PyObject * +psutil_net_if_stats(PyObject *self, PyObject *args) { + int i; + DWORD dwSize = 0; + DWORD dwRetVal = 0; + MIB_IFTABLE *pIfTable; + MIB_IFROW *pIfRow; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + char descr[MAX_PATH]; + int ifname_found; + + PyObject *py_nic_name = NULL; + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + PyObject *py_is_up = NULL; + + if (py_retdict == NULL) + return NULL; + + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) + goto error; + + pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); + if (pIfTable == NULL) { + PyErr_NoMemory(); + goto error; + } + dwSize = sizeof(MIB_IFTABLE); + if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { + free(pIfTable); + pIfTable = (MIB_IFTABLE *) malloc(dwSize); + if (pIfTable == NULL) { + PyErr_NoMemory(); + goto error; + } + } + // Make a second call to GetIfTable to get the actual + // data we want. + if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) { + PyErr_SetString(PyExc_RuntimeError, "GetIfTable() syscall failed"); + goto error; + } + + for (i = 0; i < (int) pIfTable->dwNumEntries; i++) { + pIfRow = (MIB_IFROW *) & pIfTable->table[i]; + + // GetIfTable is not able to give us NIC with "friendly names" + // so we determine them via GetAdapterAddresses() which + // provides friendly names *and* descriptions and find the + // ones that match. + ifname_found = 0; + pCurrAddresses = pAddresses; + while (pCurrAddresses) { + sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description); + if (lstrcmp(descr, pIfRow->bDescr) == 0) { + py_nic_name = PyUnicode_FromWideChar( + pCurrAddresses->FriendlyName, + wcslen(pCurrAddresses->FriendlyName)); + if (py_nic_name == NULL) + goto error; + ifname_found = 1; + break; + } + pCurrAddresses = pCurrAddresses->Next; + } + if (ifname_found == 0) { + // Name not found means GetAdapterAddresses() doesn't list + // this NIC, only GetIfTable, meaning it's not really a NIC + // interface so we skip it. + continue; + } + + // is up? + if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || + pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) && + pIfRow->dwAdminStatus == 1 ) { + py_is_up = Py_True; + } + else { + py_is_up = Py_False; + } + Py_INCREF(py_is_up); + + py_ifc_info = Py_BuildValue( + "(Oikk)", + py_is_up, + 2, // there's no way to know duplex so let's assume 'full' + pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb + pIfRow->dwMtu + ); + if (!py_ifc_info) + goto error; + if (PyDict_SetItem(py_retdict, py_nic_name, py_ifc_info)) + goto error; + Py_DECREF(py_nic_name); + Py_DECREF(py_ifc_info); + } + + free(pIfTable); + free(pAddresses); + return py_retdict; + +error: + Py_XDECREF(py_is_up); + Py_XDECREF(py_ifc_info); + Py_XDECREF(py_nic_name); + Py_DECREF(py_retdict); + if (pIfTable != NULL) + free(pIfTable); + if (pAddresses != NULL) + free(pAddresses); + return NULL; +} + + +/* + * Return CPU statistics. + */ +static PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + // NtQuerySystemInformation stuff + typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + + NTSTATUS status; + _SYSTEM_PERFORMANCE_INFORMATION *spi = NULL; + _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; + _SYSTEM_INTERRUPT_INFORMATION *InterruptInformation = NULL; + SYSTEM_INFO si; + UINT i; + ULONG64 dpcs = 0; + ULONG interrupts = 0; + + // obtain NtQuerySystemInformation + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + if (hNtDll == NULL) { + PyErr_SetFromWindowsErr(0); + goto error; + } + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + if (NtQuerySystemInformation == NULL) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // retrives number of processors + GetSystemInfo(&si); + + // get syscalls / ctx switches + spi = (_SYSTEM_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PERFORMANCE_INFORMATION)); + if (spi == NULL) { + PyErr_NoMemory(); + goto error; + } + status = NtQuerySystemInformation( + SystemPerformanceInformation, + spi, + si.dwNumberOfProcessors * sizeof(_SYSTEM_PERFORMANCE_INFORMATION), + NULL); + if (status != 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // get DPCs + InterruptInformation = \ + malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) * + si.dwNumberOfProcessors); + if (InterruptInformation == NULL) { + PyErr_NoMemory(); + goto error; + } + + status = NtQuerySystemInformation( + SystemInterruptInformation, + InterruptInformation, + si.dwNumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION), + NULL); + if (status != 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + for (i = 0; i < si.dwNumberOfProcessors; i++) { + dpcs += InterruptInformation[i].DpcCount; + } + + // get interrupts + sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + if (sppi == NULL) { + PyErr_NoMemory(); + goto error; + } + + status = NtQuerySystemInformation( + SystemProcessorPerformanceInformation, + sppi, + si.dwNumberOfProcessors * sizeof + (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), + NULL); + if (status != 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + for (i = 0; i < si.dwNumberOfProcessors; i++) { + interrupts += sppi[i].InterruptCount; + } + + // done + free(spi); + free(InterruptInformation); + free(sppi); + FreeLibrary(hNtDll); + return Py_BuildValue( + "kkkk", + spi->ContextSwitches, + interrupts, + (unsigned long)dpcs, + spi->SystemCalls + ); + +error: + if (spi) + free(spi); + if (InterruptInformation) + free(InterruptInformation); + if (sppi) + free(sppi); + if (hNtDll) + FreeLibrary(hNtDll); + return NULL; +} + + +/* + * Return CPU frequency. + */ +static PyObject * +psutil_cpu_freq(PyObject *self, PyObject *args) { + PROCESSOR_POWER_INFORMATION *ppi; + NTSTATUS ret; + size_t size; + LPBYTE pBuffer = NULL; + ULONG current; + ULONG max; + unsigned int num_cpus; + SYSTEM_INFO system_info; + system_info.dwNumberOfProcessors = 0; + + // Get the number of CPUs. + GetSystemInfo(&system_info); + if (system_info.dwNumberOfProcessors == 0) + num_cpus = 1; + else + num_cpus = system_info.dwNumberOfProcessors; + + // Allocate size. + size = num_cpus * sizeof(PROCESSOR_POWER_INFORMATION); + pBuffer = (BYTE*)LocalAlloc(LPTR, size); + if (! pBuffer) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + + // Syscall. + ret = CallNtPowerInformation( + ProcessorInformation, NULL, 0, pBuffer, size); + if (ret != 0) { + PyErr_SetString(PyExc_RuntimeError, + "CallNtPowerInformation syscall failed"); + goto error; + } + + // Results. + ppi = (PROCESSOR_POWER_INFORMATION *)pBuffer; + max = ppi->MaxMhz; + current = ppi->CurrentMhz; + LocalFree(pBuffer); + + return Py_BuildValue("kk", current, max); + +error: + if (pBuffer != NULL) + LocalFree(pBuffer); + return NULL; +} + + +/* + * Return battery usage stats. + */ +static PyObject * +psutil_sensors_battery(PyObject *self, PyObject *args) { + SYSTEM_POWER_STATUS sps; + + if (GetSystemPowerStatus(&sps) == 0) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + return Py_BuildValue( + "iiiI", + sps.ACLineStatus, // whether AC is connected: 0=no, 1=yes, 255=unknown + // status flag: + // 1, 2, 4 = high, low, critical + // 8 = charging + // 128 = no battery + sps.BatteryFlag, + sps.BatteryLifePercent, // percent + sps.BatteryLifeTime // remaining secs + ); +} + + +// ------------------------ Python init --------------------------- + +static PyMethodDef +PsutilMethods[] = { + + // --- per-process functions + + {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, + "Return process cmdline as a list of cmdline arguments"}, + {"proc_environ", psutil_proc_environ, METH_VARARGS, + "Return process environment data"}, + {"proc_exe", psutil_proc_exe, METH_VARARGS, + "Return path of the process executable"}, + {"proc_name", psutil_proc_name, METH_VARARGS, + "Return process name"}, + {"proc_kill", psutil_proc_kill, METH_VARARGS, + "Kill the process identified by the given PID"}, + {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, + "Return tuple of user/kern time for the given PID"}, + {"proc_create_time", psutil_proc_create_time, METH_VARARGS, + "Return a float indicating the process create time expressed in " + "seconds since the epoch"}, + {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, + "Return a tuple of process memory information"}, + {"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS, + "Return the USS of the process"}, + {"proc_cwd", psutil_proc_cwd, METH_VARARGS, + "Return process current working directory"}, + {"proc_suspend", psutil_proc_suspend, METH_VARARGS, + "Suspend a process"}, + {"proc_resume", psutil_proc_resume, METH_VARARGS, + "Resume a process"}, + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process"}, + {"proc_username", psutil_proc_username, METH_VARARGS, + "Return the username of a process"}, + {"proc_threads", psutil_proc_threads, METH_VARARGS, + "Return process threads information as a list of tuple"}, + {"proc_wait", psutil_proc_wait, METH_VARARGS, + "Wait for process to terminate and return its exit code."}, + {"proc_priority_get", psutil_proc_priority_get, METH_VARARGS, + "Return process priority."}, + {"proc_priority_set", psutil_proc_priority_set, METH_VARARGS, + "Set process priority."}, +#if (_WIN32_WINNT >= 0x0600) // Windows Vista + {"proc_io_priority_get", psutil_proc_io_priority_get, METH_VARARGS, + "Return process IO priority."}, + {"proc_io_priority_set", psutil_proc_io_priority_set, METH_VARARGS, + "Set process IO priority."}, +#endif + {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, + "Return process CPU affinity as a bitmask."}, + {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, + "Set process CPU affinity."}, + {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, + "Get process I/O counters."}, + {"proc_is_suspended", psutil_proc_is_suspended, METH_VARARGS, + "Return True if one of the process threads is in a suspended state"}, + {"proc_num_handles", psutil_proc_num_handles, METH_VARARGS, + "Return the number of handles opened by process."}, + {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, + "Return a list of process's memory mappings"}, + + // --- alternative pinfo interface + {"proc_info", psutil_proc_info, METH_VARARGS, + "Various process information"}, + + // --- system-related functions + {"pids", psutil_pids, METH_VARARGS, + "Returns a list of PIDs currently running on the system"}, + {"ppid_map", psutil_ppid_map, METH_VARARGS, + "Return a {pid:ppid, ...} dict for all running processes"}, + {"pid_exists", psutil_pid_exists, METH_VARARGS, + "Determine if the process exists in the current process list."}, + {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, + "Returns the number of logical CPUs on the system"}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Returns the number of physical CPUs on the system"}, + {"boot_time", psutil_boot_time, METH_VARARGS, + "Return the system boot time expressed in seconds since the epoch."}, + {"virtual_mem", psutil_virtual_mem, METH_VARARGS, + "Return the total amount of physical memory, in bytes"}, + {"cpu_times", psutil_cpu_times, METH_VARARGS, + "Return system cpu times as a list"}, + {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, + "Return system per-cpu times as a list of tuples"}, + {"disk_usage", psutil_disk_usage, METH_VARARGS, + "Return path's disk total and free as a Python tuple."}, + {"net_io_counters", psutil_net_io_counters, METH_VARARGS, + "Return dict of tuples of networks I/O information."}, + {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, + "Return dict of tuples of disks I/O information."}, + {"users", psutil_users, METH_VARARGS, + "Return a list of currently connected users."}, + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return disk partitions."}, + {"net_connections", psutil_net_connections, METH_VARARGS, + "Return system-wide connections"}, + {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, + "Return NICs addresses."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NICs stats."}, + {"cpu_stats", psutil_cpu_stats, METH_VARARGS, + "Return NICs stats."}, + {"cpu_freq", psutil_cpu_freq, METH_VARARGS, + "Return CPU frequency."}, + {"sensors_battery", psutil_sensors_battery, METH_VARARGS, + "Return battery metrics usage."}, + + // --- windows services + {"winservice_enumerate", psutil_winservice_enumerate, METH_VARARGS, + "List all services"}, + {"winservice_query_config", psutil_winservice_query_config, METH_VARARGS, + "Return service config"}, + {"winservice_query_status", psutil_winservice_query_status, METH_VARARGS, + "Return service config"}, + {"winservice_query_descr", psutil_winservice_query_descr, METH_VARARGS, + "Return the description of a service"}, + {"winservice_start", psutil_winservice_start, METH_VARARGS, + "Start a service"}, + {"winservice_stop", psutil_winservice_stop, METH_VARARGS, + "Stop a service"}, + + // --- windows API bindings + {"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS, + "QueryDosDevice binding"}, + + {NULL, NULL, 0, NULL} +}; + + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +static struct module_state _state; +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int psutil_windows_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int psutil_windows_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_windows", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_windows_traverse, + psutil_windows_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_windows(void) + +#else +#define INITERROR return +void init_psutil_windows(void) +#endif +{ + struct module_state *st = NULL; +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_windows", PsutilMethods); +#endif + + if (module == NULL) { + INITERROR; + } + + st = GETSTATE(module); + st->error = PyErr_NewException("_psutil_windows.Error", NULL, NULL); + if (st->error == NULL) { + Py_DECREF(module); + INITERROR; + } + + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + + // process status constants + // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx + PyModule_AddIntConstant( + module, "ABOVE_NORMAL_PRIORITY_CLASS", ABOVE_NORMAL_PRIORITY_CLASS); + PyModule_AddIntConstant( + module, "BELOW_NORMAL_PRIORITY_CLASS", BELOW_NORMAL_PRIORITY_CLASS); + PyModule_AddIntConstant( + module, "HIGH_PRIORITY_CLASS", HIGH_PRIORITY_CLASS); + PyModule_AddIntConstant( + module, "IDLE_PRIORITY_CLASS", IDLE_PRIORITY_CLASS); + PyModule_AddIntConstant( + module, "NORMAL_PRIORITY_CLASS", NORMAL_PRIORITY_CLASS); + PyModule_AddIntConstant( + module, "REALTIME_PRIORITY_CLASS", REALTIME_PRIORITY_CLASS); + + // connection status constants + // http://msdn.microsoft.com/en-us/library/cc669305.aspx + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_CLOSED", MIB_TCP_STATE_CLOSED); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_CLOSING", MIB_TCP_STATE_CLOSING); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_CLOSE_WAIT", MIB_TCP_STATE_CLOSE_WAIT); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_LISTEN", MIB_TCP_STATE_LISTEN); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_ESTAB", MIB_TCP_STATE_ESTAB); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_SYN_SENT", MIB_TCP_STATE_SYN_SENT); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_SYN_RCVD", MIB_TCP_STATE_SYN_RCVD); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_FIN_WAIT1", MIB_TCP_STATE_FIN_WAIT1); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_FIN_WAIT2", MIB_TCP_STATE_FIN_WAIT2); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_LAST_ACK", MIB_TCP_STATE_LAST_ACK); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); + PyModule_AddIntConstant( + module, "MIB_TCP_STATE_DELETE_TCB", MIB_TCP_STATE_DELETE_TCB); + PyModule_AddIntConstant( + module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); + + // service status constants + /* + PyModule_AddIntConstant( + module, "SERVICE_CONTINUE_PENDING", SERVICE_CONTINUE_PENDING); + PyModule_AddIntConstant( + module, "SERVICE_PAUSE_PENDING", SERVICE_PAUSE_PENDING); + PyModule_AddIntConstant( + module, "SERVICE_PAUSED", SERVICE_PAUSED); + PyModule_AddIntConstant( + module, "SERVICE_RUNNING", SERVICE_RUNNING); + PyModule_AddIntConstant( + module, "SERVICE_START_PENDING", SERVICE_START_PENDING); + PyModule_AddIntConstant( + module, "SERVICE_STOP_PENDING", SERVICE_STOP_PENDING); + PyModule_AddIntConstant( + module, "SERVICE_STOPPED", SERVICE_STOPPED); + */ + + // ...for internal use in _psutil_windows.py + PyModule_AddIntConstant( + module, "INFINITE", INFINITE); + PyModule_AddIntConstant( + module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); + PyModule_AddIntConstant( + module, "ERROR_INVALID_NAME", ERROR_INVALID_NAME); + PyModule_AddIntConstant( + module, "ERROR_SERVICE_DOES_NOT_EXIST", ERROR_SERVICE_DOES_NOT_EXIST); + + // set SeDebug for the current process + psutil_set_se_debug(); + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/pipenv/vendor/psutil/_pswindows.py b/pipenv/vendor/psutil/_pswindows.py new file mode 100644 index 00000000..0105d6c8 --- /dev/null +++ b/pipenv/vendor/psutil/_pswindows.py @@ -0,0 +1,965 @@ +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Windows platform implementation.""" + +import contextlib +import errno +import functools +import os +import sys +from collections import namedtuple + +from . import _common +try: + from . import _psutil_windows as cext +except ImportError as err: + if str(err).lower().startswith("dll load failed") and \ + sys.getwindowsversion()[0] < 6: + # We may get here if: + # 1) we are on an old Windows version + # 2) psutil was installed via pip + wheel + # See: https://github.com/giampaolo/psutil/issues/811 + # It must be noted that psutil can still (kind of) work + # on outdated systems if compiled / installed from sources, + # but if we get here it means this this was a wheel (or exe). + msg = "this Windows version is too old (< Windows Vista); " + msg += "psutil 3.4.2 is the latest version which supports Windows " + msg += "2000, XP and 2003 server" + raise RuntimeError(msg) + else: + raise + +from ._common import conn_tmap +from ._common import isfile_strict +from ._common import parse_environ_block +from ._common import sockfam_to_enum +from ._common import socktype_to_enum +from ._common import usage_percent +from ._common import memoize_when_activated +from ._compat import long +from ._compat import lru_cache +from ._compat import PY3 +from ._compat import xrange +from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS +from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS +from ._psutil_windows import HIGH_PRIORITY_CLASS +from ._psutil_windows import IDLE_PRIORITY_CLASS +from ._psutil_windows import NORMAL_PRIORITY_CLASS +from ._psutil_windows import REALTIME_PRIORITY_CLASS + +if sys.version_info >= (3, 4): + import enum +else: + enum = None + +# process priority constants, import from __init__.py: +# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx +__extra__all__ = [ + "win_service_iter", "win_service_get", + "ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", + "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", + "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS", + "CONN_DELETE_TCB", + "AF_LINK", +] + + +# ===================================================================== +# --- globals +# ===================================================================== + + +CONN_DELETE_TCB = "DELETE_TCB" +WAIT_TIMEOUT = 0x00000102 # 258 in decimal +ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, + cext.ERROR_ACCESS_DENIED]) + +if enum is None: + AF_LINK = -1 +else: + AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) + AF_LINK = AddressFamily.AF_LINK + +TCP_STATUSES = { + cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED, + cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT, + cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV, + cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1, + cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2, + cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT, + cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE, + cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, + cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK, + cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN, + cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING, + cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB, + cext.PSUTIL_CONN_NONE: _common.CONN_NONE, +} + +if enum is not None: + class Priority(enum.IntEnum): + ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS + BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS + HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS + IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS + NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS + REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS + + globals().update(Priority.__members__) + +pinfo_map = dict( + num_handles=0, + ctx_switches=1, + user_time=2, + kernel_time=3, + create_time=4, + num_threads=5, + io_rcount=6, + io_wcount=7, + io_rbytes=8, + io_wbytes=9, + io_count_others=10, + io_bytes_others=11, + num_page_faults=12, + peak_wset=13, + wset=14, + peak_paged_pool=15, + paged_pool=16, + peak_non_paged_pool=17, + non_paged_pool=18, + pagefile=19, + peak_pagefile=20, + mem_private=21, +) + +# these get overwritten on "import psutil" from the __init__.py file +NoSuchProcess = None +AccessDenied = None +TimeoutExpired = None + + +# ===================================================================== +# --- named tuples +# ===================================================================== + + +# psutil.cpu_times() +scputimes = namedtuple('scputimes', + ['user', 'system', 'idle', 'interrupt', 'dpc']) +# psutil.virtual_memory() +svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) +# psutil.Process.memory_info() +pmem = namedtuple( + 'pmem', ['rss', 'vms', + 'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', + 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', + 'pagefile', 'peak_pagefile', 'private']) +# psutil.Process.memory_full_info() +pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', )) +# psutil.Process.memory_maps(grouped=True) +pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss']) +# psutil.Process.memory_maps(grouped=False) +pmmap_ext = namedtuple( + 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) +# psutil.Process.io_counters() +pio = namedtuple('pio', ['read_count', 'write_count', + 'read_bytes', 'write_bytes', + 'other_count', 'other_bytes']) + + +# ===================================================================== +# --- utils +# ===================================================================== + + +@lru_cache(maxsize=512) +def convert_dos_path(s): + """Convert paths using native DOS format like: + "\Device\HarddiskVolume1\Windows\systemew\file.txt" + into: + "C:\Windows\systemew\file.txt" + """ + if PY3 and not isinstance(s, str): + s = s.decode('utf8') + rawdrive = '\\'.join(s.split('\\')[:3]) + driveletter = cext.win32_QueryDosDevice(rawdrive) + return os.path.join(driveletter, s[len(rawdrive):]) + + +def py2_strencode(s, encoding=sys.getfilesystemencoding()): + """Encode a string in the given encoding. Falls back on returning + the string as is if it can't be encoded. + """ + if PY3 or isinstance(s, str): + return s + else: + try: + return s.encode(encoding) + except UnicodeEncodeError: + # Filesystem codec failed, return the plain unicode + # string (this should never happen). + return s + + +# ===================================================================== +# --- memory +# ===================================================================== + + +def virtual_memory(): + """System virtual memory as a namedtuple.""" + mem = cext.virtual_mem() + totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem + # + total = totphys + avail = availphys + free = availphys + used = total - avail + percent = usage_percent((total - avail), total, _round=1) + return svmem(total, avail, percent, used, free) + + +def swap_memory(): + """Swap system memory as a (total, used, free, sin, sout) tuple.""" + mem = cext.virtual_mem() + total = mem[2] + free = mem[3] + used = total - free + percent = usage_percent(used, total, _round=1) + return _common.sswap(total, used, free, percent, 0, 0) + + +# ===================================================================== +# --- disk +# ===================================================================== + + +disk_io_counters = cext.disk_io_counters + + +def disk_usage(path): + """Return disk usage associated with path.""" + try: + total, free = cext.disk_usage(path) + except WindowsError: + if not os.path.exists(path): + msg = "No such file or directory: '%s'" % path + raise OSError(errno.ENOENT, msg) + raise + used = total - free + percent = usage_percent(used, total, _round=1) + return _common.sdiskusage(total, used, free, percent) + + +def disk_partitions(all): + """Return disk partitions.""" + rawlist = cext.disk_partitions(all) + return [_common.sdiskpart(*x) for x in rawlist] + + +# ===================================================================== +# --- CPU +# ===================================================================== + + +def cpu_times(): + """Return system CPU times as a named tuple.""" + user, system, idle = cext.cpu_times() + # Internally, GetSystemTimes() is used, and it doesn't return + # interrupt and dpc times. cext.per_cpu_times() does, so we + # rely on it to get those only. + percpu_summed = scputimes(*[sum(n) for n in zip(*cext.per_cpu_times())]) + return scputimes(user, system, idle, + percpu_summed.interrupt, percpu_summed.dpc) + + +def per_cpu_times(): + """Return system per-CPU times as a list of named tuples.""" + ret = [] + for user, system, idle, interrupt, dpc in cext.per_cpu_times(): + item = scputimes(user, system, idle, interrupt, dpc) + ret.append(item) + return ret + + +def cpu_count_logical(): + """Return the number of logical CPUs in the system.""" + return cext.cpu_count_logical() + + +def cpu_count_physical(): + """Return the number of physical CPUs in the system.""" + return cext.cpu_count_phys() + + +def cpu_stats(): + """Return CPU statistics.""" + ctx_switches, interrupts, dpcs, syscalls = cext.cpu_stats() + soft_interrupts = 0 + return _common.scpustats(ctx_switches, interrupts, soft_interrupts, + syscalls) + + +def cpu_freq(): + """Return CPU frequency. + On Windows per-cpu frequency is not supported. + """ + curr, max_ = cext.cpu_freq() + min_ = 0.0 + return [_common.scpufreq(float(curr), min_, float(max_))] + + +# ===================================================================== +# --- network +# ===================================================================== + + +def net_connections(kind, _pid=-1): + """Return socket connections. If pid == -1 return system-wide + connections (as opposed to connections opened by one process only). + """ + if kind not in conn_tmap: + raise ValueError("invalid %r kind argument; choose between %s" + % (kind, ', '.join([repr(x) for x in conn_tmap]))) + families, types = conn_tmap[kind] + rawlist = cext.net_connections(_pid, families, types) + ret = set() + for item in rawlist: + fd, fam, type, laddr, raddr, status, pid = item + status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + if _pid == -1: + nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) + else: + nt = _common.pconn(fd, fam, type, laddr, raddr, status) + ret.add(nt) + return list(ret) + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + ret = cext.net_if_stats() + for name, items in ret.items(): + name = py2_strencode(name) + isup, duplex, speed, mtu = items + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + +def net_io_counters(): + """Return network I/O statistics for every network interface + installed on the system as a dict of raw tuples. + """ + ret = cext.net_io_counters() + return dict([(py2_strencode(k), v) for k, v in ret.items()]) + + +def net_if_addrs(): + """Return the addresses associated to each NIC.""" + ret = [] + for items in cext.net_if_addrs(): + items = list(items) + items[0] = py2_strencode(items[0]) + ret.append(items) + return ret + + +# ===================================================================== +# --- sensors +# ===================================================================== + + +def sensors_battery(): + """Return battery information.""" + # For constants meaning see: + # https://msdn.microsoft.com/en-us/library/windows/desktop/ + # aa373232(v=vs.85).aspx + acline_status, flags, percent, secsleft = cext.sensors_battery() + power_plugged = acline_status == 1 + no_battery = bool(flags & 128) + charging = bool(flags & 8) + + if no_battery: + return None + if power_plugged or charging: + secsleft = _common.POWER_TIME_UNLIMITED + elif secsleft == -1: + secsleft = _common.POWER_TIME_UNKNOWN + + return _common.sbattery(percent, secsleft, power_plugged) + + +# ===================================================================== +# --- other system functions +# ===================================================================== + + +def boot_time(): + """The system boot time expressed in seconds since the epoch.""" + return cext.boot_time() + + +def users(): + """Return currently connected users as a list of namedtuples.""" + retlist = [] + rawlist = cext.users() + for item in rawlist: + user, hostname, tstamp = item + user = py2_strencode(user) + nt = _common.suser(user, None, hostname, tstamp) + retlist.append(nt) + return retlist + + +# ===================================================================== +# --- Windows services +# ===================================================================== + + +def win_service_iter(): + """Return a list of WindowsService instances.""" + for name, display_name in cext.winservice_enumerate(): + yield WindowsService(name, display_name) + + +def win_service_get(name): + """Open a Windows service and return it as a WindowsService instance.""" + service = WindowsService(name, None) + service._display_name = service._query_config()['display_name'] + return service + + +class WindowsService(object): + """Represents an installed Windows service.""" + + def __init__(self, name, display_name): + self._name = name + self._display_name = display_name + + def __str__(self): + details = "(name=%r, display_name=%r)" % ( + self._name, self._display_name) + return "%s%s" % (self.__class__.__name__, details) + + def __repr__(self): + return "<%s at %s>" % (self.__str__(), id(self)) + + def __eq__(self, other): + # Test for equality with another WindosService object based + # on name. + if not isinstance(other, WindowsService): + return NotImplemented + return self._name == other._name + + def __ne__(self, other): + return not self == other + + def _query_config(self): + with self._wrap_exceptions(): + display_name, binpath, username, start_type = \ + cext.winservice_query_config(self._name) + # XXX - update _self.display_name? + return dict( + display_name=display_name, + binpath=binpath, + username=username, + start_type=start_type) + + def _query_status(self): + with self._wrap_exceptions(): + status, pid = cext.winservice_query_status(self._name) + if pid == 0: + pid = None + return dict(status=status, pid=pid) + + @contextlib.contextmanager + def _wrap_exceptions(self): + """Ctx manager which translates bare OSError and WindowsError + exceptions into NoSuchProcess and AccessDenied. + """ + try: + yield + except WindowsError as err: + NO_SUCH_SERVICE_SET = (cext.ERROR_INVALID_NAME, + cext.ERROR_SERVICE_DOES_NOT_EXIST) + if err.errno in ACCESS_DENIED_SET: + raise AccessDenied( + pid=None, name=self._name, + msg="service %r is not querable (not enough privileges)" % + self._name) + elif err.errno in NO_SUCH_SERVICE_SET or \ + err.winerror in NO_SUCH_SERVICE_SET: + raise NoSuchProcess( + pid=None, name=self._name, + msg="service %r does not exist)" % self._name) + else: + raise + + # config query + + def name(self): + """The service name. This string is how a service is referenced + and can be passed to win_service_get() to get a new + WindowsService instance. + """ + return self._name + + def display_name(self): + """The service display name. The value is cached when this class + is instantiated. + """ + return self._display_name + + def binpath(self): + """The fully qualified path to the service binary/exe file as + a string, including command line arguments. + """ + return self._query_config()['binpath'] + + def username(self): + """The name of the user that owns this service.""" + return self._query_config()['username'] + + def start_type(self): + """A string which can either be "automatic", "manual" or + "disabled". + """ + return self._query_config()['start_type'] + + # status query + + def pid(self): + """The process PID, if any, else None. This can be passed + to Process class to control the service's process. + """ + return self._query_status()['pid'] + + def status(self): + """Service status as a string.""" + return self._query_status()['status'] + + def description(self): + """Service long description.""" + return cext.winservice_query_descr(self.name()) + + # utils + + def as_dict(self): + """Utility method retrieving all the information above as a + dictionary. + """ + d = self._query_config() + d.update(self._query_status()) + d['name'] = self.name() + d['display_name'] = self.display_name() + d['description'] = self.description() + return d + + # actions + # XXX: the necessary C bindings for start() and stop() are + # implemented but for now I prefer not to expose them. + # I may change my mind in the future. Reasons: + # - they require Administrator privileges + # - can't implement a timeout for stop() (unless by using a thread, + # which sucks) + # - would require adding ServiceAlreadyStarted and + # ServiceAlreadyStopped exceptions, adding two new APIs. + # - we might also want to have modify(), which would basically mean + # rewriting win32serviceutil.ChangeServiceConfig, which involves a + # lot of stuff (and API constants which would pollute the API), see: + # http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/ + # win32/lib/win32serviceutil.py.html#0175 + # - psutil is typically about "read only" monitoring stuff; + # win_service_* APIs should only be used to retrieve a service and + # check whether it's running + + # def start(self, timeout=None): + # with self._wrap_exceptions(): + # cext.winservice_start(self.name()) + # if timeout: + # giveup_at = time.time() + timeout + # while True: + # if self.status() == "running": + # return + # else: + # if time.time() > giveup_at: + # raise TimeoutExpired(timeout) + # else: + # time.sleep(.1) + + # def stop(self): + # # Note: timeout is not implemented because it's just not + # # possible, see: + # # http://stackoverflow.com/questions/11973228/ + # with self._wrap_exceptions(): + # return cext.winservice_stop(self.name()) + + +# ===================================================================== +# --- processes +# ===================================================================== + + +pids = cext.pids +pid_exists = cext.pid_exists +ppid_map = cext.ppid_map # used internally by Process.children() + + +def wrap_exceptions(fun): + """Decorator which translates bare OSError and WindowsError + exceptions into NoSuchProcess and AccessDenied. + """ + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + raise AccessDenied(self.pid, self._name) + if err.errno == errno.ESRCH: + raise NoSuchProcess(self.pid, self._name) + raise + return wrapper + + +class Process(object): + """Wrapper class around underlying C implementation.""" + + __slots__ = ["pid", "_name", "_ppid"] + + def __init__(self, pid): + self.pid = pid + self._name = None + self._ppid = None + + # --- oneshot() stuff + + def oneshot_enter(self): + self.oneshot_info.cache_activate() + + def oneshot_exit(self): + self.oneshot_info.cache_deactivate() + + @memoize_when_activated + def oneshot_info(self): + """Return multiple information about this process as a + raw tuple. + """ + ret = cext.proc_info(self.pid) + assert len(ret) == len(pinfo_map) + return ret + + @wrap_exceptions + def name(self): + """Return process name, which on Windows is always the final + part of the executable. + """ + # This is how PIDs 0 and 4 are always represented in taskmgr + # and process-hacker. + if self.pid == 0: + return "System Idle Process" + elif self.pid == 4: + return "System" + else: + try: + # Note: this will fail with AD for most PIDs owned + # by another user but it's faster. + return py2_strencode(os.path.basename(self.exe())) + except AccessDenied: + return py2_strencode(cext.proc_name(self.pid)) + + @wrap_exceptions + def exe(self): + # Note: os.path.exists(path) may return False even if the file + # is there, see: + # http://stackoverflow.com/questions/3112546/os-path-exists-lies + + # see https://github.com/giampaolo/psutil/issues/414 + # see https://github.com/giampaolo/psutil/issues/528 + if self.pid in (0, 4): + raise AccessDenied(self.pid, self._name) + return py2_strencode(convert_dos_path(cext.proc_exe(self.pid))) + + @wrap_exceptions + def cmdline(self): + ret = cext.proc_cmdline(self.pid) + if PY3: + return ret + else: + return [py2_strencode(s) for s in ret] + + @wrap_exceptions + def environ(self): + return parse_environ_block(cext.proc_environ(self.pid)) + + def ppid(self): + try: + return ppid_map()[self.pid] + except KeyError: + raise NoSuchProcess(self.pid, self._name) + + def _get_raw_meminfo(self): + try: + return cext.proc_memory_info(self.pid) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + # TODO: the C ext can probably be refactored in order + # to get this from cext.proc_info() + info = self.oneshot_info() + return ( + info[pinfo_map['num_page_faults']], + info[pinfo_map['peak_wset']], + info[pinfo_map['wset']], + info[pinfo_map['peak_paged_pool']], + info[pinfo_map['paged_pool']], + info[pinfo_map['peak_non_paged_pool']], + info[pinfo_map['non_paged_pool']], + info[pinfo_map['pagefile']], + info[pinfo_map['peak_pagefile']], + info[pinfo_map['mem_private']], + ) + raise + + @wrap_exceptions + def memory_info(self): + # on Windows RSS == WorkingSetSize and VSM == PagefileUsage. + # Underlying C function returns fields of PROCESS_MEMORY_COUNTERS + # struct. + t = self._get_raw_meminfo() + rss = t[2] # wset + vms = t[7] # pagefile + return pmem(*(rss, vms, ) + t) + + @wrap_exceptions + def memory_full_info(self): + basic_mem = self.memory_info() + uss = cext.proc_memory_uss(self.pid) + return pfullmem(*basic_mem + (uss, )) + + def memory_maps(self): + try: + raw = cext.proc_memory_maps(self.pid) + except OSError as err: + # XXX - can't use wrap_exceptions decorator as we're + # returning a generator; probably needs refactoring. + if err.errno in ACCESS_DENIED_SET: + raise AccessDenied(self.pid, self._name) + if err.errno == errno.ESRCH: + raise NoSuchProcess(self.pid, self._name) + raise + else: + for addr, perm, path, rss in raw: + path = convert_dos_path(path) + addr = hex(addr) + yield (addr, perm, path, rss) + + @wrap_exceptions + def kill(self): + return cext.proc_kill(self.pid) + + @wrap_exceptions + def send_signal(self, sig): + os.kill(self.pid, sig) + + @wrap_exceptions + def wait(self, timeout=None): + if timeout is None: + cext_timeout = cext.INFINITE + else: + # WaitForSingleObject() expects time in milliseconds + cext_timeout = int(timeout * 1000) + ret = cext.proc_wait(self.pid, cext_timeout) + if ret == WAIT_TIMEOUT: + raise TimeoutExpired(timeout, self.pid, self._name) + return ret + + @wrap_exceptions + def username(self): + if self.pid in (0, 4): + return 'NT AUTHORITY\\SYSTEM' + return cext.proc_username(self.pid) + + @wrap_exceptions + def create_time(self): + # special case for kernel process PIDs; return system boot time + if self.pid in (0, 4): + return boot_time() + try: + return cext.proc_create_time(self.pid) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + return self.oneshot_info()[pinfo_map['create_time']] + raise + + @wrap_exceptions + def num_threads(self): + return self.oneshot_info()[pinfo_map['num_threads']] + + @wrap_exceptions + def threads(self): + rawlist = cext.proc_threads(self.pid) + retlist = [] + for thread_id, utime, stime in rawlist: + ntuple = _common.pthread(thread_id, utime, stime) + retlist.append(ntuple) + return retlist + + @wrap_exceptions + def cpu_times(self): + try: + user, system = cext.proc_cpu_times(self.pid) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + info = self.oneshot_info() + user = info[pinfo_map['user_time']] + system = info[pinfo_map['kernel_time']] + else: + raise + # Children user/system times are not retrievable (set to 0). + return _common.pcputimes(user, system, 0, 0) + + @wrap_exceptions + def suspend(self): + return cext.proc_suspend(self.pid) + + @wrap_exceptions + def resume(self): + return cext.proc_resume(self.pid) + + @wrap_exceptions + def cwd(self): + if self.pid in (0, 4): + raise AccessDenied(self.pid, self._name) + # return a normalized pathname since the native C function appends + # "\\" at the and of the path + path = cext.proc_cwd(self.pid) + return py2_strencode(os.path.normpath(path)) + + @wrap_exceptions + def open_files(self): + if self.pid in (0, 4): + return [] + ret = set() + # Filenames come in in native format like: + # "\Device\HarddiskVolume1\Windows\systemew\file.txt" + # Convert the first part in the corresponding drive letter + # (e.g. "C:\") by using Windows's QueryDosDevice() + raw_file_names = cext.proc_open_files(self.pid) + for _file in raw_file_names: + _file = convert_dos_path(_file) + if isfile_strict(_file): + if not PY3: + _file = py2_strencode(_file) + ntuple = _common.popenfile(_file, -1) + ret.add(ntuple) + return list(ret) + + @wrap_exceptions + def connections(self, kind='inet'): + return net_connections(kind, _pid=self.pid) + + @wrap_exceptions + def nice_get(self): + value = cext.proc_priority_get(self.pid) + if enum is not None: + value = Priority(value) + return value + + @wrap_exceptions + def nice_set(self, value): + return cext.proc_priority_set(self.pid, value) + + # available on Windows >= Vista + if hasattr(cext, "proc_io_priority_get"): + @wrap_exceptions + def ionice_get(self): + return cext.proc_io_priority_get(self.pid) + + @wrap_exceptions + def ionice_set(self, value, _): + if _: + raise TypeError("set_proc_ionice() on Windows takes only " + "1 argument (2 given)") + if value not in (2, 1, 0): + raise ValueError("value must be 2 (normal), 1 (low) or 0 " + "(very low); got %r" % value) + return cext.proc_io_priority_set(self.pid, value) + + @wrap_exceptions + def io_counters(self): + try: + ret = cext.proc_io_counters(self.pid) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + info = self.oneshot_info() + ret = ( + info[pinfo_map['io_rcount']], + info[pinfo_map['io_wcount']], + info[pinfo_map['io_rbytes']], + info[pinfo_map['io_wbytes']], + info[pinfo_map['io_count_others']], + info[pinfo_map['io_bytes_others']], + ) + else: + raise + return pio(*ret) + + @wrap_exceptions + def status(self): + suspended = cext.proc_is_suspended(self.pid) + if suspended: + return _common.STATUS_STOPPED + else: + return _common.STATUS_RUNNING + + @wrap_exceptions + def cpu_affinity_get(self): + def from_bitmask(x): + return [i for i in xrange(64) if (1 << i) & x] + bitmask = cext.proc_cpu_affinity_get(self.pid) + return from_bitmask(bitmask) + + @wrap_exceptions + def cpu_affinity_set(self, value): + def to_bitmask(l): + if not l: + raise ValueError("invalid argument %r" % l) + out = 0 + for b in l: + out |= 2 ** b + return out + + # SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER + # is returned for an invalid CPU but this seems not to be true, + # therefore we check CPUs validy beforehand. + allcpus = list(range(len(per_cpu_times()))) + for cpu in value: + if cpu not in allcpus: + if not isinstance(cpu, (int, long)): + raise TypeError( + "invalid CPU %r; an integer is required" % cpu) + else: + raise ValueError("invalid CPU %r" % cpu) + + bitmask = to_bitmask(value) + cext.proc_cpu_affinity_set(self.pid, bitmask) + + @wrap_exceptions + def num_handles(self): + try: + return cext.proc_num_handles(self.pid) + except OSError as err: + if err.errno in ACCESS_DENIED_SET: + return self.oneshot_info()[pinfo_map['num_handles']] + raise + + @wrap_exceptions + def num_ctx_switches(self): + ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']] + # only voluntary ctx switches are supported + return _common.pctxsw(ctx_switches, 0) diff --git a/pipenv/vendor/psutil/arch/bsd/freebsd.c b/pipenv/vendor/psutil/arch/bsd/freebsd.c new file mode 100644 index 00000000..0bec81d8 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/freebsd.c @@ -0,0 +1,1020 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Helper functions related to fetching process information. + * Used by _psutil_bsd module methods. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // needed for vmtotal struct +#include // for swap mem +#include // process open files, shared libs (kinfo_getvmmap), cwd +#include + +#include "../../_psutil_common.h" + + +#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) +#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * (uint32_t) \ + (bt.frac >> 32) ) >> 32 ) / 1000000) +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif + + +// ============================================================================ +// Utility functions +// ============================================================================ + + +int +psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { + // Fills a kinfo_proc struct based on process pid. + int mib[4]; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + size = sizeof(struct kinfo_proc); + if (sysctl((int *)mib, 4, proc, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +// remove spaces from string +static void psutil_remove_spaces(char *str) { + char *p1 = str; + char *p2 = str; + do + while (*p2 == ' ') + p2++; + while ((*p1++ = *p2++)); +} + + +// ============================================================================ +// APIS +// ============================================================================ + +int +psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { + // Returns a list of all BSD processes on the system. This routine + // allocates the list and puts it in *procList and a count of the + // number of entries in *procCount. You are responsible for freeing + // this list (use "free" from System framework). + // On success, the function returns 0. + // On error, the function returns a BSD errno value. + int err; + struct kinfo_proc *result; + int done; + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; + size_t length; + + assert( procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + *procCount = 0; + + /* + * We start by calling sysctl with result == NULL and length == 0. + * That will succeed, and set length to the appropriate length. + * We then allocate a buffer of that size and call sysctl again + * with that buffer. If that succeeds, we're done. If that fails + * with ENOMEM, we have to throw away our buffer and loop. Note + * that the loop causes use to call sysctl with NULL again; this + * is necessary because the ENOMEM failure case sets length to + * the amount of data returned, not the amount of data that + * could have been returned. + */ + result = NULL; + done = 0; + do { + assert(result == NULL); + // Call sysctl with a NULL buffer. + length = 0; + err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, + NULL, &length, NULL, 0); + if (err == -1) + err = errno; + + // Allocate an appropriately sized buffer based on the results + // from the previous call. + if (err == 0) { + result = malloc(length); + if (result == NULL) + err = ENOMEM; + } + + // Call sysctl again with the new buffer. If we get an ENOMEM + // error, toss away our buffer and start again. + if (err == 0) { + err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, + result, &length, NULL, 0); + if (err == -1) + err = errno; + if (err == 0) { + done = 1; + } + else if (err == ENOMEM) { + assert(result != NULL); + free(result); + result = NULL; + err = 0; + } + } + } while (err == 0 && ! done); + + // Clean up and establish post conditions. + if (err != 0 && result != NULL) { + free(result); + result = NULL; + } + + *procList = result; + *procCount = length / sizeof(struct kinfo_proc); + + assert((err == 0) == (*procList != NULL)); + return err; +} + + +/* + * XXX no longer used; it probably makese sense to remove it. + * Borrowed from psi Python System Information project + * + * Get command arguments and environment variables. + * + * Based on code from ps. + * + * Returns: + * 0 for success; + * -1 for failure (Exception raised); + * 1 for insufficient privileges. + */ +static char +*psutil_get_cmd_args(long pid, size_t *argsize) { + int mib[4], argmax; + size_t size = sizeof(argmax); + char *procargs = NULL; + + // Get the maximum process arguments size. + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + size = sizeof(argmax); + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) + return NULL; + + // Allocate space for the arguments. + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* + * Make a sysctl() call to get the raw argument space of the process. + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ARGS; + mib[3] = pid; + + size = argmax; + if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) { + free(procargs); + return NULL; // Insufficient privileges + } + + // return string and set the length of arguments + *argsize = size; + return procargs; +} + + +// returns the command line as a python list object +PyObject * +psutil_get_cmdline(long pid) { + char *argstr = NULL; + int pos = 0; + size_t argsize = 0; + PyObject *py_retlist = Py_BuildValue("[]"); + PyObject *py_arg = NULL; + + if (pid < 0) + return py_retlist; + argstr = psutil_get_cmd_args(pid, &argsize); + if (argstr == NULL) + goto error; + + // args are returned as a flattened string with \0 separators between + // arguments add each string to the list then step forward to the next + // separator + if (argsize > 0) { + while (pos < argsize) { +#if PY_MAJOR_VERSION >= 3 + py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]); +#else + py_arg = Py_BuildValue("s", &argstr[pos]); +#endif + if (!py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); + pos = pos + strlen(&argstr[pos]) + 1; + } + } + + free(argstr); + return py_retlist; + +error: + Py_XDECREF(py_arg); + Py_DECREF(py_retlist); + if (argstr != NULL) + free(argstr); + return NULL; +} + + +/* + * Return process pathname executable. + * Thanks to Robert N. M. Watson: + * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT + */ +PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { + long pid; + char pathname[PATH_MAX]; + int error; + int mib[4]; + int ret; + size_t size; + const char *encoding_errs; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = pid; + + size = sizeof(pathname); + error = sysctl(mib, 4, pathname, &size, NULL, 0); + if (error == -1) { + if (errno == ENOENT) { + // see: https://github.com/giampaolo/psutil/issues/907 + return Py_BuildValue("s", ""); + } + else { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + } + if (size == 0 || strlen(pathname) == 0) { + ret = psutil_pid_exists(pid); + if (ret == -1) + return NULL; + else if (ret == 0) + return NoSuchProcess(); + else + strcpy(pathname, ""); + } + +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(pathname); +#else + return Py_BuildValue("s", pathname); +#endif + +} + + +PyObject * +psutil_proc_num_threads(PyObject *self, PyObject *args) { + // Return number of threads used by process as a Python integer. + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + return Py_BuildValue("l", (long)kp.ki_numthreads); +} + + +PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + // Retrieves all threads used by process returning a list of tuples + // including thread id, user time and system time. + // Thanks to Robert N. M. Watson: + // http://fxr.googlebit.com/source/usr.bin/procstat/ + // procstat_threads.c?v=8-CURRENT + long pid; + int mib[4]; + struct kinfo_proc *kip = NULL; + struct kinfo_proc *kipp = NULL; + int error; + unsigned int i; + size_t size; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + // we need to re-query for thread information, so don't use *kipp + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; + mib[3] = pid; + + size = 0; + error = sysctl(mib, 4, NULL, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + kip = malloc(size); + if (kip == NULL) { + PyErr_NoMemory(); + goto error; + } + + error = sysctl(mib, 4, kip, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + for (i = 0; i < size / sizeof(*kipp); i++) { + kipp = &kip[i]; + py_tuple = Py_BuildValue("Idd", + kipp->ki_tid, + PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_utime), + PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_stime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + free(kip); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kip != NULL) + free(kip); + return NULL; +} + + +PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + // Return an XML string from which we'll determine the number of + // physical CPU cores in the system. + void *topology = NULL; + size_t size = 0; + PyObject *py_str; + + if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) + goto error; + + topology = malloc(size); + if (!topology) { + PyErr_NoMemory(); + return NULL; + } + + if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) + goto error; + + py_str = Py_BuildValue("s", topology); + free(topology); + return py_str; + +error: + if (topology != NULL) + free(topology); + Py_RETURN_NONE; +} + + +/* + * Return virtual memory usage statistics. + */ +PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + unsigned long total; + unsigned int active, inactive, wired, cached, free; + size_t size = sizeof(total); + struct vmtotal vm; + int mib[] = {CTL_VM, VM_METER}; + long pagesize = getpagesize(); +#if __FreeBSD_version > 702101 + long buffers; +#else + int buffers; +#endif + size_t buffers_size = sizeof(buffers); + + if (sysctlbyname("hw.physmem", &total, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_inactive_count", + &inactive, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) + goto error; + if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) + goto error; + + size = sizeof(vm); + if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0) + goto error; + + return Py_BuildValue("KKKKKKKK", + (unsigned long long) total, + (unsigned long long) free * pagesize, + (unsigned long long) active * pagesize, + (unsigned long long) inactive * pagesize, + (unsigned long long) wired * pagesize, + (unsigned long long) cached * pagesize, + (unsigned long long) buffers, + (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared + ); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + // Return swap memory stats (see 'swapinfo' cmdline tool) + kvm_t *kd; + struct kvm_swap kvmsw[1]; + unsigned int swapin, swapout, nodein, nodeout; + size_t size = sizeof(unsigned int); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed"); + if (kd == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kvm_open() syscall failed"); + return NULL; + } + + if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) { + kvm_close(kd); + PyErr_SetString(PyExc_RuntimeError, + "kvm_getswapinfo() syscall failed"); + return NULL; + } + + kvm_close(kd); + + if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1) + goto sbn_error; + + return Py_BuildValue("(iiiII)", + kvmsw[0].ksw_total, // total + kvmsw[0].ksw_used, // used + kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free + swapin + swapout, // swap in + nodein + nodeout); // swap out + +sbn_error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 +PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + long pid; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + struct kinfo_proc kipp; + const char *encoding_errs; + PyObject *py_path = NULL; + + int i, cnt; + + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; + if (kif->kf_fd == KF_FD_TYPE_CWD) { +#if PY_MAJOR_VERSION >= 3 + py_path = PyUnicode_DecodeFSDefault(kif->kf_path); +#else + py_path = Py_BuildValue("s", kif->kf_path); +#endif + if (!py_path) + goto error; + break; + } + } + /* + * For lower pids it seems we can't retrieve any information + * (lsof can't do that it either). Since this happens even + * as root we return an empty string instead of AccessDenied. + */ + if (py_path == NULL) + py_path = Py_BuildValue("s", ""); + free(freep); + return py_path; + +error: + Py_XDECREF(py_path); + if (freep != NULL) + free(freep); + return NULL; +} +#endif + + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 +PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + struct kinfo_proc kipp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) + return NULL; + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} +#endif + + +PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + static int maxcpus; + int mib[2]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + // retrieve maxcpus value + size = sizeof(maxcpus); + if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { + Py_DECREF(py_retlist); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + long cpu_time[maxcpus][CPUSTATES]; + + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // per-cpu info + size = sizeof(cpu_time); + if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < ncpu; i++) { + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + int i; + struct statinfo stats; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + + if (py_retdict == NULL) + return NULL; + if (devstat_checkversion(NULL) < 0) { + PyErr_Format(PyExc_RuntimeError, + "devstat_checkversion() syscall failed"); + goto error; + } + + stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); + if (stats.dinfo == NULL) { + PyErr_NoMemory(); + goto error; + } + bzero(stats.dinfo, sizeof(struct devinfo)); + + if (devstat_getdevs(NULL, &stats) == -1) { + PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() syscall failed"); + goto error; + } + + for (i = 0; i < stats.dinfo->numdevs; i++) { + py_disk_info = NULL; + struct devstat current; + char disk_name[128]; + current = stats.dinfo->devices[i]; + snprintf(disk_name, sizeof(disk_name), "%s%d", + current.device_name, + current.unit_number); + + py_disk_info = Py_BuildValue( + "(KKKKLLL)", + current.operations[DEVSTAT_READ], // no reads + current.operations[DEVSTAT_WRITE], // no writes + current.bytes[DEVSTAT_READ], // bytes read + current.bytes[DEVSTAT_WRITE], // bytes written + (long long) PSUTIL_BT2MSEC(current.duration[DEVSTAT_READ]), // r time + (long long) PSUTIL_BT2MSEC(current.duration[DEVSTAT_WRITE]), // w time + (long long) PSUTIL_BT2MSEC(current.busy_time) // busy time + ); // finished transactions + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + if (stats.dinfo->mem_ptr) + free(stats.dinfo->mem_ptr); + free(stats.dinfo); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats.dinfo != NULL) + free(stats.dinfo); + return NULL; +} + + +PyObject * +psutil_proc_memory_maps(PyObject *self, PyObject *args) { + // Return a list of tuples for every process memory maps. + //'procstat' cmdline utility has been used as an example. + long pid; + int ptrwidth; + int i, cnt; + char addr[1000]; + char perms[4]; + const char *path; + struct kinfo_proc kp; + struct kinfo_vmentry *freep = NULL; + struct kinfo_vmentry *kve; + ptrwidth = 2 * sizeof(void *); + PyObject *py_tuple = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kp) == -1) + goto error; + + errno = 0; + freep = kinfo_getvmmap(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getvmmap() failed"); + goto error; + } + for (i = 0; i < cnt; i++) { + py_tuple = NULL; + kve = &freep[i]; + addr[0] = '\0'; + perms[0] = '\0'; + sprintf(addr, "%#*jx-%#*jx", ptrwidth, (uintmax_t)kve->kve_start, + ptrwidth, (uintmax_t)kve->kve_end); + psutil_remove_spaces(addr); + strlcat(perms, kve->kve_protection & KVME_PROT_READ ? "r" : "-", + sizeof(perms)); + strlcat(perms, kve->kve_protection & KVME_PROT_WRITE ? "w" : "-", + sizeof(perms)); + strlcat(perms, kve->kve_protection & KVME_PROT_EXEC ? "x" : "-", + sizeof(perms)); + + if (strlen(kve->kve_path) == 0) { + switch (kve->kve_type) { + case KVME_TYPE_NONE: + path = "[none]"; + break; + case KVME_TYPE_DEFAULT: + path = "[default]"; + break; + case KVME_TYPE_VNODE: + path = "[vnode]"; + break; + case KVME_TYPE_SWAP: + path = "[swap]"; + break; + case KVME_TYPE_DEVICE: + path = "[device]"; + break; + case KVME_TYPE_PHYS: + path = "[phys]"; + break; + case KVME_TYPE_DEAD: + path = "[dead]"; + break; + case KVME_TYPE_SG: + path = "[sg]"; + break; + case KVME_TYPE_UNKNOWN: + path = "[unknown]"; + break; + default: + path = "[?]"; + break; + } + } + else { + path = kve->kve_path; + } + + py_tuple = Py_BuildValue("sssiiii", + addr, // "start-end" address + perms, // "rwx" permissions + path, // path + kve->kve_resident, // rss + kve->kve_private_resident, // private + kve->kve_ref_count, // ref count + kve->kve_shadow_count); // shadow count + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + free(freep); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + return NULL; +} + + +PyObject* +psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) { + // Get process CPU affinity. + // Reference: + // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + long pid; + int ret; + int i; + cpuset_t mask; + PyObject* py_retlist; + PyObject* py_cpu_num; + + if (!PyArg_ParseTuple(args, "i", &pid)) + return NULL; + ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(mask), &mask); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_retlist = PyList_New(0); + if (py_retlist == NULL) + return NULL; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, &mask)) { + py_cpu_num = Py_BuildValue("i", i); + if (py_cpu_num == NULL) + goto error; + if (PyList_Append(py_retlist, py_cpu_num)) + goto error; + } + } + + return py_retlist; + +error: + Py_XDECREF(py_cpu_num); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { + // Set process CPU affinity. + // Reference: + // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + long pid; + int i; + int seq_len; + int ret; + cpuset_t cpu_set; + PyObject *py_cpu_set; + PyObject *py_cpu_seq = NULL; + + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; + + py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); + if (!py_cpu_seq) + return NULL; + seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); + + // calculate the mask + CPU_ZERO(&cpu_set); + for (i = 0; i < seq_len; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); +#if PY_MAJOR_VERSION >= 3 + long value = PyLong_AsLong(item); +#else + long value = PyInt_AsLong(item); +#endif + if (value == -1 || PyErr_Occurred()) + goto error; + CPU_SET(value, &cpu_set); + } + + // set affinity + ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(cpu_set), &cpu_set); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + Py_DECREF(py_cpu_seq); + Py_RETURN_NONE; + +error: + if (py_cpu_seq != NULL) + Py_DECREF(py_cpu_seq); + return NULL; +} + + +PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + unsigned int v_soft; + unsigned int v_intr; + unsigned int v_syscall; + unsigned int v_trap; + unsigned int v_swtch; + size_t size = sizeof(v_soft); + + if (sysctlbyname("vm.stats.sys.v_soft", &v_soft, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.sys.v_intr", &v_intr, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.sys.v_syscall", &v_syscall, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.sys.v_trap", &v_trap, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.sys.v_swtch", &v_swtch, &size, NULL, 0)) + goto error; + + return Py_BuildValue( + "IIIII", + v_swtch, // ctx switches + v_intr, // interrupts + v_soft, // software interrupts + v_syscall, // syscalls + v_trap // traps + ); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Return battery information. + */ +PyObject * +psutil_sensors_battery(PyObject *self, PyObject *args) { + int percent; + int minsleft; + int power_plugged; + size_t size = sizeof(percent); + + if (sysctlbyname("hw.acpi.battery.life", &percent, &size, NULL, 0)) + goto error; + if (sysctlbyname("hw.acpi.battery.time", &minsleft, &size, NULL, 0)) + goto error; + if (sysctlbyname("hw.acpi.acline", &power_plugged, &size, NULL, 0)) + goto error; + return Py_BuildValue("iii", percent, minsleft, power_plugged); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} diff --git a/pipenv/vendor/psutil/arch/bsd/freebsd.h b/pipenv/vendor/psutil/arch/bsd/freebsd.h new file mode 100644 index 00000000..0df66ecc --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/freebsd.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +typedef struct kinfo_proc kinfo_proc; + +int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); +int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc); + +// +PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); +PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); +PyObject* psutil_get_cmdline(long pid); +PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); +PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); +PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); +PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); +PyObject* psutil_proc_exe(PyObject* self, PyObject* args); +PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); +PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); +PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); +PyObject* psutil_proc_threads(PyObject* self, PyObject* args); +PyObject* psutil_swap_mem(PyObject* self, PyObject* args); +PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); +PyObject* psutil_cpu_stats(PyObject* self, PyObject* args); +#if defined(PSUTIL_FREEBSD) +PyObject* psutil_sensors_battery(PyObject* self, PyObject* args); +#endif diff --git a/pipenv/vendor/psutil/arch/bsd/freebsd_socks.c b/pipenv/vendor/psutil/arch/bsd/freebsd_socks.c new file mode 100644 index 00000000..826b27f7 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/freebsd_socks.c @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include // for struct xsocket +#include +#include +#include +#include +#include // for xinpcb struct +#include +#include +#include +#include +#include +#include // for struct xtcpcb +#include // for TCP connection states +#include // for inet_ntop() +#include +#include + +#include "../../_psutil_common.h" + + +#define HASHSIZE 1009 +// a signaler for connections without an actual status +static int PSUTIL_CONN_NONE = 128; +static struct xfile *psutil_xfiles; +static int psutil_nxfiles; + + +// The tcplist fetching and walking is borrowed from netstat/inet.c. +static char * +psutil_fetch_tcplist(void) { + char *buf; + size_t len; + + for (;;) { + if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) { + free(buf); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return buf; + } +} + + +static int +psutil_sockaddr_port(int family, struct sockaddr_storage *ss) { + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (sin->sin_port); + } + else { + sin6 = (struct sockaddr_in6 *)ss; + return (sin6->sin6_port); + } +} + + +static void * +psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) { + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (&sin->sin_addr); + } + else { + sin6 = (struct sockaddr_in6 *)ss; + return (&sin6->sin6_addr); + } +} + + +static socklen_t +psutil_sockaddr_addrlen(int family) { + if (family == AF_INET) + return (sizeof(struct in_addr)); + else + return (sizeof(struct in6_addr)); +} + + +static int +psutil_sockaddr_matches(int family, int port, void *pcb_addr, + struct sockaddr_storage *ss) { + if (psutil_sockaddr_port(family, ss) != port) + return (0); + return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, + psutil_sockaddr_addrlen(family)) == 0); +} + + +static struct tcpcb * +psutil_search_tcplist(char *buf, struct kinfo_file *kif) { + struct tcpcb *tp; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + + oxig = xig = (struct xinpgen *)buf; + for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); + xig->xig_len > sizeof(struct xinpgen); + xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { + tp = &((struct xtcpcb *)xig)->xt_tp; + inp = &((struct xtcpcb *)xig)->xt_inp; + so = &((struct xtcpcb *)xig)->xt_socket; + + if (so->so_type != kif->kf_sock_type || + so->xso_family != kif->kf_sock_domain || + so->xso_protocol != kif->kf_sock_protocol) + continue; + + if (kif->kf_sock_domain == AF_INET) { + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_lport, &inp->inp_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_fport, &inp->inp_faddr, + &kif->kf_sa_peer)) + continue; + } else { + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_lport, &inp->in6p_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_fport, &inp->in6p_faddr, + &kif->kf_sa_peer)) + continue; + } + + return (tp); + } + return NULL; +} + + +int +psutil_populate_xfiles() { + size_t len; + + if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) { + PyErr_NoMemory(); + return 0; + } + while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) { + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + return 0; + } + len *= 2; + if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) { + PyErr_NoMemory(); + return 0; + } + } + if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) { + PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch"); + return 0; + } + psutil_nxfiles = len / sizeof *psutil_xfiles; + return 1; +} + + +int +psutil_get_pid_from_sock(int sock_hash) { + struct xfile *xf; + int hash, n; + for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) { + if (xf->xf_data == NULL) + continue; + hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); + if (sock_hash == hash) + return xf->xf_pid; + } + return -1; +} + + +// Reference: +// https://gitorious.org/freebsd/freebsd/source/ +// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c +int psutil_gather_inet(int proto, PyObject *py_retlist) { + struct xinpgen *xig, *exig; + struct xinpcb *xip; + struct xtcpcb *xtp; + struct inpcb *inp; + struct xsocket *so; + const char *varname = NULL; + size_t len, bufsize; + void *buf; + int hash; + int retry; + int type; + + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + + switch (proto) { + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + type = SOCK_STREAM; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + type = SOCK_DGRAM; + break; + } + + buf = NULL; + bufsize = 8192; + retry = 5; + do { + for (;;) { + buf = realloc(buf, bufsize); + if (buf == NULL) + continue; // XXX + len = bufsize; + if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) + break; + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + goto error; + } + bufsize *= 2; + } + xig = (struct xinpgen *)buf; + exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); + if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) { + PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); + goto error; + } + } while (xig->xig_gen != exig->xig_gen && retry--); + + for (;;) { + int lport, rport, pid, status, family; + + xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); + if (xig >= exig) + break; + + switch (proto) { + case IPPROTO_TCP: + xtp = (struct xtcpcb *)xig; + if (xtp->xt_len != sizeof *xtp) { + PyErr_Format(PyExc_RuntimeError, + "struct xtcpcb size mismatch"); + goto error; + } + inp = &xtp->xt_inp; + so = &xtp->xt_socket; + status = xtp->xt_tp.t_state; + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)xig; + if (xip->xi_len != sizeof *xip) { + PyErr_Format(PyExc_RuntimeError, + "struct xinpcb size mismatch"); + goto error; + } + inp = &xip->xi_inp; + so = &xip->xi_socket; + status = PSUTIL_CONN_NONE; + break; + default: + PyErr_Format(PyExc_RuntimeError, "invalid proto"); + goto error; + } + + char lip[200], rip[200]; + + hash = (int)((uintptr_t)so->xso_so % HASHSIZE); + pid = psutil_get_pid_from_sock(hash); + if (pid < 0) + continue; + lport = ntohs(inp->inp_lport); + rport = ntohs(inp->inp_fport); + + if (inp->inp_vflag & INP_IPV4) { + family = AF_INET; + inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip)); + inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip)); + } + else if (inp->inp_vflag & INP_IPV6) { + family = AF_INET6; + inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip)); + inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip)); + } + + // construct python tuple/list + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr, + py_raddr, status, pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + free(buf); + return 1; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + free(buf); + return 0; +} + + +int psutil_gather_unix(int proto, PyObject *py_retlist) { + struct xunpgen *xug, *exug; + struct xunpcb *xup; + const char *varname = NULL; + const char *protoname = NULL; + size_t len; + size_t bufsize; + void *buf; + int hash; + int retry; + int pid; + struct sockaddr_un *sun; + char path[PATH_MAX]; + + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + + switch (proto) { + case SOCK_STREAM: + varname = "net.local.stream.pcblist"; + protoname = "stream"; + break; + case SOCK_DGRAM: + varname = "net.local.dgram.pcblist"; + protoname = "dgram"; + break; + } + + buf = NULL; + bufsize = 8192; + retry = 5; + + do { + for (;;) { + buf = realloc(buf, bufsize); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + len = bufsize; + if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) + break; + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + goto error; + } + bufsize *= 2; + } + xug = (struct xunpgen *)buf; + exug = (struct xunpgen *)(void *) + ((char *)buf + len - sizeof *exug); + if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) { + PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); + goto error; + } + } while (xug->xug_gen != exug->xug_gen && retry--); + + for (;;) { + xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); + if (xug >= exug) + break; + xup = (struct xunpcb *)xug; + if (xup->xu_len != sizeof *xup) + goto error; + + hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE); + pid = psutil_get_pid_from_sock(hash); + if (pid < 0) + continue; + + sun = (struct sockaddr_un *)&xup->xu_addr; + snprintf(path, sizeof(path), "%.*s", + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + sun->sun_path); + + py_tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, + Py_None, PSUTIL_CONN_NONE, pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_INCREF(Py_None); + } + + free(buf); + return 1; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + free(buf); + return 0; +} + + +PyObject* +psutil_net_connections(PyObject* self, PyObject* args) { + // Return system-wide open connections. + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + if (psutil_populate_xfiles() != 1) + goto error; + if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) + goto error; + if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) + goto error; + if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0) + goto error; + if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0) + goto error; + + free(psutil_xfiles); + return py_retlist; + +error: + Py_DECREF(py_retlist); + free(psutil_xfiles); + return NULL; +} + + +PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) { + // Return connections opened by process. + long pid; + int i, cnt; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + char *tcplist = NULL; + struct tcpcb *tcp; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_family = NULL; + PyObject *py_type = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + goto error; + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + goto error; + } + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + goto error; + } + + tcplist = psutil_fetch_tcplist(); + if (tcplist == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < cnt; i++) { + int lport, rport, state; + char lip[200], rip[200]; + char path[PATH_MAX]; + int inseq; + py_tuple = NULL; + py_laddr = NULL; + py_raddr = NULL; + + kif = &freep[i]; + if (kif->kf_type == KF_TYPE_SOCKET) { + // apply filters + py_family = PyLong_FromLong((long)kif->kf_sock_domain); + inseq = PySequence_Contains(py_af_filter, py_family); + Py_DECREF(py_family); + if (inseq == 0) + continue; + py_type = PyLong_FromLong((long)kif->kf_sock_type); + inseq = PySequence_Contains(py_type_filter, py_type); + Py_DECREF(py_type); + if (inseq == 0) + continue; + // IPv4 / IPv6 socket + if ((kif->kf_sock_domain == AF_INET) || + (kif->kf_sock_domain == AF_INET6)) { + // fill status + state = PSUTIL_CONN_NONE; + if (kif->kf_sock_type == SOCK_STREAM) { + tcp = psutil_search_tcplist(tcplist, kif); + if (tcp != NULL) + state = (int)tcp->t_state; + } + + // build addr and port + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_local), + lip, + sizeof(lip)); + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_peer), + rip, + sizeof(rip)); + lport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_local)); + rport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_peer)); + + // construct python tuple/list + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else + py_raddr = Py_BuildValue("()"); + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue( + "(iiiNNi)", + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, + py_laddr, + py_raddr, + state + ); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + // UNIX socket + else if (kif->kf_sock_domain == AF_UNIX) { + struct sockaddr_un *sun; + + sun = (struct sockaddr_un *)&kif->kf_sa_local; + snprintf( + path, sizeof(path), "%.*s", + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + sun->sun_path); + + py_tuple = Py_BuildValue( + "(iiisOi)", + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, + path, + Py_None, + PSUTIL_CONN_NONE + ); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_INCREF(Py_None); + } + } + } + free(freep); + free(tcplist); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + if (tcplist != NULL) + free(tcplist); + return NULL; +} diff --git a/pipenv/vendor/psutil/arch/bsd/freebsd_socks.h b/pipenv/vendor/psutil/arch/bsd/freebsd_socks.h new file mode 100644 index 00000000..15ccb0b3 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/freebsd_socks.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +PyObject* psutil_proc_connections(PyObject* self, PyObject* args); +PyObject* psutil_net_connections(PyObject* self, PyObject* args); diff --git a/pipenv/vendor/psutil/arch/bsd/netbsd.c b/pipenv/vendor/psutil/arch/bsd/netbsd.c new file mode 100644 index 00000000..d5c3e3b9 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/netbsd.c @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Platform-specific module methods for NetBSD. + */ + +#if defined(PSUTIL_NETBSD) + #define _KMEMUSER +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for swap_mem +#include +#include +// connection stuff +#include // for NI_MAXHOST +#include +#include // for CPUSTATES & CP_* +#define _KERNEL // for DTYPE_* +#include +#undef _KERNEL +#include // struct diskstats +#include +#include + + +#include "netbsd_socks.h" +#include "netbsd.h" +#include "../../_psutil_common.h" + +#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + + +// ============================================================================ +// Utility functions +// ============================================================================ + + +int +psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) { + // Fills a kinfo_proc struct based on process pid. + int ret; + int mib[6]; + size_t size = sizeof(kinfo_proc); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC2; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + mib[4] = size; + mib[5] = 1; + + ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +struct kinfo_file * +kinfo_getfile(pid_t pid, int* cnt) { + // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an + // int as arg and returns an array with cnt struct kinfo_file. + int mib[6]; + size_t len; + struct kinfo_file* kf; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE2; + mib[2] = KERN_FILE_BYPID; + mib[3] = (int) pid; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + // get the size of what would be returned + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if ((kf = malloc(len)) == NULL) { + PyErr_NoMemory(); + return NULL; + } + mib[5] = (int)(len / sizeof(struct kinfo_file)); + if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *cnt = (int)(len / sizeof(struct kinfo_file)); + return kf; +} + + +// XXX: This is no longer used as per +// https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820 +// Current implementation uses /proc instead. +// Left here just in case. +PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { +#if __NetBSD_Version__ >= 799000000 + pid_t pid; + char pathname[MAXPATHLEN]; + int error; + int mib[4]; + int ret; + size_t size; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (pid == 0) { + // else returns ENOENT + return Py_BuildValue("s", ""); + } + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = KERN_PROC_PATHNAME; + + size = sizeof(pathname); + error = sysctl(mib, 4, NULL, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + error = sysctl(mib, 4, pathname, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (size == 0 || strlen(pathname) == 0) { + ret = psutil_pid_exists(pid); + if (ret == -1) + return NULL; + else if (ret == 0) + return NoSuchProcess(); + else + strcpy(pathname, ""); + } + +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(pathname); +#else + return Py_BuildValue("s", pathname); +#endif + +#else + return Py_BuildValue("s", ""); +#endif +} + +PyObject * +psutil_proc_num_threads(PyObject *self, PyObject *args) { + // Return number of threads used by process as a Python integer. + long pid; + kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + return Py_BuildValue("l", (long)kp.p_nlwps); +} + +PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + pid_t pid; + int mib[5]; + int i, nlwps; + ssize_t st; + size_t size; + struct kinfo_lwp *kl = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + mib[0] = CTL_KERN; + mib[1] = KERN_LWP; + mib[2] = pid; + mib[3] = sizeof(struct kinfo_lwp); + mib[4] = 0; + + st = sysctl(mib, 5, NULL, &size, NULL, 0); + if (st == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + mib[4] = size / sizeof(size_t); + kl = malloc(size); + if (kl == NULL) { + PyErr_NoMemory(); + goto error; + } + + st = sysctl(mib, 5, kl, &size, NULL, 0); + if (st == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + nlwps = (int)(size / sizeof(struct kinfo_lwp)); + for (i = 0; i < nlwps; i++) { + py_tuple = Py_BuildValue("idd", + (&kl[i])->l_lid, + PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime), + PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + free(kl); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kl != NULL) + free(kl); + return NULL; +} + + +// ============================================================================ +// APIS +// ============================================================================ + +int +psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { + // Returns a list of all BSD processes on the system. This routine + // allocates the list and puts it in *procList and a count of the + // number of entries in *procCount. You are responsible for freeing + // this list (use "free" from System framework). + // On success, the function returns 0. + // On error, the function returns a BSD errno value. + kinfo_proc *result; + int done; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; + // Declaring name as const requires us to cast it when passing it to + // sysctl because the prototype doesn't include the const modifier. + size_t length; + char errbuf[_POSIX2_LINE_MAX]; + kinfo_proc *x; + int cnt; + kvm_t *kd; + + assert( procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + + if (kd == NULL) { + PyErr_Format( + PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf); + return errno; + } + + result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt); + if (result == NULL) { + PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() syscall failed"); + kvm_close(kd); + return errno; + } + + *procCount = (size_t)cnt; + + size_t mlen = cnt * sizeof(kinfo_proc); + + if ((*procList = malloc(mlen)) == NULL) { + PyErr_NoMemory(); + kvm_close(kd); + return errno; + } + + memcpy(*procList, result, mlen); + assert(*procList != NULL); + kvm_close(kd); + + return 0; +} + + +char * +psutil_get_cmd_args(pid_t pid, size_t *argsize) { + int mib[4]; + ssize_t st; + size_t argmax; + size_t size; + char *procargs = NULL; + + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + size = sizeof(argmax); + st = sysctl(mib, 2, &argmax, &size, NULL, 0); + if (st == -1) { + warn("failed to get kern.argmax"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + PyErr_NoMemory(); + return NULL; + } + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = KERN_PROC_ARGV; + + st = sysctl(mib, 4, procargs, &argmax, NULL, 0); + if (st == -1) { + warn("failed to get kern.procargs"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *argsize = argmax; + return procargs; +} + +// Return the command line as a python list object. +// XXX - most of the times sysctl() returns a truncated string. +// Also /proc/pid/cmdline behaves the same so it looks like this +// is a kernel bug. +PyObject * +psutil_get_cmdline(pid_t pid) { + char *argstr = NULL; + int pos = 0; + size_t argsize = 0; + PyObject *py_arg = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + if (pid == 0) + return py_retlist; + + argstr = psutil_get_cmd_args(pid, &argsize); + if (argstr == NULL) + goto error; + + // args are returned as a flattened string with \0 separators between + // arguments add each string to the list then step forward to the next + // separator + if (argsize > 0) { + while (pos < argsize) { +#if PY_MAJOR_VERSION >= 3 + py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]); +#else + py_arg = Py_BuildValue("s", &argstr[pos]); +#endif + if (!py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); + pos = pos + strlen(&argstr[pos]) + 1; + } + } + + free(argstr); + return py_retlist; + +error: + Py_XDECREF(py_arg); + Py_DECREF(py_retlist); + if (argstr != NULL) + free(argstr); + return NULL; +} + + +/* + * Virtual memory stats, taken from: + * https://github.com/satterly/zabbix-stats/blob/master/src/libs/zbxsysinfo/ + * netbsd/memory.c + */ +PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + size_t size; + struct uvmexp_sysctl uv; + int mib[] = {CTL_VM, VM_UVMEXP2}; + long pagesize = getpagesize(); + + size = sizeof(uv); + if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("KKKKKKKK", + (unsigned long long) uv.npages << uv.pageshift, // total + (unsigned long long) uv.free << uv.pageshift, // free + (unsigned long long) uv.active << uv.pageshift, // active + (unsigned long long) uv.inactive << uv.pageshift, // inactive + (unsigned long long) uv.wired << uv.pageshift, // wired + (unsigned long long) uv.filepages + uv.execpages * pagesize, // cached + // These are determined from /proc/meminfo in Python. + (unsigned long long) 0, // buffers + (unsigned long long) 0 // shared + ); +} + + +PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + uint64_t swap_total, swap_free; + struct swapent *swdev; + int nswap, i; + + nswap = swapctl(SWAP_NSWAP, 0, 0); + if (nswap == 0) { + // This means there's no swap partition. + return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0); + } + + swdev = calloc(nswap, sizeof(*swdev)); + if (swdev == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if (swapctl(SWAP_STATS, swdev, nswap) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // Total things up. + swap_total = swap_free = 0; + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + swap_total += swdev[i].se_nblks * DEV_BSIZE; + swap_free += (swdev[i].se_nblks - swdev[i].se_inuse) * DEV_BSIZE; + } + } + free(swdev); + + // Get swap in/out + unsigned int total; + size_t size = sizeof(total); + struct uvmexp_sysctl uv; + int mib[] = {CTL_VM, VM_UVMEXP2}; + long pagesize = getpagesize(); + size = sizeof(uv); + if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + return Py_BuildValue("(LLLll)", + swap_total, + (swap_total - swap_free), + swap_free, + (long) uv.pgswapin * pagesize, // swap in + (long) uv.pgswapout * pagesize); // swap out + +error: + free(swdev); +} + + +PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} + + +PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + // XXX: why static? + static int maxcpus; + int mib[3]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_cputime = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + uint64_t cpu_time[CPUSTATES]; + + for (i = 0; i < ncpu; i++) { + // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CP_TIME; + mib[2] = i; + size = sizeof(cpu_time); + if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { + warn("failed to get kern.cptime2"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + int i, dk_ndrive, mib[3]; + size_t len; + struct io_sysctl *stats; + PyObject *py_disk_info = NULL; + PyObject *py_retdict = PyDict_New(); + + if (py_retdict == NULL) + return NULL; + mib[0] = CTL_HW; + mib[1] = HW_IOSTATS; + mib[2] = sizeof(struct io_sysctl); + len = 0; + if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) { + warn("can't get HW_IOSTATS"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + dk_ndrive = (int)(len / sizeof(struct io_sysctl)); + + stats = malloc(len); + if (stats == NULL) { + PyErr_NoMemory(); + goto error; + } + if (sysctl(mib, 3, stats, &len, NULL, 0) < 0 ) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < dk_ndrive; i++) { + py_disk_info = Py_BuildValue( + "(KKKK)", + stats[i].rxfer, + stats[i].wxfer, + stats[i].rbytes, + stats[i].wbytes + ); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + free(stats); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats != NULL) + free(stats); + return NULL; +} + + +PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + size_t size; + struct uvmexp_sysctl uv; + int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2}; + + size = sizeof(uv); + if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue( + "IIIIIII", + uv.swtch, // ctx switches + uv.intrs, // interrupts - XXX always 0, will be determined via /proc + uv.softs, // soft interrupts + uv.syscalls, // syscalls - XXX always 0 + uv.traps, // traps + uv.faults, // faults + uv.forks // forks + ); +} diff --git a/pipenv/vendor/psutil/arch/bsd/netbsd.h b/pipenv/vendor/psutil/arch/bsd/netbsd.h new file mode 100644 index 00000000..96ad9f7d --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/netbsd.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +typedef struct kinfo_proc2 kinfo_proc; + +int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc); +struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt); +int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); +char *psutil_get_cmd_args(pid_t pid, size_t *argsize); + +// +PyObject *psutil_get_cmdline(pid_t pid); +PyObject *psutil_proc_threads(PyObject *self, PyObject *args); +PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); +PyObject *psutil_swap_mem(PyObject *self, PyObject *args); +PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); +PyObject *psutil_proc_connections(PyObject *self, PyObject *args); +PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); +PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); +PyObject* psutil_proc_exe(PyObject* self, PyObject* args); +PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); +PyObject* psutil_cpu_stats(PyObject* self, PyObject* args); diff --git a/pipenv/vendor/psutil/arch/bsd/netbsd_socks.c b/pipenv/vendor/psutil/arch/bsd/netbsd_socks.c new file mode 100644 index 00000000..c782a443 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/netbsd_socks.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * Copyright (c) 2015, Ryo ONODERA. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// a signaler for connections without an actual status +int PSUTIL_CONN_NONE = 128; + +// address family filter +enum af_filter { + INET, + INET4, + INET6, + TCP, + TCP4, + TCP6, + UDP, + UDP4, + UDP6, + UNIX, + ALL, +}; + +// kinfo_file results +struct kif { + SLIST_ENTRY(kif) kifs; + struct kinfo_file *kif; +}; + +// kinfo_file results list +SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead); + + +// kinfo_pcb results +struct kpcb { + SLIST_ENTRY(kpcb) kpcbs; + struct kinfo_pcb *kpcb; +}; + +// kinfo_pcb results list +SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead); + +static void psutil_kiflist_init(void); +static void psutil_kiflist_clear(void); +static void psutil_kpcblist_init(void); +static void psutil_kpcblist_clear(void); +static int psutil_get_files(void); +static int psutil_get_sockets(const char *name); +static int psutil_get_info(int aff); + + +// Initialize kinfo_file results list. +static void +psutil_kiflist_init(void) { + SLIST_INIT(&kihead); + return; +} + + +// Clear kinfo_file results list. +static void +psutil_kiflist_clear(void) { + while (!SLIST_EMPTY(&kihead)) { + SLIST_REMOVE_HEAD(&kihead, kifs); + } + + return; +} + + +// Initialize kinof_pcb result list. +static void +psutil_kpcblist_init(void) { + SLIST_INIT(&kpcbhead); + return; +} + + +// Clear kinof_pcb result list. +static void +psutil_kpcblist_clear(void) { + while (!SLIST_EMPTY(&kpcbhead)) { + SLIST_REMOVE_HEAD(&kpcbhead, kpcbs); + } + + return; +} + + +// Get all open files including socket. +static int +psutil_get_files(void) { + size_t len; + int mib[6]; + char *buf; + off_t offset; + int j; + + mib[0] = CTL_KERN; + mib[1] = KERN_FILE2; + mib[2] = KERN_FILE_BYFILE; + mib[3] = 0; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + offset = len % sizeof(off_t); + mib[5] = len / sizeof(struct kinfo_file); + + if ((buf = malloc(len + offset)) == NULL) { + PyErr_NoMemory(); + return -1; + } + + if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) { + free(buf); + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + len /= sizeof(struct kinfo_file); + struct kinfo_file *ki = (struct kinfo_file *)(buf + offset); + + for (j = 0; j < len; j++) { + struct kif *kif = malloc(sizeof(struct kif)); + kif->kif = &ki[j]; + SLIST_INSERT_HEAD(&kihead, kif, kifs); + } + + /* + // debug + struct kif *k; + SLIST_FOREACH(k, &kihead, kifs) { + printf("%d\n", k->kif->ki_pid); + } + */ + + return 0; +} + + +// Get open sockets. +static int +psutil_get_sockets(const char *name) { + size_t namelen; + int mib[8]; + int ret, j; + struct kinfo_pcb *pcb; + size_t len; + + memset(mib, 0, sizeof(mib)); + + if (sysctlnametomib(name, mib, &namelen) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + if ((pcb = malloc(len)) == NULL) { + PyErr_NoMemory(); + return -1; + } + memset(pcb, 0, len); + + mib[6] = sizeof(*pcb); + mib[7] = len / sizeof(*pcb); + + if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) { + free(pcb); + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + len /= sizeof(struct kinfo_pcb); + struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb; + + for (j = 0; j < len; j++) { + struct kpcb *kpcb = malloc(sizeof(struct kpcb)); + kpcb->kpcb = &kp[j]; + SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs); + } + + /* + // debug + struct kif *k; + struct kpcb *k; + SLIST_FOREACH(k, &kpcbhead, kpcbs) { + printf("ki_type: %d\n", k->kpcb->ki_type); + printf("ki_family: %d\n", k->kpcb->ki_family); + } + */ + + return 0; +} + + +// Collect open file and connections. +static int +psutil_get_info(int aff) { + switch (aff) { + case INET: + if (psutil_get_sockets("net.inet.tcp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet.udp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0) + return -1; + break; + case INET4: + if (psutil_get_sockets("net.inet.tcp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet.udp.pcblist") != 0) + return -1; + break; + case INET6: + if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0) + return -1; + break; + case TCP: + if (psutil_get_sockets("net.inet.tcp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0) + return -1; + break; + case TCP4: + if (psutil_get_sockets("net.inet.tcp.pcblist") != 0) + return -1; + break; + case TCP6: + if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0) + return -1; + break; + case UDP: + if (psutil_get_sockets("net.inet.udp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0) + return -1; + break; + case UDP4: + if (psutil_get_sockets("net.inet.udp.pcblist") != 0) + return -1; + break; + case UDP6: + if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0) + return -1; + break; + case UNIX: + if (psutil_get_sockets("net.local.stream.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.local.dgram.pcblist") != 0) + return -1; + break; + case ALL: + if (psutil_get_sockets("net.inet.tcp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet.udp.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.local.stream.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0) + return -1; + if (psutil_get_sockets("net.local.dgram.pcblist") != 0) + return -1; + break; + } + + return 0; +} + + +/* + * Return system-wide connections (unless a pid != -1 is passed). + */ +PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + pid_t pid; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + psutil_kiflist_init(); + psutil_kpcblist_init(); + if (psutil_get_files() != 0) + goto error; + if (psutil_get_info(ALL) != 0) + goto error; + + struct kif *k; + SLIST_FOREACH(k, &kihead, kifs) { + struct kpcb *kp; + if ((pid != -1) && (k->kif->ki_pid != pid)) + continue; + SLIST_FOREACH(kp, &kpcbhead, kpcbs) { + if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr) + continue; + char laddr[PATH_MAX]; + char raddr[PATH_MAX]; + int32_t lport; + int32_t rport; + int32_t status; + + // IPv4 or IPv6 + if ((kp->kpcb->ki_family == AF_INET) || + (kp->kpcb->ki_family == AF_INET6)) { + + if (kp->kpcb->ki_family == AF_INET) { + // IPv4 + struct sockaddr_in *sin_src = + (struct sockaddr_in *)&kp->kpcb->ki_src; + struct sockaddr_in *sin_dst = + (struct sockaddr_in *)&kp->kpcb->ki_dst; + // source addr and port + inet_ntop(AF_INET, &sin_src->sin_addr, laddr, + sizeof(laddr)); + lport = ntohs(sin_src->sin_port); + // remote addr and port + inet_ntop(AF_INET, &sin_dst->sin_addr, raddr, + sizeof(raddr)); + rport = ntohs(sin_dst->sin_port); + } + else { + // IPv6 + struct sockaddr_in6 *sin6_src = + (struct sockaddr_in6 *)&kp->kpcb->ki_src; + struct sockaddr_in6 *sin6_dst = + (struct sockaddr_in6 *)&kp->kpcb->ki_dst; + // local addr and port + inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr, + sizeof(laddr)); + lport = ntohs(sin6_src->sin6_port); + // remote addr and port + inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr, + sizeof(raddr)); + rport = ntohs(sin6_dst->sin6_port); + } + + // status + if (kp->kpcb->ki_type == SOCK_STREAM) + status = kp->kpcb->ki_tstate; + else + status = PSUTIL_CONN_NONE; + + // build addr tuple + py_laddr = Py_BuildValue("(si)", laddr, lport); + if (! py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", raddr, rport); + else + py_raddr = Py_BuildValue("()"); + if (! py_raddr) + goto error; + } + else if (kp->kpcb->ki_family == AF_UNIX) { + // UNIX sockets + struct sockaddr_un *sun_src = + (struct sockaddr_un *)&kp->kpcb->ki_src; + struct sockaddr_un *sun_dst = + (struct sockaddr_un *)&kp->kpcb->ki_dst; + strcpy(laddr, sun_src->sun_path); + strcpy(raddr, sun_dst->sun_path); + status = PSUTIL_CONN_NONE; + // TODO: handle unicode + py_laddr = Py_BuildValue("s", laddr); + if (! py_laddr) + goto error; + // TODO: handle unicode + py_raddr = Py_BuildValue("s", raddr); + if (! py_raddr) + goto error; + } + + // append tuple to list + py_tuple = Py_BuildValue( + "(iiiNNii)", + k->kif->ki_fd, + kp->kpcb->ki_family, + kp->kpcb->ki_type, + py_laddr, + py_raddr, + status, + k->kif->ki_pid); + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + + psutil_kiflist_clear(); + psutil_kpcblist_clear(); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + return 0; +} diff --git a/pipenv/vendor/psutil/arch/bsd/netbsd_socks.h b/pipenv/vendor/psutil/arch/bsd/netbsd_socks.h new file mode 100644 index 00000000..9e6a97c0 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/netbsd_socks.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * Copyright (c) 2015, Ryo ONODERA. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +PyObject *psutil_proc_connections(PyObject *, PyObject *); +PyObject *psutil_net_connections(PyObject *, PyObject *); diff --git a/pipenv/vendor/psutil/arch/bsd/openbsd.c b/pipenv/vendor/psutil/arch/bsd/openbsd.c new file mode 100644 index 00000000..dfa8999b --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/openbsd.c @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Platform-specific module methods for OpenBSD. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for VFS_* +#include // for swap_mem +#include // for vmtotal struct +#include +#include +// connection stuff +#include // for NI_MAXHOST +#include +#include // for CPUSTATES & CP_* +#define _KERNEL // for DTYPE_* +#include +#undef _KERNEL +#include // struct diskstats +#include // for inet_ntoa() +#include // for warn() & err() + + +#include "../../_psutil_common.h" + +#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +// #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + +// a signaler for connections without an actual status +int PSUTIL_CONN_NONE = 128; + + +// ============================================================================ +// Utility functions +// ============================================================================ + +int +psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { + // Fills a kinfo_proc struct based on process pid. + int ret; + int mib[6]; + size_t size = sizeof(struct kinfo_proc); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + mib[4] = size; + mib[5] = 1; + + ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +struct kinfo_file * +kinfo_getfile(long pid, int* cnt) { + // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an + // int as arg and returns an array with cnt struct kinfo_file. + int mib[6]; + size_t len; + struct kinfo_file* kf; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE; + mib[2] = KERN_FILE_BYPID; + mib[3] = (int) pid; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + /* get the size of what would be returned */ + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if ((kf = malloc(len)) == NULL) { + PyErr_NoMemory(); + return NULL; + } + mib[5] = (int)(len / sizeof(struct kinfo_file)); + if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *cnt = (int)(len / sizeof(struct kinfo_file)); + return kf; +} + + +// ============================================================================ +// APIS +// ============================================================================ + +int +psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { + // Returns a list of all BSD processes on the system. This routine + // allocates the list and puts it in *procList and a count of the + // number of entries in *procCount. You are responsible for freeing + // this list (use "free" from System framework). + // On success, the function returns 0. + // On error, the function returns a BSD errno value. + struct kinfo_proc *result; + // Declaring name as const requires us to cast it when passing it to + // sysctl because the prototype doesn't include the const modifier. + char errbuf[_POSIX2_LINE_MAX]; + int cnt; + kvm_t *kd; + + assert(procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + + if (kd == NULL) { + return errno; + } + + result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); + if (result == NULL) { + kvm_close(kd); + err(1, NULL); + return errno; + } + + *procCount = (size_t)cnt; + + size_t mlen = cnt * sizeof(struct kinfo_proc); + + if ((*procList = malloc(mlen)) == NULL) { + kvm_close(kd); + err(1, NULL); + return errno; + } + + memcpy(*procList, result, mlen); + assert(*procList != NULL); + kvm_close(kd); + + return 0; +} + + +char ** +_psutil_get_argv(long pid) { + static char **argv; + int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; + size_t argv_size = 128; + /* Loop and reallocate until we have enough space to fit argv. */ + for (;; argv_size *= 2) { + if ((argv = realloc(argv, argv_size)) == NULL) + err(1, NULL); + if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0) + return argv; + if (errno == ESRCH) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (errno != ENOMEM) + err(1, NULL); + } +} + + +// returns the command line as a python list object +PyObject * +psutil_get_cmdline(long pid) { + static char **argv; + char **p; + PyObject *py_arg = NULL; + PyObject *py_retlist = Py_BuildValue("[]"); + + if (!py_retlist) + return NULL; + if (pid < 0) + return py_retlist; + + if ((argv = _psutil_get_argv(pid)) == NULL) + goto error; + + for (p = argv; *p != NULL; p++) { +#if PY_MAJOR_VERSION >= 3 + py_arg = PyUnicode_DecodeFSDefault(*p); +#else + py_arg = Py_BuildValue("s", *p); +#endif + if (!py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); + } + return py_retlist; + +error: + Py_XDECREF(py_arg); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + // OpenBSD reference: + // https://github.com/janmojzis/pstree/blob/master/proc_kvm.c + // Note: this requires root access, else it will fail trying + // to access /dev/kmem. + long pid; + kvm_t *kd = NULL; + int nentries, i; + char errbuf[4096]; + struct kinfo_proc *kp; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); + if (! kd) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() syscall failed"); + goto error; + } + + kp = kvm_getprocs( + kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid, + sizeof(*kp), &nentries); + if (! kp) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() syscall failed"); + goto error; + } + + for (i = 0; i < nentries; i++) { + if (kp[i].p_tid < 0) + continue; + if (kp[i].p_pid == pid) { + py_tuple = Py_BuildValue( + "Idd", + kp[i].p_tid, + PSUTIL_KPT2DOUBLE(kp[i].p_uutime), + PSUTIL_KPT2DOUBLE(kp[i].p_ustime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + + kvm_close(kd); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kd != NULL) + kvm_close(kd); + return NULL; +} + + +PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + int64_t total_physmem; + int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; + int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT}; + int physmem_mib[] = {CTL_HW, HW_PHYSMEM64}; + int vmmeter_mib[] = {CTL_VM, VM_METER}; + size_t size; + struct uvmexp uvmexp; + struct bcachestats bcstats; + struct vmtotal vmdata; + long pagesize = getpagesize(); + + size = sizeof(total_physmem); + if (sysctl(physmem_mib, 2, &total_physmem, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + size = sizeof(uvmexp); + if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + size = sizeof(bcstats); + if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + size = sizeof(vmdata); + if (sysctl(vmmeter_mib, 2, &vmdata, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("KKKKKKKK", + // Note: many programs calculate total memory as + // "uvmexp.npages * pagesize" but this is incorrect and does not + // match "sysctl | grep hw.physmem". + (unsigned long long) total_physmem, + (unsigned long long) uvmexp.free * pagesize, + (unsigned long long) uvmexp.active * pagesize, + (unsigned long long) uvmexp.inactive * pagesize, + (unsigned long long) uvmexp.wired * pagesize, + // this is how "top" determines it + (unsigned long long) bcstats.numbufpages * pagesize, // cached + (unsigned long long) 0, // buffers + (unsigned long long) vmdata.t_vmshr + vmdata.t_rmshr // shared + ); +} + + +PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + uint64_t swap_total, swap_free; + struct swapent *swdev; + int nswap, i; + + if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if (swapctl(SWAP_STATS, swdev, nswap) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // Total things up. + swap_total = swap_free = 0; + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); + swap_total += swdev[i].se_nblks; + } + } + + free(swdev); + return Py_BuildValue("(LLLII)", + swap_total * DEV_BSIZE, + (swap_total - swap_free) * DEV_BSIZE, + swap_free * DEV_BSIZE, + // swap in / swap out is not supported as the + // swapent struct does not provide any info + // about it. + 0, 0); + +error: + free(swdev); + return NULL; +} + + +PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + struct kinfo_proc kipp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) + return NULL; + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} + + +PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + // Reference: + // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179 + long pid; + struct kinfo_proc kp; + char path[MAXPATHLEN]; + size_t pathlen = sizeof path; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + + int name[] = { CTL_KERN, KERN_PROC_CWD, pid }; + if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_DecodeFSDefault(path); +#else + return Py_BuildValue("s", path); +#endif +} + + +// see sys/kern/kern_sysctl.c lines 1100 and +// usr.bin/fstat/fstat.c print_inet_details() +static char * +psutil_convert_ipv4(int family, uint32_t addr[4]) { + struct in_addr a; + memcpy(&a, addr, sizeof(a)); + return inet_ntoa(a); +} + + +static char * +psutil_inet6_addrstr(struct in6_addr *p) +{ + struct sockaddr_in6 sin6; + static char hbuf[NI_MAXHOST]; + const int niflags = NI_NUMERICHOST; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *p; + if (IN6_IS_ADDR_LINKLOCAL(p) && + *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; + } + + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + hbuf, sizeof(hbuf), NULL, 0, niflags)) + return "invalid"; + + return hbuf; +} + + +PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) { + long pid; + int i, cnt; + + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + char *tcplist = NULL; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_family = NULL; + PyObject *_type = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + goto error; + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + goto error; + } + + errno = 0; + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_for_pid(pid, "kinfo_getfile() failed"); + goto error; + } + + for (i = 0; i < cnt; i++) { + int state; + int lport; + int rport; + char addrbuf[NI_MAXHOST + 2]; + int inseq; + struct in6_addr laddr6; + py_tuple = NULL; + py_laddr = NULL; + py_raddr = NULL; + + kif = &freep[i]; + if (kif->f_type == DTYPE_SOCKET) { + // apply filters + py_family = PyLong_FromLong((long)kif->so_family); + inseq = PySequence_Contains(py_af_filter, py_family); + Py_DECREF(py_family); + if (inseq == 0) + continue; + _type = PyLong_FromLong((long)kif->so_type); + inseq = PySequence_Contains(py_type_filter, _type); + Py_DECREF(_type); + if (inseq == 0) + continue; + + // IPv4 / IPv6 socket + if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { + // fill status + if (kif->so_type == SOCK_STREAM) + state = kif->t_state; + else + state = PSUTIL_CONN_NONE; + + // ports + lport = ntohs(kif->inp_lport); + rport = ntohs(kif->inp_fport); + + // local address, IPv4 + if (kif->so_family == AF_INET) { + py_laddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4(kif->so_family, kif->inp_laddru), + lport); + if (!py_laddr) + goto error; + } + else { + // local address, IPv6 + memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6)); + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_laddr = Py_BuildValue("(si)", addrbuf, lport); + if (!py_laddr) + goto error; + } + + if (rport != 0) { + // remote address, IPv4 + if (kif->so_family == AF_INET) { + py_raddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4( + kif->so_family, kif->inp_faddru), + rport); + } + else { + // remote address, IPv6 + memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6)); + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_raddr = Py_BuildValue("(si)", addrbuf, rport); + if (!py_raddr) + goto error; + } + } + else { + py_raddr = Py_BuildValue("()"); + } + + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue( + "(iiiNNi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + py_laddr, + py_raddr, + state); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + // UNIX socket + else if (kif->so_family == AF_UNIX) { + py_tuple = Py_BuildValue( + "(iiisOi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + kif->unp_path, + Py_None, + PSUTIL_CONN_NONE); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_INCREF(Py_None); + } + } + } + free(freep); + free(tcplist); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + if (tcplist != NULL) + free(tcplist); + return NULL; +} + + +PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + int mib[3]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + uint64_t cpu_time[CPUSTATES]; + + for (i = 0; i < ncpu; i++) { + // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME2; + mib[2] = i; + size = sizeof(cpu_time); + if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { + warn("failed to get kern.cptime2"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + int i, dk_ndrive, mib[3]; + size_t len; + struct diskstats *stats; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + if (py_retdict == NULL) + return NULL; + + mib[0] = CTL_HW; + mib[1] = HW_DISKSTATS; + len = 0; + if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { + warn("can't get hw.diskstats size"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + dk_ndrive = (int)(len / sizeof(struct diskstats)); + + stats = malloc(len); + if (stats == NULL) { + warn("can't malloc"); + PyErr_NoMemory(); + goto error; + } + if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { + warn("could not read hw.diskstats"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < dk_ndrive; i++) { + py_disk_info = Py_BuildValue( + "(KKKK)", + stats[i].ds_rxfer, // num reads + stats[i].ds_wxfer, // num writes + stats[i].ds_rbytes, // read bytes + stats[i].ds_wbytes // write bytes + ); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + free(stats); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats != NULL) + free(stats); + return NULL; +} + + +PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + size_t size; + struct uvmexp uv; + int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; + + size = sizeof(uv); + if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue( + "IIIIIII", + uv.swtch, // ctx switches + uv.intrs, // interrupts - XXX always 0, will be determined via /proc + uv.softs, // soft interrupts + uv.syscalls, // syscalls - XXX always 0 + uv.traps, // traps + uv.faults, // faults + uv.forks // forks + ); +} diff --git a/pipenv/vendor/psutil/arch/bsd/openbsd.h b/pipenv/vendor/psutil/arch/bsd/openbsd.h new file mode 100644 index 00000000..4f870268 --- /dev/null +++ b/pipenv/vendor/psutil/arch/bsd/openbsd.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +typedef struct kinfo_proc kinfo_proc; + +int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc); +struct kinfo_file * kinfo_getfile(long pid, int* cnt); +int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); +char **_psutil_get_argv(long pid); +PyObject * psutil_get_cmdline(long pid); + +// +PyObject *psutil_proc_threads(PyObject *self, PyObject *args); +PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); +PyObject *psutil_swap_mem(PyObject *self, PyObject *args); +PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); +PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); +PyObject *psutil_proc_connections(PyObject *self, PyObject *args); +PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); +PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); +PyObject* psutil_cpu_stats(PyObject* self, PyObject* args); diff --git a/pipenv/vendor/psutil/arch/osx/process_info.c b/pipenv/vendor/psutil/arch/osx/process_info.c new file mode 100644 index 00000000..4b0b458b --- /dev/null +++ b/pipenv/vendor/psutil/arch/osx/process_info.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Helper functions related to fetching process information. + * Used by _psutil_osx module methods. + */ + + +#include +#include +#include +#include // for INT_MAX +#include +#include +#include +#include +#include +#include + +#include "process_info.h" +#include "../../_psutil_common.h" + + +/* + * Returns a list of all BSD processes on the system. This routine + * allocates the list and puts it in *procList and a count of the + * number of entries in *procCount. You are responsible for freeing + * this list (use "free" from System framework). + * On success, the function returns 0. + * On error, the function returns a BSD errno value. + */ +int +psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { + int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; + size_t size, size2; + void *ptr; + int err; + int lim = 8; // some limit + + assert( procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + *procCount = 0; + + /* + * We start by calling sysctl with ptr == NULL and size == 0. + * That will succeed, and set size to the appropriate length. + * We then allocate a buffer of at least that size and call + * sysctl with that buffer. If that succeeds, we're done. + * If that call fails with ENOMEM, we throw the buffer away + * and try again. + * Note that the loop calls sysctl with NULL again. This is + * is necessary because the ENOMEM failure case sets size to + * the amount of data returned, not the amount of data that + * could have been returned. + */ + while (lim-- > 0) { + size = 0; + if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) + return errno; + size2 = size + (size >> 3); // add some + if (size2 > size) { + ptr = malloc(size2); + if (ptr == NULL) + ptr = malloc(size); + else + size = size2; + } + else { + ptr = malloc(size); + } + if (ptr == NULL) + return ENOMEM; + + if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) { + err = errno; + free(ptr); + if (err != ENOMEM) + return err; + } + else { + *procList = (kinfo_proc *)ptr; + *procCount = size / sizeof(kinfo_proc); + return 0; + } + } + return ENOMEM; +} + + +// Read the maximum argument size for processes +int +psutil_get_argmax() { + int argmax; + int mib[] = { CTL_KERN, KERN_ARGMAX }; + size_t size = sizeof(argmax); + + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) + return argmax; + return 0; +} + + +// return process args as a python list +PyObject * +psutil_get_cmdline(long pid) { + int mib[3]; + int nargs; + size_t len; + char *procargs = NULL; + char *arg_ptr; + char *arg_end; + char *curr_arg; + size_t argmax; + + PyObject *py_arg = NULL; + PyObject *py_retlist = NULL; + + // special case for PID 0 (kernel_task) where cmdline cannot be fetched + if (pid == 0) + return Py_BuildValue("[]"); + + // read argmax and allocate memory for argument space. + argmax = psutil_get_argmax(); + if (! argmax) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + procargs = (char *)malloc(argmax); + if (NULL == procargs) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // read argument space + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = (pid_t)pid; + if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) { + if (EINVAL == errno) { + // EINVAL == access denied OR nonexistent PID + if (psutil_pid_exists(pid)) + AccessDenied(); + else + NoSuchProcess(); + } + goto error; + } + + arg_end = &procargs[argmax]; + // copy the number of arguments to nargs + memcpy(&nargs, procargs, sizeof(nargs)); + + arg_ptr = procargs + sizeof(nargs); + len = strlen(arg_ptr); + arg_ptr += len + 1; + + if (arg_ptr == arg_end) { + free(procargs); + return Py_BuildValue("[]"); + } + + // skip ahead to the first argument + for (; arg_ptr < arg_end; arg_ptr++) { + if (*arg_ptr != '\0') + break; + } + + // iterate through arguments + curr_arg = arg_ptr; + py_retlist = Py_BuildValue("[]"); + if (!py_retlist) + goto error; + while (arg_ptr < arg_end && nargs > 0) { + if (*arg_ptr++ == '\0') { +#if PY_MAJOR_VERSION >= 3 + py_arg = PyUnicode_DecodeFSDefault(curr_arg); +#else + py_arg = Py_BuildValue("s", curr_arg); +#endif + if (!py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); + // iterate to next arg and decrement # of args + curr_arg = arg_ptr; + nargs--; + } + } + + free(procargs); + return py_retlist; + +error: + Py_XDECREF(py_arg); + Py_XDECREF(py_retlist); + if (procargs != NULL) + free(procargs); + return NULL; +} + + +// return process environment as a python string +PyObject * +psutil_get_environ(long pid) { + int mib[3]; + int nargs; + char *procargs = NULL; + char *procenv = NULL; + char *arg_ptr; + char *arg_end; + char *env_start; + size_t argmax; + PyObject *py_ret = NULL; + + // special case for PID 0 (kernel_task) where cmdline cannot be fetched + if (pid == 0) + goto empty; + + // read argmax and allocate memory for argument space. + argmax = psutil_get_argmax(); + if (! argmax) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + procargs = (char *)malloc(argmax); + if (NULL == procargs) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // read argument space + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = (pid_t)pid; + if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) { + if (EINVAL == errno) { + // EINVAL == access denied OR nonexistent PID + if (psutil_pid_exists(pid)) + AccessDenied(); + else + NoSuchProcess(); + } + goto error; + } + + arg_end = &procargs[argmax]; + // copy the number of arguments to nargs + memcpy(&nargs, procargs, sizeof(nargs)); + + // skip executable path + arg_ptr = procargs + sizeof(nargs); + arg_ptr = memchr(arg_ptr, '\0', arg_end - arg_ptr); + + if (arg_ptr == NULL || arg_ptr == arg_end) + goto empty; + + // skip ahead to the first argument + for (; arg_ptr < arg_end; arg_ptr++) { + if (*arg_ptr != '\0') + break; + } + + // iterate through arguments + while (arg_ptr < arg_end && nargs > 0) { + if (*arg_ptr++ == '\0') + nargs--; + } + + // build an environment variable block + env_start = arg_ptr; + + procenv = calloc(1, arg_end - arg_ptr); + if (procenv == NULL) { + PyErr_NoMemory(); + goto error; + } + + while (*arg_ptr != '\0' && arg_ptr < arg_end) { + char *s = memchr(arg_ptr + 1, '\0', arg_end - arg_ptr); + + if (s == NULL) + break; + + memcpy(procenv + (arg_ptr - env_start), arg_ptr, s - arg_ptr); + + arg_ptr = s + 1; + } + +#if PY_MAJOR_VERSION >= 3 + py_ret = PyUnicode_DecodeFSDefaultAndSize( + procenv, arg_ptr - env_start + 1); +#else + py_ret = PyString_FromStringAndSize(procenv, arg_ptr - env_start + 1); +#endif + + if (!py_ret) { + // XXX: don't want to free() this as per: + // https://github.com/giampaolo/psutil/issues/926 + // It sucks but not sure what else to do. + procargs = NULL; + goto error; + } + + free(procargs); + free(procenv); + + return py_ret; + +empty: + if (procargs != NULL) + free(procargs); + return Py_BuildValue("s", ""); + +error: + Py_XDECREF(py_ret); + if (procargs != NULL) + free(procargs); + if (procenv != NULL) + free(procargs); + return NULL; +} + + +int +psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp) { + int mib[4]; + size_t len; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = (pid_t)pid; + + // fetch the info with sysctl() + len = sizeof(struct kinfo_proc); + + // now read the data from sysctl + if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) { + // raise an exception and throw errno as the error + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + // sysctl succeeds but len is zero, happens when process has gone away + if (len == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +/* + * A wrapper around proc_pidinfo(). + * Returns 0 on failure (and Python exception gets already set). + */ +int +psutil_proc_pidinfo(long pid, int flavor, uint64_t arg, void *pti, int size) { + errno = 0; + int ret = proc_pidinfo((int)pid, flavor, arg, pti, size); + if ((ret <= 0) || ((unsigned long)ret < sizeof(pti))) { + psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed"); + return 0; + } + return ret; +} diff --git a/pipenv/vendor/psutil/arch/osx/process_info.h b/pipenv/vendor/psutil/arch/osx/process_info.h new file mode 100644 index 00000000..bd2eef86 --- /dev/null +++ b/pipenv/vendor/psutil/arch/osx/process_info.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +typedef struct kinfo_proc kinfo_proc; + +int psutil_get_argmax(void); +int psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp); +int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); +int psutil_proc_pidinfo( + long pid, int flavor, uint64_t arg, void *pti, int size); +PyObject* psutil_get_cmdline(long pid); +PyObject* psutil_get_environ(long pid); diff --git a/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.c b/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.c new file mode 100644 index 00000000..59529e6a --- /dev/null +++ b/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.c @@ -0,0 +1,124 @@ +/* Refrences: + * https://lists.samba.org/archive/samba-technical/2009-February/063079.html + * http://stackoverflow.com/questions/4139405/#4139811 + * https://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/getifaddrs.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifaddrs.h" + +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define SIZE(p) MAX((p).ss_len,sizeof(p)) + + +static struct sockaddr * +sa_dup (struct sockaddr *sa1) +{ + struct sockaddr *sa2; + size_t sz = sizeof(sa1); + sa2 = (struct sockaddr *) calloc(1,sz); + memcpy(sa2,sa1,sz); + return(sa2); +} + + +void freeifaddrs (struct ifaddrs *ifp) +{ + if (NULL == ifp) return; + free(ifp->ifa_name); + free(ifp->ifa_addr); + free(ifp->ifa_netmask); + free(ifp->ifa_dstaddr); + freeifaddrs(ifp->ifa_next); + free(ifp); +} + + +int getifaddrs (struct ifaddrs **ifap) +{ + int sd = -1; + char *ccp, *ecp; + struct lifconf ifc; + struct lifreq *ifr; + struct lifnum lifn; + struct ifaddrs *cifa = NULL; /* current */ + struct ifaddrs *pifa = NULL; /* previous */ + const size_t IFREQSZ = sizeof(struct lifreq); + + sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) + goto error; + + ifc.lifc_buf = NULL; + *ifap = NULL; + /* find how much memory to allocate for the SIOCGLIFCONF call */ + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = 0; + if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0) + goto error; + + /* Sun and Apple code likes to pad the interface count here in case interfaces + * are coming up between calls */ + lifn.lifn_count += 4; + + ifc.lifc_family = AF_UNSPEC; + ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq); + ifc.lifc_buf = calloc(1, ifc.lifc_len); + if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0) + goto error; + + ccp = (char *)ifc.lifc_req; + ecp = ccp + ifc.lifc_len; + + while (ccp < ecp) { + + ifr = (struct lifreq *) ccp; + cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs)); + cifa->ifa_next = NULL; + cifa->ifa_name = strdup(ifr->lifr_name); + + if (pifa == NULL) *ifap = cifa; /* first one */ + else pifa->ifa_next = cifa; + + if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0) + goto error; + cifa->ifa_addr = sa_dup((struct sockaddr*)&ifr->lifr_addr); + + if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0) + goto error; + cifa->ifa_netmask = sa_dup((struct sockaddr*)&ifr->lifr_addr); + + cifa->ifa_flags = 0; + cifa->ifa_dstaddr = NULL; + + if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */ + cifa->ifa_flags = ifr->lifr_flags; + + if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) { + if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ)) + cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr); + } + else cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr); + + pifa = cifa; + ccp += IFREQSZ; + } + free(ifc.lifc_buf); + close(sd); + return 0; +error: + if (ifc.lifc_buf != NULL) + free(ifc.lifc_buf); + if (sd != -1) + close(sd); + return (-1); +} diff --git a/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.h b/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.h new file mode 100644 index 00000000..e1d88596 --- /dev/null +++ b/pipenv/vendor/psutil/arch/solaris/v10/ifaddrs.h @@ -0,0 +1,26 @@ +/* Reference: https://lists.samba.org/archive/samba-technical/2009-February/063079.html */ + + +#ifndef __IFADDRS_H___ +#define __IFADDRS_H___ + +#include +#include + +#undef ifa_dstaddr +#undef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; +}; + +extern int getifaddrs(struct ifaddrs **); +extern void freeifaddrs(struct ifaddrs *); + +#endif \ No newline at end of file diff --git a/pipenv/vendor/psutil/arch/windows/glpi.h b/pipenv/vendor/psutil/arch/windows/glpi.h new file mode 100644 index 00000000..6f984837 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/glpi.h @@ -0,0 +1,41 @@ +// mingw headers are missing this + +typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationAll=0xffff +} LOGICAL_PROCESSOR_RELATIONSHIP; + +typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified,CacheInstruction,CacheData,CacheTrace +} PROCESSOR_CACHE_TYPE; + +typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; +} CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; + +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; + +WINBASEAPI WINBOOL WINAPI +GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, + PDWORD ReturnedLength); \ No newline at end of file diff --git a/pipenv/vendor/psutil/arch/windows/inet_ntop.c b/pipenv/vendor/psutil/arch/windows/inet_ntop.c new file mode 100644 index 00000000..50dfb6ae --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/inet_ntop.c @@ -0,0 +1,38 @@ +#include "inet_ntop.h" + +// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/ +PCSTR +WSAAPI +inet_ntop(__in INT Family, + __in PVOID pAddr, + __out_ecount(StringBufSize) PSTR pStringBuf, + __in size_t StringBufSize) { + DWORD dwAddressLength = 0; + struct sockaddr_storage srcaddr; + struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr; + struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr; + + memset(&srcaddr, 0, sizeof(struct sockaddr_storage)); + srcaddr.ss_family = Family; + + if (Family == AF_INET) + { + dwAddressLength = sizeof(struct sockaddr_in); + memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr)); + } else if (Family == AF_INET6) + { + dwAddressLength = sizeof(struct sockaddr_in6); + memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr)); + } else { + return NULL; + } + + if (WSAAddressToString((LPSOCKADDR) &srcaddr, + dwAddressLength, + 0, + pStringBuf, + (LPDWORD) &StringBufSize) != 0) { + return NULL; + } + return pStringBuf; +} diff --git a/pipenv/vendor/psutil/arch/windows/inet_ntop.h b/pipenv/vendor/psutil/arch/windows/inet_ntop.h new file mode 100644 index 00000000..0d97e28c --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/inet_ntop.h @@ -0,0 +1,10 @@ +#include + +PCSTR +WSAAPI +inet_ntop( + __in INT Family, + __in PVOID pAddr, + __out_ecount(StringBufSize) PSTR pStringBuf, + __in size_t StringBufSize +); \ No newline at end of file diff --git a/pipenv/vendor/psutil/arch/windows/ntextapi.h b/pipenv/vendor/psutil/arch/windows/ntextapi.h new file mode 100644 index 00000000..1bbbf2ac --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/ntextapi.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#if !defined(__NTEXTAPI_H__) +#define __NTEXTAPI_H__ +#include + + +typedef struct { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + + +typedef struct { + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG PeakCommitment; + ULONG PageFaultCount; + ULONG CopyOnWriteCount; + ULONG TransitionCount; + ULONG CacheTransitionCount; + ULONG DemandZeroCount; + ULONG PageReadCount; + ULONG PageReadIoCount; + ULONG CacheReadCount; + ULONG CacheIoCount; + ULONG DirtyPagesWriteCount; + ULONG DirtyWriteIoCount; + ULONG MappedPagesWriteCount; + ULONG MappedWriteIoCount; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG ResidentSystemCodePage; + ULONG TotalSystemDriverPages; + ULONG TotalSystemCodePages; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG AvailablePagedPoolPages; + ULONG ResidentSystemCachePage; + ULONG ResidentPagedPoolPage; + ULONG ResidentSystemDriverPage; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadResourceMiss; + ULONG CcFastReadNotPossible; + ULONG CcFastMdlReadNoWait; + ULONG CcFastMdlReadWait; + ULONG CcFastMdlReadResourceMiss; + ULONG CcFastMdlReadNotPossible; + ULONG CcMapDataNoWait; + ULONG CcMapDataWait; + ULONG CcMapDataNoWaitMiss; + ULONG CcMapDataWaitMiss; + ULONG CcPinMappedDataCount; + ULONG CcPinReadNoWait; + ULONG CcPinReadWait; + ULONG CcPinReadNoWaitMiss; + ULONG CcPinReadWaitMiss; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG CcCopyReadWaitMiss; + ULONG CcMdlReadNoWait; + ULONG CcMdlReadWait; + ULONG CcMdlReadNoWaitMiss; + ULONG CcMdlReadWaitMiss; + ULONG CcReadAheadIos; + ULONG CcLazyWriteIos; + ULONG CcLazyWritePages; + ULONG CcDataFlushes; + ULONG CcDataPages; + ULONG ContextSwitches; + ULONG FirstLevelTbFills; + ULONG SecondLevelTbFills; + ULONG SystemCalls; + +} _SYSTEM_PERFORMANCE_INFORMATION; + + +typedef struct { + ULONG ContextSwitches; + ULONG DpcCount; + ULONG DpcRate; + ULONG TimeIncrement; + ULONG DpcBypassCount; + ULONG ApcBypassCount; +} _SYSTEM_INTERRUPT_INFORMATION; + + +typedef enum _KTHREAD_STATE { + Initialized, + Ready, + Running, + Standby, + Terminated, + Waiting, + Transition, + DeferredReady, + GateWait, + MaximumThreadState +} KTHREAD_STATE, *PKTHREAD_STATE; + + +typedef enum _KWAIT_REASON { + Executive = 0, + FreePage = 1, + PageIn = 2, + PoolAllocation = 3, + DelayExecution = 4, + Suspended = 5, + UserRequest = 6, + WrExecutive = 7, + WrFreePage = 8, + WrPageIn = 9, + WrPoolAllocation = 10, + WrDelayExecution = 11, + WrSuspended = 12, + WrUserRequest = 13, + WrEventPair = 14, + WrQueue = 15, + WrLpcReceive = 16, + WrLpcReply = 17, + WrVirtualMemory = 18, + WrPageOut = 19, + WrRendezvous = 20, + Spare2 = 21, + Spare3 = 22, + Spare4 = 23, + Spare5 = 24, + WrCalloutStack = 25, + WrKernel = 26, + WrResource = 27, + WrPushLock = 28, + WrMutex = 29, + WrQuantumEnd = 30, + WrDispatchInt = 31, + WrPreempted = 32, + WrYieldExecution = 33, + WrFastMutex = 34, + WrGuardedMutex = 35, + WrRundown = 36, + MaximumWaitReason = 37 +} KWAIT_REASON, *PKWAIT_REASON; + + +typedef struct _CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + + +typedef struct _SYSTEM_THREAD_INFORMATION { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + LONG Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + KWAIT_REASON WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + + +typedef struct _TEB *PTEB; + + +// private +typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION { + SYSTEM_THREAD_INFORMATION ThreadInfo; + PVOID StackBase; + PVOID StackLimit; + PVOID Win32StartAddress; + PTEB TebBase; + ULONG_PTR Reserved2; + ULONG_PTR Reserved3; + ULONG_PTR Reserved4; +} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; + + +typedef struct _SYSTEM_PROCESS_INFORMATION2 { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + LONG BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG_PTR PageDirectoryBase; + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; + SYSTEM_THREAD_INFORMATION Threads[1]; +} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2; + +#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2 +#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2 + + +// ================================================ +// psutil.users() support +// ================================================ + +typedef struct _WINSTATION_INFO { + BYTE Reserved1[72]; + ULONG SessionId; + BYTE Reserved2[4]; + FILETIME ConnectTime; + FILETIME DisconnectTime; + FILETIME LastInputTime; + FILETIME LoginTime; + BYTE Reserved3[1096]; + FILETIME CurrentTime; +} WINSTATION_INFO, *PWINSTATION_INFO; + + +typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW) + (HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG); + + +/* + * NtQueryInformationProcess code taken from + * http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/ + * typedefs needed to compile against ntdll functions not exposted in the API + */ +typedef LONG NTSTATUS; + + +typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)( + HANDLE ProcessHandle, + DWORD ProcessInformationClass, + PVOID ProcessInformation, + DWORD ProcessInformationLength, + PDWORD ReturnLength +); + + +typedef NTSTATUS (NTAPI *_NtSetInformationProcess)( + HANDLE ProcessHandle, + DWORD ProcessInformationClass, + PVOID ProcessInformation, + DWORD ProcessInformationLength +); + + +typedef enum _PROCESSINFOCLASS2 { + _ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + _ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + _ProcessWow64Information, + /* added after XP+ */ + _ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + _ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessResourceManagement, + ProcessCookie, + ProcessImageInformation, + MaxProcessInfoClass +} PROCESSINFOCLASS2; + + +#define PROCESSINFOCLASS PROCESSINFOCLASS2 +#define ProcessBasicInformation _ProcessBasicInformation +#define ProcessWow64Information _ProcessWow64Information +#define ProcessDebugPort _ProcessDebugPort +#define ProcessImageFileName _ProcessImageFileName +#define ProcessBreakOnTermination _ProcessBreakOnTermination + +#endif // __NTEXTAPI_H__ diff --git a/pipenv/vendor/psutil/arch/windows/process_handles.c b/pipenv/vendor/psutil/arch/windows/process_handles.c new file mode 100644 index 00000000..670d74f0 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/process_handles.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + */ +#include "process_handles.h" + +static _NtQuerySystemInformation __NtQuerySystemInformation = NULL; +static _NtQueryObject __NtQueryObject = NULL; + +CRITICAL_SECTION g_cs; +BOOL g_initialized = FALSE; +NTSTATUS g_status; +HANDLE g_hFile = NULL; +HANDLE g_hEvtStart = NULL; +HANDLE g_hEvtFinish = NULL; +HANDLE g_hThread = NULL; +PUNICODE_STRING g_pNameBuffer = NULL; +ULONG g_dwSize = 0; +ULONG g_dwLength = 0; + + +PVOID +GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) { + return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); +} + + +PyObject * +psutil_get_open_files(long dwPid, HANDLE hProcess) { + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // Threaded version only works for Vista+ + if (osvi.dwMajorVersion >= 6) + return psutil_get_open_files_ntqueryobject(dwPid, hProcess); + else + return psutil_get_open_files_getmappedfilename(dwPid, hProcess); +} + + +VOID +psutil_get_open_files_init(BOOL threaded) { + if (g_initialized == TRUE) + return; + + // Resolve the Windows API calls + __NtQuerySystemInformation = + GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); + __NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); + + // Create events for signalling work between threads + if (threaded == TRUE) { + g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL); + g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL); + InitializeCriticalSection(&g_cs); + } + + g_initialized = TRUE; +} + + +PyObject * +psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) { + NTSTATUS status; + PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; + DWORD dwInfoSize = 0x10000; + DWORD dwRet = 0; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; + DWORD i = 0; + BOOLEAN error = FALSE; + DWORD dwWait = 0; + PyObject* py_retlist = NULL; + PyObject* py_path = NULL; + + if (g_initialized == FALSE) + psutil_get_open_files_init(TRUE); + + // Due to the use of global variables, ensure only 1 call + // to psutil_get_open_files() is running + EnterCriticalSection(&g_cs); + + if (__NtQuerySystemInformation == NULL || + __NtQueryObject == NULL || + g_hEvtStart == NULL || + g_hEvtFinish == NULL) + + { + PyErr_SetFromWindowsErr(0); + error = TRUE; + goto cleanup; + } + + // Py_BuildValue raises an exception if NULL is returned + py_retlist = PyList_New(0); + if (py_retlist == NULL) { + error = TRUE; + goto cleanup; + } + + do { + if (pHandleInfo != NULL) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + } + + // NtQuerySystemInformation won't give us the correct buffer size, + // so we guess by doubling the buffer size. + dwInfoSize *= 2; + pHandleInfo = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwInfoSize); + + if (pHandleInfo == NULL) { + PyErr_NoMemory(); + error = TRUE; + goto cleanup; + } + } while ((status = __NtQuerySystemInformation( + SystemExtendedHandleInformation, + pHandleInfo, + dwInfoSize, + &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); + + // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH + if (!NT_SUCCESS(status)) { + PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); + error = TRUE; + goto cleanup; + } + + for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { + hHandle = &pHandleInfo->Handles[i]; + + // Check if this hHandle belongs to the PID the user specified. + if (hHandle->UniqueProcessId != (HANDLE)dwPid) + goto loop_cleanup; + + if (!DuplicateHandle(hProcess, + hHandle->HandleValue, + GetCurrentProcess(), + &g_hFile, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + /* + printf("[%d] DuplicateHandle (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + // Guess buffer size is MAX_PATH + 1 + g_dwLength = (MAX_PATH+1) * sizeof(WCHAR); + + do { + // Release any previously allocated buffer + if (g_pNameBuffer != NULL) { + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + } + + // NtQueryObject puts the required buffer size in g_dwLength + // WinXP edge case puts g_dwLength == 0, just skip this handle + if (g_dwLength == 0) + goto loop_cleanup; + + g_dwSize = g_dwLength; + if (g_dwSize > 0) { + g_pNameBuffer = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + g_dwSize); + + if (g_pNameBuffer == NULL) + goto loop_cleanup; + } + + dwWait = psutil_NtQueryObject(); + + // If the call does not return, skip this handle + if (dwWait != WAIT_OBJECT_0) + goto loop_cleanup; + + } while (g_status == STATUS_INFO_LENGTH_MISMATCH); + + // NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH + if (!NT_SUCCESS(g_status)) + goto loop_cleanup; + + // Convert to PyUnicode and append it to the return list + if (g_pNameBuffer->Length > 0) { + /* + printf("[%d] Filename (%#x) %#d bytes: %S\n", + dwPid, + hHandle->HandleValue, + g_pNameBuffer->Length, + g_pNameBuffer->Buffer); + */ + + py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer, + g_pNameBuffer->Length/2); + if (py_path == NULL) { + /* + printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + + if (PyList_Append(py_retlist, py_path)) { + /* + printf("[%d] PyList_Append (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + } + +loop_cleanup: + Py_XDECREF(py_path); + py_path = NULL; + + if (g_pNameBuffer != NULL) + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + g_dwLength = 0; + + if (g_hFile != NULL) + CloseHandle(g_hFile); + g_hFile = NULL; + } + +cleanup: + if (g_pNameBuffer != NULL) + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + g_dwLength = 0; + + if (g_hFile != NULL) + CloseHandle(g_hFile); + g_hFile = NULL; + + if (pHandleInfo != NULL) + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + + if (error) { + Py_XDECREF(py_retlist); + py_retlist = NULL; + } + + LeaveCriticalSection(&g_cs); + + return py_retlist; +} + + +DWORD +psutil_NtQueryObject() { + DWORD dwWait = 0; + + if (g_hThread == NULL) + g_hThread = CreateThread( + NULL, + 0, + psutil_NtQueryObjectThread, + NULL, + 0, + NULL); + if (g_hThread == NULL) + return GetLastError(); + + // Signal the worker thread to start + SetEvent(g_hEvtStart); + + // Wait for the worker thread to finish + dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT); + + // If the thread hangs, kill it and cleanup + if (dwWait == WAIT_TIMEOUT) { + SuspendThread(g_hThread); + TerminateThread(g_hThread, 1); + WaitForSingleObject(g_hThread, INFINITE); + CloseHandle(g_hThread); + + g_hThread = NULL; + } + + return dwWait; +} + + +DWORD WINAPI +psutil_NtQueryObjectThread(LPVOID lpvParam) { + // Loop infinitely waiting for work + while (TRUE) { + WaitForSingleObject(g_hEvtStart, INFINITE); + + g_status = __NtQueryObject(g_hFile, + ObjectNameInformation, + g_pNameBuffer, + g_dwSize, + &g_dwLength); + SetEvent(g_hEvtFinish); + } +} + + +PyObject * +psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) { + NTSTATUS status; + PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; + DWORD dwInfoSize = 0x10000; + DWORD dwRet = 0; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; + HANDLE hFile = NULL; + HANDLE hMap = NULL; + DWORD i = 0; + BOOLEAN error = FALSE; + PyObject* py_retlist = NULL; + PyObject* py_path = NULL; + ULONG dwSize = 0; + LPVOID pMem = NULL; + TCHAR pszFilename[MAX_PATH+1]; + + if (g_initialized == FALSE) + psutil_get_open_files_init(FALSE); + + if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) { + PyErr_SetFromWindowsErr(0); + error = TRUE; + goto cleanup; + } + + // Py_BuildValue raises an exception if NULL is returned + py_retlist = PyList_New(0); + if (py_retlist == NULL) { + error = TRUE; + goto cleanup; + } + + do { + if (pHandleInfo != NULL) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + } + + // NtQuerySystemInformation won't give us the correct buffer size, + // so we guess by doubling the buffer size. + dwInfoSize *= 2; + pHandleInfo = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwInfoSize); + + if (pHandleInfo == NULL) { + PyErr_NoMemory(); + error = TRUE; + goto cleanup; + } + } while ((status = __NtQuerySystemInformation( + SystemExtendedHandleInformation, + pHandleInfo, + dwInfoSize, + &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); + + // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH + if (!NT_SUCCESS(status)) { + PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); + error = TRUE; + goto cleanup; + } + + for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { + hHandle = &pHandleInfo->Handles[i]; + + // Check if this hHandle belongs to the PID the user specified. + if (hHandle->UniqueProcessId != (HANDLE)dwPid) + goto loop_cleanup; + + if (!DuplicateHandle(hProcess, + hHandle->HandleValue, + GetCurrentProcess(), + &hFile, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + { + /* + printf("[%d] DuplicateHandle (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMap == NULL) { + /* + printf("[%d] CreateFileMapping (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1); + + if (pMem == NULL) { + /* + printf("[%d] MapViewOfFile (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + dwSize = GetMappedFileName( + GetCurrentProcess(), pMem, pszFilename, MAX_PATH); + if (dwSize == 0) { + /* + printf("[%d] GetMappedFileName (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + pszFilename[dwSize] = '\0'; + /* + printf("[%d] Filename (%#x) %#d bytes: %S\n", + dwPid, + hHandle->HandleValue, + dwSize, + pszFilename); + */ + + py_path = PyUnicode_FromWideChar(pszFilename, dwSize); + if (py_path == NULL) { + /* + printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + + if (PyList_Append(py_retlist, py_path)) { + /* + printf("[%d] PyList_Append (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + +loop_cleanup: + Py_XDECREF(py_path); + py_path = NULL; + + if (pMem != NULL) + UnmapViewOfFile(pMem); + pMem = NULL; + + if (hMap != NULL) + CloseHandle(hMap); + hMap = NULL; + + if (hFile != NULL) + CloseHandle(hFile); + hFile = NULL; + + dwSize = 0; + } + +cleanup: + if (pMem != NULL) + UnmapViewOfFile(pMem); + pMem = NULL; + + if (hMap != NULL) + CloseHandle(hMap); + hMap = NULL; + + if (hFile != NULL) + CloseHandle(hFile); + hFile = NULL; + + if (pHandleInfo != NULL) + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + + if (error) { + Py_XDECREF(py_retlist); + py_retlist = NULL; + } + + return py_retlist; +} diff --git a/pipenv/vendor/psutil/arch/windows/process_handles.h b/pipenv/vendor/psutil/arch/windows/process_handles.h new file mode 100644 index 00000000..4a022c1c --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/process_handles.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __PROCESS_HANDLES_H__ +#define __PROCESS_HANDLES_H__ + +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include +#include +#include +#include + + +#ifndef NT_SUCCESS +#define NT_SUCCESS(x) ((x) >= 0) +#endif + +#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 +#define ObjectBasicInformation 0 +#define ObjectNameInformation 1 +#define ObjectTypeInformation 2 +#define HANDLE_TYPE_FILE 28 +#define NTQO_TIMEOUT 100 + +typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( + ULONG SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength +); + +typedef NTSTATUS (NTAPI *_NtQueryObject)( + HANDLE ObjectHandle, + ULONG ObjectInformationClass, + PVOID ObjectInformation, + ULONG ObjectInformationLength, + PULONG ReturnLength +); + +// Undocumented FILE_INFORMATION_CLASS: FileNameInformation +static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { + PVOID Object; + HANDLE UniqueProcessId; + HANDLE HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX { + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; + +typedef enum _POOL_TYPE { + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS +} POOL_TYPE, *PPOOL_TYPE; + +typedef struct _OBJECT_TYPE_INFORMATION { + UNICODE_STRING Name; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccess; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + USHORT MaintainTypeList; + POOL_TYPE PoolType; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName); +VOID psutil_get_open_files_init(BOOL threaded); +PyObject* psutil_get_open_files(long pid, HANDLE processHandle); +PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess); +PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess); +DWORD psutil_NtQueryObject(void); +DWORD WINAPI psutil_NtQueryObjectThread(LPVOID lpvParam); + +#endif // __PROCESS_HANDLES_H__ diff --git a/pipenv/vendor/psutil/arch/windows/process_info.c b/pipenv/vendor/psutil/arch/windows/process_info.c new file mode 100644 index 00000000..e29f2161 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/process_info.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Helper functions related to fetching process information. Used by + * _psutil_windows module methods. + */ + +#include +#include +#include +#include + +#include "security.h" +#include "process_info.h" +#include "ntextapi.h" +#include "../../_psutil_common.h" + + +/* + * A wrapper around OpenProcess setting NSP exception if process + * no longer exists. + * "pid" is the process pid, "dwDesiredAccess" is the first argument + * exptected by OpenProcess. + * Return a process handle or NULL. + */ +HANDLE +psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { + HANDLE hProcess; + DWORD processExitCode = 0; + + if (pid == 0) { + // otherwise we'd get NoSuchProcess + return AccessDenied(); + } + + hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); + if (hProcess == NULL) { + if (GetLastError() == ERROR_INVALID_PARAMETER) + NoSuchProcess(); + else + PyErr_SetFromWindowsErr(0); + return NULL; + } + + // make sure the process is running + GetExitCodeProcess(hProcess, &processExitCode); + if (processExitCode == 0) { + NoSuchProcess(); + CloseHandle(hProcess); + return NULL; + } + return hProcess; +} + + +/* + * Same as psutil_handle_from_pid_waccess but implicitly uses + * PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as dwDesiredAccess + * parameter for OpenProcess. + */ +HANDLE +psutil_handle_from_pid(DWORD pid) { + DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + return psutil_handle_from_pid_waccess(pid, dwDesiredAccess); +} + + +/* + * Given a Python int referencing a process handle close the process handle. + */ +PyObject * +psutil_win32_CloseHandle(PyObject *self, PyObject *args) { + unsigned long handle; + + if (! PyArg_ParseTuple(args, "k", &handle)) + return NULL; + // TODO: may want to check return value; + CloseHandle((HANDLE)handle); + Py_RETURN_NONE; +} + + +DWORD * +psutil_get_pids(DWORD *numberOfReturnedPIDs) { + // Win32 SDK says the only way to know if our process array + // wasn't large enough is to check the returned size and make + // sure that it doesn't match the size of the array. + // If it does we allocate a larger array and try again + + // Stores the actual array + DWORD *procArray = NULL; + DWORD procArrayByteSz; + int procArraySz = 0; + + // Stores the byte size of the returned array from enumprocesses + DWORD enumReturnSz = 0; + + do { + procArraySz += 1024; + free(procArray); + procArrayByteSz = procArraySz * sizeof(DWORD); + procArray = malloc(procArrayByteSz); + if (procArray == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) { + free(procArray); + PyErr_SetFromWindowsErr(0); + return NULL; + } + } while (enumReturnSz == procArraySz * sizeof(DWORD)); + + // The number of elements is the returned size / size of each element + *numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD); + + return procArray; +} + + +int +psutil_pid_is_running(DWORD pid) { + HANDLE hProcess; + DWORD exitCode; + + // Special case for PID 0 System Idle Process + if (pid == 0) + return 1; + if (pid < 0) + return 0; + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, pid); + if (NULL == hProcess) { + // invalid parameter is no such process + if (GetLastError() == ERROR_INVALID_PARAMETER) { + CloseHandle(hProcess); + return 0; + } + + // access denied obviously means there's a process to deny access to... + if (GetLastError() == ERROR_ACCESS_DENIED) { + CloseHandle(hProcess); + return 1; + } + + CloseHandle(hProcess); + PyErr_SetFromWindowsErr(0); + return -1; + } + + if (GetExitCodeProcess(hProcess, &exitCode)) { + CloseHandle(hProcess); + return (exitCode == STILL_ACTIVE); + } + + // access denied means there's a process there so we'll assume + // it's running + if (GetLastError() == ERROR_ACCESS_DENIED) { + CloseHandle(hProcess); + return 1; + } + + PyErr_SetFromWindowsErr(0); + CloseHandle(hProcess); + return -1; +} + + +int +psutil_pid_in_proclist(DWORD pid) { + DWORD *proclist = NULL; + DWORD numberOfReturnedPIDs; + DWORD i; + + proclist = psutil_get_pids(&numberOfReturnedPIDs); + if (proclist == NULL) + return -1; + for (i = 0; i < numberOfReturnedPIDs; i++) { + if (pid == proclist[i]) { + free(proclist); + return 1; + } + } + + free(proclist); + return 0; +} + + +// Check exit code from a process handle. Return FALSE on an error also +// XXX - not used anymore +int +handlep_is_running(HANDLE hProcess) { + DWORD dwCode; + + if (NULL == hProcess) + return 0; + if (GetExitCodeProcess(hProcess, &dwCode)) { + if (dwCode == STILL_ACTIVE) + return 1; + } + return 0; +} + +// Helper structures to access the memory correctly. Some of these might also +// be defined in the winternl.h header file but unfortunately not in a usable +// way. + +// see http://msdn2.microsoft.com/en-us/library/aa489609.aspx +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx +typedef struct { + BYTE Reserved1[16]; + PVOID Reserved2[5]; + UNICODE_STRING CurrentDirectoryPath; + PVOID CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + LPCWSTR env; +} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_; + +// https://msdn.microsoft.com/en-us/library/aa813706(v=vs.85).aspx +#ifdef _WIN64 +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[21]; + PVOID LoaderData; + PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters; + /* More fields ... */ +} PEB_; +#else +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PVOID Ldr; + PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters; + /* More fields ... */ +} PEB_; +#endif + +#ifdef _WIN64 +/* When we are a 64 bit process accessing a 32 bit (WoW64) process we need to + use the 32 bit structure layout. */ +typedef struct { + USHORT Length; + USHORT MaxLength; + DWORD Buffer; +} UNICODE_STRING32; + +typedef struct { + BYTE Reserved1[16]; + DWORD Reserved2[5]; + UNICODE_STRING32 CurrentDirectoryPath; + DWORD CurrentDirectoryHandle; + UNICODE_STRING32 DllPath; + UNICODE_STRING32 ImagePathName; + UNICODE_STRING32 CommandLine; + DWORD env; +} RTL_USER_PROCESS_PARAMETERS32; + +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + DWORD Reserved3[2]; + DWORD Ldr; + DWORD ProcessParameters; + /* More fields ... */ +} PEB32; +#else +/* When we are a 32 bit (WoW64) process accessing a 64 bit process we need to + use the 64 bit structure layout and a special function to read its memory. + */ +typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)( + IN HANDLE ProcessHandle, + IN PVOID64 BaseAddress, + OUT PVOID Buffer, + IN ULONG64 Size, + OUT PULONG64 NumberOfBytesRead); + +typedef enum { + MemoryInformationBasic +} MEMORY_INFORMATION_CLASS; + +typedef NTSTATUS (NTAPI *_NtWow64QueryVirtualMemory64)( + IN HANDLE ProcessHandle, + IN PVOID64 BaseAddress, + IN MEMORY_INFORMATION_CLASS MemoryInformationClass, + OUT PMEMORY_BASIC_INFORMATION64 MemoryInformation, + IN ULONG64 Size, + OUT PULONG64 ReturnLength OPTIONAL); + +typedef struct { + PVOID Reserved1[2]; + PVOID64 PebBaseAddress; + PVOID Reserved2[4]; + PVOID UniqueProcessId[2]; + PVOID Reserved3[2]; +} PROCESS_BASIC_INFORMATION64; + +typedef struct { + USHORT Length; + USHORT MaxLength; + PVOID64 Buffer; +} UNICODE_STRING64; + +typedef struct { + BYTE Reserved1[16]; + PVOID64 Reserved2[5]; + UNICODE_STRING64 CurrentDirectoryPath; + PVOID64 CurrentDirectoryHandle; + UNICODE_STRING64 DllPath; + UNICODE_STRING64 ImagePathName; + UNICODE_STRING64 CommandLine; + PVOID64 env; +} RTL_USER_PROCESS_PARAMETERS64; + +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[21]; + PVOID64 LoaderData; + PVOID64 ProcessParameters; + /* More fields ... */ +} PEB64; +#endif + +/* Given a pointer into a process's memory, figure out how much data can be + * read from it. */ +static int psutil_get_process_region_size(HANDLE hProcess, + LPCVOID src, + SIZE_T *psize) { + MEMORY_BASIC_INFORMATION info; + + if (!VirtualQueryEx(hProcess, src, &info, sizeof(info))) { + PyErr_SetFromWindowsErr(0); + return -1; + } + + *psize = info.RegionSize - ((char*)src - (char*)info.BaseAddress); + return 0; +} + + +#ifndef _WIN64 +/* Given a pointer into a process's memory, figure out how much data can be + * read from it. */ +static int psutil_get_process_region_size64(HANDLE hProcess, + const PVOID64 src64, + PULONG64 psize) { + static _NtWow64QueryVirtualMemory64 NtWow64QueryVirtualMemory64 = NULL; + MEMORY_BASIC_INFORMATION64 info64; + + if (NtWow64QueryVirtualMemory64 == NULL) { + NtWow64QueryVirtualMemory64 = + (_NtWow64QueryVirtualMemory64)GetProcAddress( + GetModuleHandleA("ntdll.dll"), + "NtWow64QueryVirtualMemory64"); + + if (NtWow64QueryVirtualMemory64 == NULL) { + PyErr_SetString(PyExc_NotImplementedError, + "NtWow64QueryVirtualMemory64 missing"); + return -1; + } + } + + if (!NT_SUCCESS(NtWow64QueryVirtualMemory64( + hProcess, + src64, + 0, + &info64, + sizeof(info64), + NULL))) { + PyErr_SetFromWindowsErr(0); + return -1; + } + + *psize = info64.RegionSize - ((char*)src64 - (char*)info64.BaseAddress); + return 0; +} +#endif + + +enum psutil_process_data_kind { + KIND_CMDLINE, + KIND_CWD, + KIND_ENVIRON, +}; + +/* Get data from the process with the given pid. The data is returned in the + pdata output member as a nul terminated string which must be freed on + success. + + On success 0 is returned. On error the output parameter is not touched, -1 + is returned, and an appropriate Python exception is set. */ +static int psutil_get_process_data(long pid, + enum psutil_process_data_kind kind, + WCHAR **pdata, + SIZE_T *psize) { + /* This function is quite complex because there are several cases to be + considered: + + Two cases are really simple: we (i.e. the python interpreter) and the + target process are both 32 bit or both 64 bit. In that case the memory + layout of the structures matches up and all is well. + + When we are 64 bit and the target process is 32 bit we need to use + custom 32 bit versions of the structures. + + When we are 32 bit and the target process is 64 bit we need to use + custom 64 bit version of the structures. Also we need to use separate + Wow64 functions to get the information. + + A few helper structs are defined above so that the compiler can handle + calculating the correct offsets. + + Additional help also came from the following sources: + + https://github.com/kohsuke/winp and + http://wj32.org/wp/2009/01/24/howto-get-the-command-line-of-processes/ + http://stackoverflow.com/a/14012919 + http://www.drdobbs.com/embracing-64-bit-windows/184401966 + */ + static _NtQueryInformationProcess NtQueryInformationProcess = NULL; +#ifndef _WIN64 + static _NtQueryInformationProcess NtWow64QueryInformationProcess64 = NULL; + static _NtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = NULL; +#endif + HANDLE hProcess = NULL; + LPCVOID src; + SIZE_T size; + WCHAR *buffer = NULL; +#ifdef _WIN64 + LPVOID ppeb32 = NULL; +#else + PVOID64 src64; + BOOL weAreWow64; + BOOL theyAreWow64; +#endif + + hProcess = psutil_handle_from_pid(pid); + if (hProcess == NULL) + return -1; + + if (NtQueryInformationProcess == NULL) { + NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); + } + +#ifdef _WIN64 + /* 64 bit case. Check if the target is a 32 bit process running in WoW64 + * mode. */ + if (!NT_SUCCESS(NtQueryInformationProcess(hProcess, + ProcessWow64Information, + &ppeb32, + sizeof(LPVOID), + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + if (ppeb32 != NULL) { + /* We are 64 bit. Target process is 32 bit running in WoW64 mode. */ + PEB32 peb32; + RTL_USER_PROCESS_PARAMETERS32 procParameters32; + + // read PEB + if (!ReadProcessMemory(hProcess, ppeb32, &peb32, sizeof(peb32), NULL)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // read process parameters + if (!ReadProcessMemory(hProcess, + UlongToPtr(peb32.ProcessParameters), + &procParameters32, + sizeof(procParameters32), + NULL)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + switch (kind) { + case KIND_CMDLINE: + src = UlongToPtr(procParameters32.CommandLine.Buffer), + size = procParameters32.CommandLine.Length; + break; + case KIND_CWD: + src = UlongToPtr(procParameters32.CurrentDirectoryPath.Buffer); + size = procParameters32.CurrentDirectoryPath.Length; + break; + case KIND_ENVIRON: + src = UlongToPtr(procParameters32.env); + break; + } + } else +#else + /* 32 bit case. Check if the target is also 32 bit. */ + if (!IsWow64Process(GetCurrentProcess(), &weAreWow64) || + !IsWow64Process(hProcess, &theyAreWow64)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + if (weAreWow64 && !theyAreWow64) { + /* We are 32 bit running in WoW64 mode. Target process is 64 bit. */ + PROCESS_BASIC_INFORMATION64 pbi64; + PEB64 peb64; + RTL_USER_PROCESS_PARAMETERS64 procParameters64; + + if (NtWow64QueryInformationProcess64 == NULL) { + NtWow64QueryInformationProcess64 = + (_NtQueryInformationProcess)GetProcAddress( + GetModuleHandleA("ntdll.dll"), + "NtWow64QueryInformationProcess64"); + + if (NtWow64QueryInformationProcess64 == NULL) { + PyErr_SetString(PyExc_NotImplementedError, + "NtWow64QueryInformationProcess64 missing"); + goto error; + } + } + + if (!NT_SUCCESS(NtWow64QueryInformationProcess64( + hProcess, + ProcessBasicInformation, + &pbi64, + sizeof(pbi64), + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // read peb + if (NtWow64ReadVirtualMemory64 == NULL) { + NtWow64ReadVirtualMemory64 = + (_NtWow64ReadVirtualMemory64)GetProcAddress( + GetModuleHandleA("ntdll.dll"), + "NtWow64ReadVirtualMemory64"); + + if (NtWow64ReadVirtualMemory64 == NULL) { + PyErr_SetString(PyExc_NotImplementedError, + "NtWow64ReadVirtualMemory64 missing"); + goto error; + } + } + + if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess, + pbi64.PebBaseAddress, + &peb64, + sizeof(peb64), + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // read process parameters + if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess, + peb64.ProcessParameters, + &procParameters64, + sizeof(procParameters64), + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + switch (kind) { + case KIND_CMDLINE: + src64 = procParameters64.CommandLine.Buffer; + size = procParameters64.CommandLine.Length; + break; + case KIND_CWD: + src64 = procParameters64.CurrentDirectoryPath.Buffer, + size = procParameters64.CurrentDirectoryPath.Length; + break; + case KIND_ENVIRON: + src64 = procParameters64.env; + break; + } + } else +#endif + + /* Target process is of the same bitness as us. */ + { + PROCESS_BASIC_INFORMATION pbi; + PEB_ peb; + RTL_USER_PROCESS_PARAMETERS_ procParameters; + + if (!NT_SUCCESS(NtQueryInformationProcess(hProcess, + ProcessBasicInformation, + &pbi, + sizeof(pbi), + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // read peb + if (!ReadProcessMemory(hProcess, + pbi.PebBaseAddress, + &peb, + sizeof(peb), + NULL)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // read process parameters + if (!ReadProcessMemory(hProcess, + peb.ProcessParameters, + &procParameters, + sizeof(procParameters), + NULL)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + switch (kind) { + case KIND_CMDLINE: + src = procParameters.CommandLine.Buffer; + size = procParameters.CommandLine.Length; + break; + case KIND_CWD: + src = procParameters.CurrentDirectoryPath.Buffer; + size = procParameters.CurrentDirectoryPath.Length; + break; + case KIND_ENVIRON: + src = procParameters.env; + break; + } + } + + if (kind == KIND_ENVIRON) { +#ifndef _WIN64 + if (weAreWow64 && !theyAreWow64) { + ULONG64 size64; + + if (psutil_get_process_region_size64(hProcess, src64, &size64) != 0) + goto error; + + size = (SIZE_T)size64; + } + else +#endif + if (psutil_get_process_region_size(hProcess, src, &size) != 0) + goto error; + } + + buffer = calloc(size + 2, 1); + + if (buffer == NULL) { + PyErr_NoMemory(); + goto error; + } + +#ifndef _WIN64 + if (weAreWow64 && !theyAreWow64) { + if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess, + src64, + buffer, + size, + NULL))) { + PyErr_SetFromWindowsErr(0); + goto error; + } + } else +#endif + if (!ReadProcessMemory(hProcess, src, buffer, size, NULL)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + CloseHandle(hProcess); + + *pdata = buffer; + *psize = size; + + return 0; + +error: + if (hProcess != NULL) + CloseHandle(hProcess); + if (buffer != NULL) + free(buffer); + return -1; +} + +/* + * returns a Python list representing the arguments for the process + * with given pid or NULL on error. + */ +PyObject * +psutil_get_cmdline(long pid) { + PyObject *ret = NULL; + WCHAR *data = NULL; + SIZE_T size; + PyObject *py_retlist = NULL; + PyObject *py_unicode = NULL; + LPWSTR *szArglist = NULL; + int nArgs, i; + + if (psutil_get_process_data(pid, KIND_CMDLINE, &data, &size) != 0) + goto out; + + // attempt to parse the command line using Win32 API + szArglist = CommandLineToArgvW(data, &nArgs); + if (szArglist == NULL) { + PyErr_SetFromWindowsErr(0); + goto out; + } + + // arglist parsed as array of UNICODE_STRING, so convert each to + // Python string object and add to arg list + py_retlist = PyList_New(nArgs); + if (py_retlist == NULL) + goto out; + for (i = 0; i < nArgs; i++) { + py_unicode = PyUnicode_FromWideChar(szArglist[i], + wcslen(szArglist[i])); + if (py_unicode == NULL) + goto out; + PyList_SET_ITEM(py_retlist, i, py_unicode); + py_unicode = NULL; + } + + ret = py_retlist; + py_retlist = NULL; + +out: + LocalFree(szArglist); + free(data); + Py_XDECREF(py_unicode); + Py_XDECREF(py_retlist); + + return ret; +} + +PyObject *psutil_get_cwd(long pid) { + PyObject *ret = NULL; + WCHAR *data = NULL; + SIZE_T size; + + if (psutil_get_process_data(pid, KIND_CWD, &data, &size) != 0) + goto out; + + // convert wchar array to a Python unicode string + ret = PyUnicode_FromWideChar(data, wcslen(data)); + +out: + free(data); + + return ret; +} + +/* + * returns a Python string containing the environment variable data for the + * process with given pid or NULL on error. + */ +PyObject *psutil_get_environ(long pid) { + PyObject *ret = NULL; + WCHAR *data = NULL; + SIZE_T size; + + if (psutil_get_process_data(pid, KIND_ENVIRON, &data, &size) != 0) + goto out; + + // convert wchar array to a Python unicode string + ret = PyUnicode_FromWideChar(data, size / 2); + +out: + free(data); + + return ret; +} + +#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes)) +#define PH_NEXT_PROCESS(Process) ( \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \ + (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \ + NULL) + +const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; +const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; + +/* + * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure + * fills the structure with various process information by using + * NtQuerySystemInformation. + * We use this as a fallback when faster functions fail with access + * denied. This is slower because it iterates over all processes. + * On success return 1, else 0 with Python exception already set. + */ +int +psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, + PVOID *retBuffer) { + static ULONG initialBufferSize = 0x4000; + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + PSYSTEM_PROCESS_INFORMATION process; + + // get NtQuerySystemInformation + typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + + bufferSize = initialBufferSize; + buffer = malloc(bufferSize); + if (buffer == NULL) { + PyErr_NoMemory(); + goto error; + } + + while (TRUE) { + status = NtQuerySystemInformation(SystemProcessInformation, buffer, + bufferSize, &bufferSize); + + if (status == STATUS_BUFFER_TOO_SMALL || + status == STATUS_INFO_LENGTH_MISMATCH) + { + free(buffer); + buffer = malloc(bufferSize); + if (buffer == NULL) { + PyErr_NoMemory(); + goto error; + } + } + else { + break; + } + } + + if (status != 0) { + PyErr_Format( + PyExc_RuntimeError, "NtQuerySystemInformation() syscall failed"); + goto error; + } + + if (bufferSize <= 0x20000) + initialBufferSize = bufferSize; + + process = PH_FIRST_PROCESS(buffer); + do { + if (process->UniqueProcessId == (HANDLE)pid) { + *retProcess = process; + *retBuffer = buffer; + return 1; + } + } while ( (process = PH_NEXT_PROCESS(process)) ); + + NoSuchProcess(); + goto error; + +error: + FreeLibrary(hNtDll); + if (buffer != NULL) + free(buffer); + return 0; +} diff --git a/pipenv/vendor/psutil/arch/windows/process_info.h b/pipenv/vendor/psutil/arch/windows/process_info.h new file mode 100644 index 00000000..7c2c9c2b --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/process_info.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#if !defined(__PROCESS_INFO_H) +#define __PROCESS_INFO_H + +#include +#include +#include "security.h" +#include "ntextapi.h" + +#define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle) +#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj)) + + +DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); +HANDLE psutil_handle_from_pid(DWORD pid); +HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess); +PyObject* psutil_win32_OpenProcess(PyObject *self, PyObject *args); +PyObject* psutil_win32_CloseHandle(PyObject *self, PyObject *args); + +int psutil_handlep_is_running(HANDLE hProcess); +int psutil_pid_in_proclist(DWORD pid); +int psutil_pid_is_running(DWORD pid); +PyObject* psutil_get_cmdline(long pid); +PyObject* psutil_get_cwd(long pid); +PyObject* psutil_get_environ(long pid); +int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, + PVOID *retBuffer); + +#endif diff --git a/pipenv/vendor/psutil/arch/windows/security.c b/pipenv/vendor/psutil/arch/windows/security.c new file mode 100644 index 00000000..331d9622 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/security.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Security related functions for Windows platform (Set privileges such as + * SeDebug), as well as security helper functions. + */ + +#include +#include + + +/* + * Convert a process handle to a process token handle. + */ +HANDLE +psutil_token_from_handle(HANDLE hProcess) { + HANDLE hToken = NULL; + + if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) + return PyErr_SetFromWindowsErr(0); + return hToken; +} + + +/* + * http://www.ddj.com/windows/184405986 + * + * There's a way to determine whether we're running under the Local System + * account. However (you guessed it), we have to call more Win32 functions to + * determine this. Backing up through the code listing, we need to make another + * call to GetTokenInformation, but instead of passing through the TOKEN_USER + * constant, we pass through the TOKEN_PRIVILEGES constant. This value returns + * an array of privileges that the account has in the environment. Iterating + * through the array, we call the function LookupPrivilegeName looking for the + * string “SeTcbPrivilege. If the function returns this string, then this + * account has Local System privileges + */ +int +psutil_has_system_privilege(HANDLE hProcess) { + DWORD i; + DWORD dwSize = 0; + DWORD dwRetval = 0; + TCHAR privName[256]; + DWORD dwNameSize = 256; + // PTOKEN_PRIVILEGES tp = NULL; + BYTE *pBuffer = NULL; + TOKEN_PRIVILEGES *tp = NULL; + HANDLE hToken = psutil_token_from_handle(hProcess); + + if (NULL == hToken) + return -1; + // call GetTokenInformation first to get the buffer size + if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) { + dwRetval = GetLastError(); + // if it failed for a reason other than the buffer, bail out + if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) { + PyErr_SetFromWindowsErr(dwRetval); + return 0; + } + } + + // allocate buffer and call GetTokenInformation again + // tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize); + pBuffer = (BYTE *) malloc(dwSize); + if (pBuffer == NULL) { + PyErr_NoMemory(); + return -1; + } + + if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer, + dwSize, &dwSize)) + { + PyErr_SetFromWindowsErr(0); + free(pBuffer); + return -1; + } + + // convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer + tp = (TOKEN_PRIVILEGES *)pBuffer; + + // check all the privileges looking for SeTcbPrivilege + for (i = 0; i < tp->PrivilegeCount; i++) { + // reset the buffer contents and the buffer size + strcpy(privName, ""); + dwNameSize = sizeof(privName) / sizeof(TCHAR); + if (! LookupPrivilegeName(NULL, + &tp->Privileges[i].Luid, + (LPTSTR)privName, + &dwNameSize)) + { + PyErr_SetFromWindowsErr(0); + free(pBuffer); + return -1; + } + + // if we find the SeTcbPrivilege then it's a LocalSystem process + if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) { + free(pBuffer); + return 1; + } + } + + free(pBuffer); + return 0; +} + + +BOOL +psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) { + TOKEN_PRIVILEGES tp; + LUID luid; + TOKEN_PRIVILEGES tpPrevious; + DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); + + if (!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; + + // first pass. get current privilege setting + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = 0; + + AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + &tpPrevious, + &cbPrevious + ); + + if (GetLastError() != ERROR_SUCCESS) return FALSE; + + // second pass. set privilege based on previous setting + tpPrevious.PrivilegeCount = 1; + tpPrevious.Privileges[0].Luid = luid; + + if (bEnablePrivilege) + tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); + else + tpPrevious.Privileges[0].Attributes ^= + (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); + + AdjustTokenPrivileges( + hToken, + FALSE, + &tpPrevious, + cbPrevious, + NULL, + NULL + ); + + if (GetLastError() != ERROR_SUCCESS) return FALSE; + + return TRUE; +} + + +int +psutil_set_se_debug() { + HANDLE hToken; + if (! OpenThreadToken(GetCurrentThread(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + FALSE, + &hToken) + ) { + if (GetLastError() == ERROR_NO_TOKEN) { + if (!ImpersonateSelf(SecurityImpersonation)) { + CloseHandle(hToken); + return 0; + } + if (!OpenThreadToken(GetCurrentThread(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + FALSE, + &hToken) + ) { + RevertToSelf(); + CloseHandle(hToken); + return 0; + } + } + } + + // enable SeDebugPrivilege (open any process) + if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE)) { + RevertToSelf(); + CloseHandle(hToken); + return 0; + } + + RevertToSelf(); + CloseHandle(hToken); + return 1; +} + + +int +psutil_unset_se_debug() { + HANDLE hToken; + if (! OpenThreadToken(GetCurrentThread(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + FALSE, + &hToken) + ) { + if (GetLastError() == ERROR_NO_TOKEN) { + if (! ImpersonateSelf(SecurityImpersonation)) + return 0; + if (!OpenThreadToken(GetCurrentThread(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + FALSE, + &hToken)) + { + return 0; + } + } + } + + // now disable SeDebug + if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) + return 0; + + CloseHandle(hToken); + return 1; +} diff --git a/pipenv/vendor/psutil/arch/windows/security.h b/pipenv/vendor/psutil/arch/windows/security.h new file mode 100644 index 00000000..aa8a22ad --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/security.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Security related functions for Windows platform (Set privileges such as + * SeDebug), as well as security helper functions. + */ + +#include + +BOOL psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege); +HANDLE psutil_token_from_handle(HANDLE hProcess); +int psutil_has_system_privilege(HANDLE hProcess); +int psutil_set_se_debug(); +int psutil_unset_se_debug(); + diff --git a/pipenv/vendor/psutil/arch/windows/services.c b/pipenv/vendor/psutil/arch/windows/services.c new file mode 100644 index 00000000..26e58225 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/services.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include + +#include "services.h" + + +// ================================================================== +// utils +// ================================================================== + +SC_HANDLE +psutil_get_service_handler(char *service_name, DWORD scm_access, DWORD access) +{ + ENUM_SERVICE_STATUS_PROCESS *lpService = NULL; + SC_HANDLE sc = NULL; + SC_HANDLE hService = NULL; + SERVICE_DESCRIPTION *scd = NULL; + + sc = OpenSCManager(NULL, NULL, scm_access); + if (sc == NULL) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + hService = OpenService(sc, service_name, access); + if (hService == NULL) { + CloseServiceHandle(sc); + PyErr_SetFromWindowsErr(0); + return NULL; + } + CloseServiceHandle(sc); + return hService; +} + + +// XXX - expose these as constants? +static const char * +get_startup_string(DWORD startup) { + switch (startup) { + case SERVICE_AUTO_START: + return "automatic"; + case SERVICE_DEMAND_START: + return "manual"; + case SERVICE_DISABLED: + return "disabled"; +/* + // drivers only (since we use EnumServicesStatusEx() with + // SERVICE_WIN32) + case SERVICE_BOOT_START: + return "boot-start"; + case SERVICE_SYSTEM_START: + return "system-start"; +*/ + default: + return "unknown"; + } +} + + +// XXX - expose these as constants? +static const char * +get_state_string(DWORD state) { + switch (state) { + case SERVICE_RUNNING: + return "running"; + case SERVICE_PAUSED: + return "paused"; + case SERVICE_START_PENDING: + return "start_pending"; + case SERVICE_PAUSE_PENDING: + return "pause_pending"; + case SERVICE_CONTINUE_PENDING: + return "continue_pending"; + case SERVICE_STOP_PENDING: + return "stop_pending"; + case SERVICE_STOPPED: + return "stopped"; + default: + return "unknown"; + } +} + + +// ================================================================== +// APIs +// ================================================================== + +/* + * Enumerate all services. + */ +PyObject * +psutil_winservice_enumerate(PyObject *self, PyObject *args) { + ENUM_SERVICE_STATUS_PROCESS *lpService = NULL; + BOOL ok; + SC_HANDLE sc = NULL; + DWORD bytesNeeded = 0; + DWORD srvCount; + DWORD resumeHandle = 0; + DWORD dwBytes = 0; + DWORD i; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_unicode_display_name = NULL; + + if (py_retlist == NULL) + return NULL; + + sc = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + if (sc == NULL) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + + for (;;) { + ok = EnumServicesStatusEx( + sc, + SC_ENUM_PROCESS_INFO, + SERVICE_WIN32, // XXX - extend this to include drivers etc.? + SERVICE_STATE_ALL, + (LPBYTE)lpService, + dwBytes, + &bytesNeeded, + &srvCount, + &resumeHandle, + NULL); + if (ok || (GetLastError() != ERROR_MORE_DATA)) + break; + if (lpService) + free(lpService); + dwBytes = bytesNeeded; + lpService = (ENUM_SERVICE_STATUS_PROCESS*)malloc(dwBytes); + } + + for (i = 0; i < srvCount; i++) { + // Get unicode display name. + py_unicode_display_name = NULL; + py_unicode_display_name = PyUnicode_Decode( + lpService[i].lpDisplayName, + _tcslen(lpService[i].lpDisplayName), + Py_FileSystemDefaultEncoding, + "replace"); + if (py_unicode_display_name == NULL) + goto error; + + // Construct the result. + py_tuple = Py_BuildValue( + "(sO)", + lpService[i].lpServiceName, // name + py_unicode_display_name // display_name + ); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_unicode_display_name); + Py_DECREF(py_tuple); + } + + // Free resources. + CloseServiceHandle(sc); + free(lpService); + return py_retlist; + +error: + Py_XDECREF(py_unicode_display_name); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (sc != NULL) + CloseServiceHandle(sc); + if (lpService != NULL) + free(lpService); + return NULL; +} + + +/* + * Get service config information. Returns: + * - display_name + * - binpath + * - username + * - startup_type + */ +PyObject * +psutil_winservice_query_config(PyObject *self, PyObject *args) { + char *service_name; + SC_HANDLE hService = NULL; + BOOL ok; + DWORD bytesNeeded = 0; + DWORD resumeHandle = 0; + DWORD dwBytes = 0; + QUERY_SERVICE_CONFIG *qsc = NULL; + PyObject *py_tuple = NULL; + PyObject *py_unicode_display_name = NULL; + PyObject *py_unicode_binpath = NULL; + PyObject *py_unicode_username = NULL; + + if (!PyArg_ParseTuple(args, "s", &service_name)) + return NULL; + hService = psutil_get_service_handler( + service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG); + if (hService == NULL) + goto error; + + // First call to QueryServiceConfig() is necessary to get the + // right size. + bytesNeeded = 0; + QueryServiceConfig(hService, NULL, 0, &bytesNeeded); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + PyErr_SetFromWindowsErr(0); + goto error; + } + qsc = (QUERY_SERVICE_CONFIG *)malloc(bytesNeeded); + ok = QueryServiceConfig(hService, qsc, bytesNeeded, &bytesNeeded); + if (ok == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + // Get unicode display name. + py_unicode_display_name = PyUnicode_Decode( + qsc->lpDisplayName, + _tcslen(qsc->lpDisplayName), + Py_FileSystemDefaultEncoding, + "replace"); + if (py_unicode_display_name == NULL) + goto error; + + // Get unicode bin path. + py_unicode_binpath = PyUnicode_Decode( + qsc->lpBinaryPathName, + _tcslen(qsc->lpBinaryPathName), + Py_FileSystemDefaultEncoding, + "replace"); + if (py_unicode_binpath == NULL) + goto error; + + // Get unicode username. + py_unicode_username = PyUnicode_Decode( + qsc->lpServiceStartName, + _tcslen(qsc->lpServiceStartName), + Py_FileSystemDefaultEncoding, + "replace"); + if (py_unicode_username == NULL) + goto error; + + // Construct result tuple. + py_tuple = Py_BuildValue( + "(OOOs)", + py_unicode_display_name, + py_unicode_binpath, + py_unicode_username, + get_startup_string(qsc->dwStartType) // startup + ); + if (py_tuple == NULL) + goto error; + + // Free resources. + Py_DECREF(py_unicode_display_name); + Py_DECREF(py_unicode_binpath); + Py_DECREF(py_unicode_username); + free(qsc); + CloseServiceHandle(hService); + return py_tuple; + +error: + Py_XDECREF(py_unicode_display_name); + Py_XDECREF(py_unicode_binpath); + Py_XDECREF(py_unicode_username); + Py_XDECREF(py_tuple); + if (hService != NULL) + CloseServiceHandle(hService); + if (qsc != NULL) + free(qsc); + return NULL; +} + + +/* + * Get service status information. Returns: + * - status + * - pid + */ +PyObject * +psutil_winservice_query_status(PyObject *self, PyObject *args) { + char *service_name; + SC_HANDLE hService = NULL; + BOOL ok; + DWORD bytesNeeded = 0; + DWORD resumeHandle = 0; + DWORD dwBytes = 0; + SERVICE_STATUS_PROCESS *ssp = NULL; + PyObject *py_tuple = NULL; + + if (!PyArg_ParseTuple(args, "s", &service_name)) + return NULL; + hService = psutil_get_service_handler( + service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_STATUS); + if (hService == NULL) + goto error; + + // First call to QueryServiceStatusEx() is necessary to get the + // right size. + QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0, + &bytesNeeded); + if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + // Also services.msc fails in the same manner, so we return an + // empty string. + CloseServiceHandle(hService); + return Py_BuildValue("s", ""); + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + PyErr_SetFromWindowsErr(0); + goto error; + } + ssp = (SERVICE_STATUS_PROCESS *)HeapAlloc( + GetProcessHeap(), 0, bytesNeeded); + if (ssp == NULL) { + PyErr_NoMemory(); + goto error; + } + + // Actual call. + ok = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)ssp, + bytesNeeded, &bytesNeeded); + if (ok == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + py_tuple = Py_BuildValue( + "(sk)", + get_state_string(ssp->dwCurrentState), + ssp->dwProcessId + ); + if (py_tuple == NULL) + goto error; + + CloseServiceHandle(hService); + HeapFree(GetProcessHeap(), 0, ssp); + return py_tuple; + +error: + Py_XDECREF(py_tuple); + if (hService != NULL) + CloseServiceHandle(hService); + if (ssp != NULL) + HeapFree(GetProcessHeap(), 0, ssp); + return NULL; +} + + +/* + * Get service description. + */ +PyObject * +psutil_winservice_query_descr(PyObject *self, PyObject *args) { + ENUM_SERVICE_STATUS_PROCESS *lpService = NULL; + BOOL ok; + DWORD bytesNeeded = 0; + DWORD resumeHandle = 0; + DWORD dwBytes = 0; + SC_HANDLE hService = NULL; + SERVICE_DESCRIPTION *scd = NULL; + char *service_name; + PyObject *py_retstr = NULL; + + if (!PyArg_ParseTuple(args, "s", &service_name)) + return NULL; + hService = psutil_get_service_handler( + service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG); + if (hService == NULL) + goto error; + + // This first call to QueryServiceConfig2() is necessary in order + // to get the right size. + bytesNeeded = 0; + QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, + &bytesNeeded); + if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + // Also services.msc fails in the same manner, so we return an + // empty string. + CloseServiceHandle(hService); + return Py_BuildValue("s", ""); + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + scd = (SERVICE_DESCRIPTION *)malloc(bytesNeeded); + ok = QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, + (LPBYTE)scd, bytesNeeded, &bytesNeeded); + if (ok == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + if (scd->lpDescription == NULL) { + py_retstr = Py_BuildValue("s", ""); + } + else { + py_retstr = PyUnicode_Decode( + scd->lpDescription, + _tcslen(scd->lpDescription), + Py_FileSystemDefaultEncoding, + "replace"); + } + if (!py_retstr) + goto error; + + free(scd); + CloseServiceHandle(hService); + return py_retstr; + +error: + if (hService != NULL) + CloseServiceHandle(hService); + if (lpService != NULL) + free(lpService); + return NULL; +} + + +/* + * Start service. + * XXX - note: this is exposed but not used. + */ +PyObject * +psutil_winservice_start(PyObject *self, PyObject *args) { + char *service_name; + BOOL ok; + SC_HANDLE hService = NULL; + + if (!PyArg_ParseTuple(args, "s", &service_name)) + return NULL; + hService = psutil_get_service_handler( + service_name, SC_MANAGER_ALL_ACCESS, SERVICE_START); + if (hService == NULL) { + goto error; + } + ok = StartService(hService, 0, NULL); + if (ok == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + Py_RETURN_NONE; + +error: + if (hService != NULL) + CloseServiceHandle(hService); + return NULL; +} + + +/* + * Stop service. + * XXX - note: this is exposed but not used. + */ +PyObject * +psutil_winservice_stop(PyObject *self, PyObject *args) { + char *service_name; + BOOL ok; + SC_HANDLE hService = NULL; + SERVICE_STATUS ssp; + + if (!PyArg_ParseTuple(args, "s", &service_name)) + return NULL; + hService = psutil_get_service_handler( + service_name, SC_MANAGER_ALL_ACCESS, SERVICE_STOP); + if (hService == NULL) + goto error; + + // Note: this can hang for 30 secs. + Py_BEGIN_ALLOW_THREADS + ok = ControlService(hService, SERVICE_CONTROL_STOP, &ssp); + Py_END_ALLOW_THREADS + if (ok == 0) { + PyErr_SetFromWindowsErr(0); + goto error; + } + + CloseServiceHandle(hService); + Py_RETURN_NONE; + +error: + if (hService != NULL) + CloseServiceHandle(hService); + return NULL; +} diff --git a/pipenv/vendor/psutil/arch/windows/services.h b/pipenv/vendor/psutil/arch/windows/services.h new file mode 100644 index 00000000..286ed232 --- /dev/null +++ b/pipenv/vendor/psutil/arch/windows/services.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include + +SC_HANDLE psutil_get_service_handle( +char service_name, DWORD scm_access, DWORD access); +PyObject *psutil_winservice_enumerate(PyObject *self, PyObject *args); +PyObject *psutil_winservice_query_config(PyObject *self, PyObject *args); +PyObject *psutil_winservice_query_status(PyObject *self, PyObject *args); +PyObject *psutil_winservice_query_descr(PyObject *self, PyObject *args); +PyObject *psutil_winservice_start(PyObject *self, PyObject *args); +PyObject *psutil_winservice_stop(PyObject *self, PyObject *args); diff --git a/pipenv/vendor/psutil/tests/README.rst b/pipenv/vendor/psutil/tests/README.rst new file mode 100644 index 00000000..2ad91c14 --- /dev/null +++ b/pipenv/vendor/psutil/tests/README.rst @@ -0,0 +1,19 @@ +Instructions for running tests +============================== + +- The recommended way to run tests (also on Windows) is to cd into psutil root + directory and run ``make test``. + +- Depending on the Python version, dependencies for running tests include + ``ipaddress``, ``mock`` and ``unittest2`` modules. + On Windows also ``pywin32`` and ``wmi`` modules are recommended + (although optional). + Run ``make setup-dev-env`` to install all deps (also on Windows). + +- To run tests on all supported Python versions install tox + (``pip install tox``) then run ``tox`` from psutil root directory. + +- Every time a commit is pushed tests are automatically run on Travis + (Linux, OSX) and appveyor (Windows): + - https://travis-ci.org/giampaolo/psutil/ + - https://ci.appveyor.com/project/giampaolo/psutil diff --git a/pipenv/vendor/psutil/tests/__init__.py b/pipenv/vendor/psutil/tests/__init__.py new file mode 100644 index 00000000..13c4cfca --- /dev/null +++ b/pipenv/vendor/psutil/tests/__init__.py @@ -0,0 +1,736 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Test utilities. +""" + +from __future__ import print_function +import atexit +import contextlib +import errno +import functools +import ipaddress # python >= 3.3 / requires "pip install ipaddress" +import os +import re +import shutil +import socket +import stat +import subprocess +import sys +import tempfile +import textwrap +import threading +import time +import warnings +from socket import AF_INET +from socket import SOCK_DGRAM +from socket import SOCK_STREAM + +try: + from unittest import mock # py3 +except ImportError: + import mock # NOQA - requires "pip install mock" + +import psutil +from psutil import LINUX +from psutil import POSIX +from psutil import WINDOWS +from psutil._compat import PY3 +from psutil._compat import unicode +from psutil._compat import which + +if sys.version_info < (2, 7): + import unittest2 as unittest # requires "pip install unittest2" +else: + import unittest +if sys.version_info >= (3, 4): + import enum +else: + enum = None + +if PY3: + import importlib + # python <=3.3 + if not hasattr(importlib, 'reload'): + import imp as importlib +else: + import imp as importlib + + +__all__ = [ + # constants + 'APPVEYOR', 'DEVNULL', 'GLOBAL_TIMEOUT', 'MEMORY_TOLERANCE', 'NO_RETRIES', + 'PYPY', 'PYTHON', 'RLIMIT_SUPPORT', 'ROOT_DIR', 'SCRIPTS_DIR', + 'TESTFILE_PREFIX', 'TESTFN', 'TESTFN_UNICODE', 'TOX', 'TRAVIS', + 'VALID_PROC_STATUSES', 'VERBOSITY', + # classes + 'ThreadTask' + # test utils + 'check_connection_ntuple', 'check_net_address', 'unittest', 'cleanup', + 'skip_on_access_denied', 'skip_on_not_implemented', 'retry_before_failing', + 'run_test_module_by_name', + # fs utils + 'chdir', 'safe_rmpath', 'create_exe', + # subprocesses + 'pyrun', 'reap_children', 'get_test_subprocess', + # os + 'get_winver', 'get_kernel_version', + # sync primitives + 'call_until', 'wait_for_pid', 'wait_for_file', + # others + 'warn', 'decode_path', 'encode_path', +] + + +# =================================================================== +# --- constants +# =================================================================== + + +# conf for retry_before_failing() decorator +NO_RETRIES = 10 +# bytes tolerance for OS memory related tests +MEMORY_TOLERANCE = 500 * 1024 # 500KB +# the timeout used in functions which have to wait +GLOBAL_TIMEOUT = 3 + +AF_INET6 = getattr(socket, "AF_INET6") +AF_UNIX = getattr(socket, "AF_UNIX", None) +PYTHON = os.path.realpath(sys.executable) +DEVNULL = open(os.devnull, 'r+') + +TESTFILE_PREFIX = '$testfn' +TESTFN = os.path.join(os.path.realpath(os.getcwd()), TESTFILE_PREFIX) +_TESTFN = TESTFN + '-internal' +TESTFN_UNICODE = TESTFN + "-ƒőő" +if not PY3: + try: + TESTFN_UNICODE = unicode(TESTFN, sys.getfilesystemencoding()) + except UnicodeDecodeError: + TESTFN_UNICODE = TESTFN + "-???" + +TOX = os.getenv('TOX') or '' in ('1', 'true') +PYPY = '__pypy__' in sys.builtin_module_names + +ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), + '..', '..')) +SCRIPTS_DIR = os.path.join(ROOT_DIR, 'scripts') + +WIN_VISTA = (6, 0, 0) if WINDOWS else None +VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) + if x.startswith('STATUS_')] +# whether we're running this test suite on Travis (https://travis-ci.org/) +TRAVIS = bool(os.environ.get('TRAVIS')) +# whether we're running this test suite on Appveyor for Windows +# (http://www.appveyor.com/) +APPVEYOR = bool(os.environ.get('APPVEYOR')) + +if TRAVIS or APPVEYOR: + GLOBAL_TIMEOUT = GLOBAL_TIMEOUT * 4 +VERBOSITY = 1 if os.getenv('SILENT') or TOX else 2 + +# assertRaisesRegexp renamed to assertRaisesRegex in 3.3; add support +# for the new name +if not hasattr(unittest.TestCase, 'assertRaisesRegex'): + unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + + +# =================================================================== +# --- classes +# =================================================================== + + +class ThreadTask(threading.Thread): + """A thread object used for running process thread tests.""" + + def __init__(self): + threading.Thread.__init__(self) + self._running = False + self._interval = None + self._flag = threading.Event() + + def __repr__(self): + name = self.__class__.__name__ + return '<%s running=%s at %#x>' % (name, self._running, id(self)) + + def start(self, interval=0.001): + """Start thread and keep it running until an explicit + stop() request. Polls for shutdown every 'timeout' seconds. + """ + if self._running: + raise ValueError("already started") + self._interval = interval + threading.Thread.start(self) + self._flag.wait() + + def run(self): + self._running = True + self._flag.set() + while self._running: + time.sleep(self._interval) + + def stop(self): + """Stop thread execution and and waits until it is stopped.""" + if not self._running: + raise ValueError("already stopped") + self._running = False + self.join() + + +# =================================================================== +# --- subprocesses +# =================================================================== + + +_subprocesses_started = set() + + +def get_test_subprocess(cmd=None, **kwds): + """Return a subprocess.Popen object to use in tests. + By default stdout and stderr are redirected to /dev/null and the + python interpreter is used as test process. + It also attemps to make sure the process is in a reasonably + initialized state. + """ + kwds.setdefault("stdin", DEVNULL) + kwds.setdefault("stdout", DEVNULL) + if cmd is None: + safe_rmpath(_TESTFN) + pyline = "from time import sleep;" + pyline += "open(r'%s', 'w').close();" % _TESTFN + pyline += "sleep(60)" + cmd = [PYTHON, "-c", pyline] + sproc = subprocess.Popen(cmd, **kwds) + wait_for_file(_TESTFN, delete_file=True, empty=True) + else: + sproc = subprocess.Popen(cmd, **kwds) + wait_for_pid(sproc.pid) + _subprocesses_started.add(sproc) + return sproc + + +_testfiles = [] + + +def pyrun(src): + """Run python 'src' code in a separate interpreter. + Return interpreter subprocess. + """ + if PY3: + src = bytes(src, 'ascii') + with tempfile.NamedTemporaryFile( + prefix=TESTFILE_PREFIX, delete=False) as f: + _testfiles.append(f.name) + f.write(src) + f.flush() + subp = get_test_subprocess([PYTHON, f.name], stdout=None, + stderr=None) + wait_for_pid(subp.pid) + return subp + + +def sh(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE): + """run cmd in a subprocess and return its output. + raises RuntimeError on error. + """ + p = subprocess.Popen(cmdline, shell=True, stdout=stdout, stderr=stderr) + stdout, stderr = p.communicate() + if p.returncode != 0: + raise RuntimeError(stderr) + if stderr: + if PY3: + stderr = str(stderr, sys.stderr.encoding or + sys.getfilesystemencoding()) + warn(stderr) + if PY3: + stdout = str(stdout, sys.stdout.encoding or + sys.getfilesystemencoding()) + return stdout.strip() + + +def reap_children(recursive=False): + """Terminate and wait() any subprocess started by this test suite + and ensure that no zombies stick around to hog resources and + create problems when looking for refleaks. + + If resursive is True it also tries to terminate and wait() + all grandchildren started by this process. + """ + # Get the children here, before terminating the children sub + # processes as we don't want to lose the intermediate reference + # in case of grandchildren. + if recursive: + children = psutil.Process().children(recursive=True) + else: + children = [] + + # Terminate subprocess.Popen instances "cleanly" by closing their + # fds and wiat()ing for them in order to avoid zombies. + subprocs = _subprocesses_started.copy() + _subprocesses_started.clear() + for subp in subprocs: + try: + subp.terminate() + except OSError as err: + if err.errno != errno.ESRCH: + raise + if subp.stdout: + subp.stdout.close() + if subp.stderr: + subp.stderr.close() + try: + # Flushing a BufferedWriter may raise an error. + if subp.stdin: + subp.stdin.close() + finally: + # Wait for the process to terminate, to avoid zombies. + try: + subp.wait() + except OSError as err: + if err.errno != errno.ECHILD: + raise + + # Terminates grandchildren. + if children: + for p in children: + try: + p.terminate() + except psutil.NoSuchProcess: + pass + gone, alive = psutil.wait_procs(children, timeout=GLOBAL_TIMEOUT) + for p in alive: + warn("couldn't terminate process %r; attempting kill()" % p) + try: + p.kill() + except psutil.NoSuchProcess: + pass + _, alive = psutil.wait_procs(alive, timeout=GLOBAL_TIMEOUT) + if alive: + for p in alive: + warn("process %r survived kill()" % p) + + +# =================================================================== +# --- OS +# =================================================================== + + +if not POSIX: + def get_kernel_version(): + return () +else: + def get_kernel_version(): + """Return a tuple such as (2, 6, 36).""" + s = "" + uname = os.uname()[2] + for c in uname: + if c.isdigit() or c == '.': + s += c + else: + break + if not s: + raise ValueError("can't parse %r" % uname) + minor = 0 + micro = 0 + nums = s.split('.') + major = int(nums[0]) + if len(nums) >= 2: + minor = int(nums[1]) + if len(nums) >= 3: + micro = int(nums[2]) + return (major, minor, micro) + + +if LINUX: + RLIMIT_SUPPORT = get_kernel_version() >= (2, 6, 36) +else: + RLIMIT_SUPPORT = False + + +if not WINDOWS: + def get_winver(): + raise NotImplementedError("not a Windows OS") +else: + def get_winver(): + wv = sys.getwindowsversion() + if hasattr(wv, 'service_pack_major'): # python >= 2.7 + sp = wv.service_pack_major or 0 + else: + r = re.search("\s\d$", wv[4]) + if r: + sp = int(r.group(0)) + else: + sp = 0 + return (wv[0], wv[1], sp) + + +# =================================================================== +# --- sync primitives +# =================================================================== + + +class retry(object): + """A retry decorator.""" + + def __init__(self, + exception=Exception, + timeout=None, + retries=None, + interval=0.001, + logfun=lambda s: print(s, file=sys.stderr), + ): + if timeout and retries: + raise ValueError("timeout and retries args are mutually exclusive") + self.exception = exception + self.timeout = timeout + self.retries = retries + self.interval = interval + self.logfun = logfun + + def __iter__(self): + if self.timeout: + stop_at = time.time() + self.timeout + while time.time() < stop_at: + yield + elif self.retries: + for _ in range(self.retries): + yield + else: + while True: + yield + + def sleep(self): + if self.interval is not None: + time.sleep(self.interval) + + def __call__(self, fun): + @functools.wraps(fun) + def wrapper(*args, **kwargs): + exc = None + for _ in self: + try: + return fun(*args, **kwargs) + except self.exception as _: + exc = _ + if self.logfun is not None: + self.logfun(exc) + self.sleep() + else: + if PY3: + raise exc + else: + raise + + # This way the user of the decorated function can change config + # parameters. + wrapper.decorator = self + return wrapper + + +@retry(exception=psutil.NoSuchProcess, logfun=None, timeout=GLOBAL_TIMEOUT, + interval=0.001) +def wait_for_pid(pid): + """Wait for pid to show up in the process list then return. + Used in the test suite to give time the sub process to initialize. + """ + psutil.Process(pid) + if WINDOWS: + # give it some more time to allow better initialization + time.sleep(0.01) + + +@retry(exception=(EnvironmentError, AssertionError), logfun=None, + timeout=GLOBAL_TIMEOUT, interval=0.001) +def wait_for_file(fname, delete_file=True, empty=False): + """Wait for a file to be written on disk with some content.""" + with open(fname, "rb") as f: + data = f.read() + if not empty: + assert data + if delete_file: + os.remove(fname) + return data + + +@retry(exception=AssertionError, logfun=None, timeout=GLOBAL_TIMEOUT, + interval=0.001) +def call_until(fun, expr): + """Keep calling function for timeout secs and exit if eval() + expression is True. + """ + ret = fun() + assert eval(expr) + return ret + + +# =================================================================== +# --- fs +# =================================================================== + + +def safe_rmpath(path): + "Convenience function for removing temporary test files or dirs" + try: + st = os.stat(path) + if stat.S_ISDIR(st.st_mode): + os.rmdir(path) + else: + os.remove(path) + except OSError as err: + if err.errno != errno.ENOENT: + raise + + +def safe_mkdir(dir): + "Convenience function for creating a directory" + try: + os.mkdir(dir) + except OSError as err: + if err.errno != errno.EEXIST: + raise + + +@contextlib.contextmanager +def chdir(dirname): + "Context manager which temporarily changes the current directory." + curdir = os.getcwd() + try: + os.chdir(dirname) + yield + finally: + os.chdir(curdir) + + +def create_exe(outpath, c_code=None): + """Creates an executable file in the given location.""" + assert not os.path.exists(outpath), outpath + if which("gcc"): + if c_code is None: + c_code = textwrap.dedent( + """ + #include + int main() { + pause(); + return 1; + } + """) + with tempfile.NamedTemporaryFile( + suffix='.c', delete=False, mode='wt') as f: + f.write(c_code) + try: + subprocess.check_call(["gcc", f.name, "-o", outpath]) + finally: + safe_rmpath(f.name) + else: + # fallback - use python's executable + if c_code is not None: + raise ValueError( + "can't specify c_code arg as gcc is not installed") + shutil.copyfile(sys.executable, outpath) + if POSIX: + st = os.stat(outpath) + os.chmod(outpath, st.st_mode | stat.S_IEXEC) + + +# =================================================================== +# --- testing +# =================================================================== + + +class TestCase(unittest.TestCase): + + def __str__(self): + return "%s.%s.%s" % ( + self.__class__.__module__, self.__class__.__name__, + self._testMethodName) + + +# Hack that overrides default unittest.TestCase in order to print +# a full path representation of the single unit tests being run. +unittest.TestCase = TestCase + + +def retry_before_failing(retries=NO_RETRIES): + """Decorator which runs a test function and retries N times before + actually failing. + """ + return retry(exception=AssertionError, timeout=None, retries=retries) + + +def run_test_module_by_name(name): + # testmodules = [os.path.splitext(x)[0] for x in os.listdir(HERE) + # if x.endswith('.py') and x.startswith('test_')] + name = os.path.splitext(os.path.basename(name))[0] + suite = unittest.TestSuite() + suite.addTest(unittest.defaultTestLoader.loadTestsFromName(name)) + result = unittest.TextTestRunner(verbosity=VERBOSITY).run(suite) + success = result.wasSuccessful() + sys.exit(0 if success else 1) + + +def skip_on_access_denied(only_if=None): + """Decorator to Ignore AccessDenied exceptions.""" + def decorator(fun): + @functools.wraps(fun) + def wrapper(*args, **kwargs): + try: + return fun(*args, **kwargs) + except psutil.AccessDenied: + if only_if is not None: + if not only_if: + raise + msg = "%r was skipped because it raised AccessDenied" \ + % fun.__name__ + raise unittest.SkipTest(msg) + return wrapper + return decorator + + +def skip_on_not_implemented(only_if=None): + """Decorator to Ignore NotImplementedError exceptions.""" + def decorator(fun): + @functools.wraps(fun) + def wrapper(*args, **kwargs): + try: + return fun(*args, **kwargs) + except NotImplementedError: + if only_if is not None: + if not only_if: + raise + msg = "%r was skipped because it raised NotImplementedError" \ + % fun.__name__ + raise unittest.SkipTest(msg) + return wrapper + return decorator + + +def check_net_address(addr, family): + """Check a net address validity. Supported families are IPv4, + IPv6 and MAC addresses. + """ + if enum and PY3: + assert isinstance(family, enum.IntEnum), family + if family == AF_INET: + octs = [int(x) for x in addr.split('.')] + assert len(octs) == 4, addr + for num in octs: + assert 0 <= num <= 255, addr + if not PY3: + addr = unicode(addr) + ipaddress.IPv4Address(addr) + elif family == AF_INET6: + assert isinstance(addr, str), addr + if not PY3: + addr = unicode(addr) + ipaddress.IPv6Address(addr) + elif family == psutil.AF_LINK: + assert re.match('([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr + else: + raise ValueError("unknown family %r", family) + + +def check_connection_ntuple(conn): + """Check validity of a connection namedtuple.""" + valid_conn_states = [getattr(psutil, x) for x in dir(psutil) if + x.startswith('CONN_')] + assert conn[0] == conn.fd + assert conn[1] == conn.family + assert conn[2] == conn.type + assert conn[3] == conn.laddr + assert conn[4] == conn.raddr + assert conn[5] == conn.status + assert conn.type in (SOCK_STREAM, SOCK_DGRAM), repr(conn.type) + assert conn.family in (AF_INET, AF_INET6, AF_UNIX), repr(conn.family) + assert conn.status in valid_conn_states, conn.status + + # check IP address and port sanity + for addr in (conn.laddr, conn.raddr): + if not addr: + continue + if conn.family in (AF_INET, AF_INET6): + assert isinstance(addr, tuple), addr + ip, port = addr + assert isinstance(port, int), port + assert 0 <= port <= 65535, port + check_net_address(ip, conn.family) + elif conn.family == AF_UNIX: + assert isinstance(addr, (str, None)), addr + else: + raise ValueError("unknown family %r", conn.family) + + if conn.family in (AF_INET, AF_INET6): + # actually try to bind the local socket; ignore IPv6 + # sockets as their address might be represented as + # an IPv4-mapped-address (e.g. "::127.0.0.1") + # and that's rejected by bind() + if conn.family == AF_INET: + s = socket.socket(conn.family, conn.type) + with contextlib.closing(s): + try: + s.bind((conn.laddr[0], 0)) + except socket.error as err: + if err.errno != errno.EADDRNOTAVAIL: + raise + elif conn.family == AF_UNIX: + assert not conn.raddr, repr(conn.raddr) + assert conn.status == psutil.CONN_NONE, conn.status + + if getattr(conn, 'fd', -1) != -1: + assert conn.fd > 0, conn + if hasattr(socket, 'fromfd') and not WINDOWS: + try: + dupsock = socket.fromfd(conn.fd, conn.family, conn.type) + except (socket.error, OSError) as err: + if err.args[0] != errno.EBADF: + raise + else: + with contextlib.closing(dupsock): + assert dupsock.family == conn.family + assert dupsock.type == conn.type + + +def cleanup(): + for name in os.listdir('.'): + if name.startswith(TESTFILE_PREFIX): + try: + safe_rmpath(name) + except UnicodeEncodeError as exc: + warn(exc) + for path in _testfiles: + safe_rmpath(path) + + +atexit.register(cleanup) +atexit.register(lambda: DEVNULL.close()) + + +# =================================================================== +# --- others +# =================================================================== + + +def warn(msg): + """Raise a warning msg.""" + warnings.warn(msg, UserWarning) + + +# In Python 3 paths are unicode objects by default. Surrogate escapes +# are used to handle non-character data. +def encode_path(path): + if PY3: + return path.encode(sys.getfilesystemencoding(), + errors="surrogateescape") + else: + return path + + +def decode_path(path): + if PY3: + return path.decode(sys.getfilesystemencoding(), + errors="surrogateescape") + else: + return path diff --git a/pipenv/vendor/psutil/tests/runner.py b/pipenv/vendor/psutil/tests/runner.py new file mode 100755 index 00000000..88bcd620 --- /dev/null +++ b/pipenv/vendor/psutil/tests/runner.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Copyright (C) 2007-2016 Giampaolo Rodola' . +# Use of this source code is governed by MIT license that can be +# found in the LICENSE file. + +"""Script for running all test files (except memory leaks tests).""" + +import os +import sys + +from psutil.tests import unittest +from psutil.tests import VERBOSITY + + +def get_suite(): + HERE = os.path.abspath(os.path.dirname(__file__)) + testmodules = [os.path.splitext(x)[0] for x in os.listdir(HERE) + if x.endswith('.py') and x.startswith('test_') and not + x.startswith('test_memory_leaks')] + suite = unittest.TestSuite() + for tm in testmodules: + # ...so that "make test" will print the full test paths + tm = "psutil.tests.%s" % tm + suite.addTest(unittest.defaultTestLoader.loadTestsFromName(tm)) + return suite + + +def main(): + # run tests + result = unittest.TextTestRunner(verbosity=VERBOSITY).run(get_suite()) + success = result.wasSuccessful() + sys.exit(0 if success else 1) + + +if __name__ == '__main__': + main() diff --git a/pipenv/vendor/psutil/tests/test_bsd.py b/pipenv/vendor/psutil/tests/test_bsd.py new file mode 100755 index 00000000..9c1753d5 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_bsd.py @@ -0,0 +1,482 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# TODO: (FreeBSD) add test for comparing connections with 'sockstat' cmd. + + +"""Tests specific to all BSD platforms.""" + + +import datetime +import os +import re +import subprocess +import sys +import time + +import psutil +from psutil import BSD +from psutil import FREEBSD +from psutil import NETBSD +from psutil import OPENBSD +from psutil._compat import PY3 +from psutil.tests import get_test_subprocess +from psutil.tests import MEMORY_TOLERANCE +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import sh +from psutil.tests import unittest +from psutil.tests import which + + +if BSD: + PAGESIZE = os.sysconf("SC_PAGE_SIZE") + if os.getuid() == 0: # muse requires root privileges + MUSE_AVAILABLE = which('muse') + else: + MUSE_AVAILABLE = False +else: + MUSE_AVAILABLE = False + + +def sysctl(cmdline): + """Expects a sysctl command with an argument and parse the result + returning only the value of interest. + """ + result = sh("sysctl " + cmdline) + if FREEBSD: + result = result[result.find(": ") + 2:] + elif OPENBSD or NETBSD: + result = result[result.find("=") + 1:] + try: + return int(result) + except ValueError: + return result + + +def muse(field): + """Thin wrapper around 'muse' cmdline utility.""" + out = sh('muse') + for line in out.split('\n'): + if line.startswith(field): + break + else: + raise ValueError("line not found") + return int(line.split()[1]) + + +# ===================================================================== +# --- All BSD* +# ===================================================================== + + +@unittest.skipUnless(BSD, "BSD only") +class BSDSpecificTestCase(unittest.TestCase): + """Generic tests common to all BSD variants.""" + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + + def test_process_create_time(self): + cmdline = "ps -o lstart -p %s" % self.pid + p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) + output = p.communicate()[0] + if PY3: + output = str(output, sys.stdout.encoding) + start_ps = output.replace('STARTED', '').strip() + start_psutil = psutil.Process(self.pid).create_time() + start_psutil = time.strftime("%a %b %e %H:%M:%S %Y", + time.localtime(start_psutil)) + self.assertEqual(start_ps, start_psutil) + + def test_disks(self): + # test psutil.disk_usage() and psutil.disk_partitions() + # against "df -a" + def df(path): + out = sh('df -k "%s"' % path).strip() + lines = out.split('\n') + lines.pop(0) + line = lines.pop(0) + dev, total, used, free = line.split()[:4] + if dev == 'none': + dev = '' + total = int(total) * 1024 + used = int(used) * 1024 + free = int(free) * 1024 + return dev, total, used, free + + for part in psutil.disk_partitions(all=False): + usage = psutil.disk_usage(part.mountpoint) + dev, total, used, free = df(part.mountpoint) + self.assertEqual(part.device, dev) + self.assertEqual(usage.total, total) + # 10 MB tollerance + if abs(usage.free - free) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % (usage.free, free)) + if abs(usage.used - used) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % (usage.used, used)) + + @unittest.skipIf(not which('sysctl'), "sysctl cmd not available") + def test_cpu_count_logical(self): + syst = sysctl("hw.ncpu") + self.assertEqual(psutil.cpu_count(logical=True), syst) + + @unittest.skipIf(not which('sysctl'), "sysctl cmd not available") + def test_virtual_memory_total(self): + num = sysctl('hw.physmem') + self.assertEqual(num, psutil.virtual_memory().total) + + def test_net_if_stats(self): + for name, stats in psutil.net_if_stats().items(): + try: + out = sh("ifconfig %s" % name) + except RuntimeError: + pass + else: + self.assertEqual(stats.isup, 'RUNNING' in out, msg=out) + self.assertEqual(stats.mtu, + int(re.findall('mtu (\d+)', out)[0])) + + +# ===================================================================== +# --- FreeBSD +# ===================================================================== + + +@unittest.skipUnless(FREEBSD, "FREEBSD only") +class FreeBSDSpecificTestCase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + + @retry_before_failing() + def test_proc_memory_maps(self): + out = sh('procstat -v %s' % self.pid) + maps = psutil.Process(self.pid).memory_maps(grouped=False) + lines = out.split('\n')[1:] + while lines: + line = lines.pop() + fields = line.split() + _, start, stop, perms, res = fields[:5] + map = maps.pop() + self.assertEqual("%s-%s" % (start, stop), map.addr) + self.assertEqual(int(res), map.rss) + if not map.path.startswith('['): + self.assertEqual(fields[10], map.path) + + def test_proc_exe(self): + out = sh('procstat -b %s' % self.pid) + self.assertEqual(psutil.Process(self.pid).exe(), + out.split('\n')[1].split()[-1]) + + def test_proc_cmdline(self): + out = sh('procstat -c %s' % self.pid) + self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()), + ' '.join(out.split('\n')[1].split()[2:])) + + def test_proc_uids_gids(self): + out = sh('procstat -s %s' % self.pid) + euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8] + p = psutil.Process(self.pid) + uids = p.uids() + gids = p.gids() + self.assertEqual(uids.real, int(ruid)) + self.assertEqual(uids.effective, int(euid)) + self.assertEqual(uids.saved, int(suid)) + self.assertEqual(gids.real, int(rgid)) + self.assertEqual(gids.effective, int(egid)) + self.assertEqual(gids.saved, int(sgid)) + + @retry_before_failing() + def test_proc_ctx_switches(self): + tested = [] + out = sh('procstat -r %s' % self.pid) + p = psutil.Process(self.pid) + for line in out.split('\n'): + line = line.lower().strip() + if ' voluntary context' in line: + pstat_value = int(line.split()[-1]) + psutil_value = p.num_ctx_switches().voluntary + self.assertEqual(pstat_value, psutil_value) + tested.append(None) + elif ' involuntary context' in line: + pstat_value = int(line.split()[-1]) + psutil_value = p.num_ctx_switches().involuntary + self.assertEqual(pstat_value, psutil_value) + tested.append(None) + if len(tested) != 2: + raise RuntimeError("couldn't find lines match in procstat out") + + @retry_before_failing() + def test_proc_cpu_times(self): + tested = [] + out = sh('procstat -r %s' % self.pid) + p = psutil.Process(self.pid) + for line in out.split('\n'): + line = line.lower().strip() + if 'user time' in line: + pstat_value = float('0.' + line.split()[-1].split('.')[-1]) + psutil_value = p.cpu_times().user + self.assertEqual(pstat_value, psutil_value) + tested.append(None) + elif 'system time' in line: + pstat_value = float('0.' + line.split()[-1].split('.')[-1]) + psutil_value = p.cpu_times().system + self.assertEqual(pstat_value, psutil_value) + tested.append(None) + if len(tested) != 2: + raise RuntimeError("couldn't find lines match in procstat out") + + # --- virtual_memory(); tests against sysctl + + @retry_before_failing() + def test_vmem_active(self): + syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE + self.assertAlmostEqual(psutil.virtual_memory().active, syst, + delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_inactive(self): + syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE + self.assertAlmostEqual(psutil.virtual_memory().inactive, syst, + delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_wired(self): + syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE + self.assertAlmostEqual(psutil.virtual_memory().wired, syst, + delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_cached(self): + syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE + self.assertAlmostEqual(psutil.virtual_memory().cached, syst, + delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_free(self): + syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE + self.assertAlmostEqual(psutil.virtual_memory().free, syst, + delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_buffers(self): + syst = sysctl("vfs.bufspace") + self.assertAlmostEqual(psutil.virtual_memory().buffers, syst, + delta=MEMORY_TOLERANCE) + + # --- virtual_memory(); tests against muse + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + def test_muse_vmem_total(self): + num = muse('Total') + self.assertEqual(psutil.virtual_memory().total, num) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_active(self): + num = muse('Active') + self.assertAlmostEqual(psutil.virtual_memory().active, num, + delta=MEMORY_TOLERANCE) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_inactive(self): + num = muse('Inactive') + self.assertAlmostEqual(psutil.virtual_memory().inactive, num, + delta=MEMORY_TOLERANCE) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_wired(self): + num = muse('Wired') + self.assertAlmostEqual(psutil.virtual_memory().wired, num, + delta=MEMORY_TOLERANCE) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_cached(self): + num = muse('Cache') + self.assertAlmostEqual(psutil.virtual_memory().cached, num, + delta=MEMORY_TOLERANCE) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_free(self): + num = muse('Free') + self.assertAlmostEqual(psutil.virtual_memory().free, num, + delta=MEMORY_TOLERANCE) + + @unittest.skipUnless(MUSE_AVAILABLE, "muse not installed") + @retry_before_failing() + def test_muse_vmem_buffers(self): + num = muse('Buffer') + self.assertAlmostEqual(psutil.virtual_memory().buffers, num, + delta=MEMORY_TOLERANCE) + + def test_cpu_stats_ctx_switches(self): + self.assertAlmostEqual(psutil.cpu_stats().ctx_switches, + sysctl('vm.stats.sys.v_swtch'), delta=1000) + + def test_cpu_stats_interrupts(self): + self.assertAlmostEqual(psutil.cpu_stats().interrupts, + sysctl('vm.stats.sys.v_intr'), delta=1000) + + def test_cpu_stats_soft_interrupts(self): + self.assertAlmostEqual(psutil.cpu_stats().soft_interrupts, + sysctl('vm.stats.sys.v_soft'), delta=1000) + + def test_cpu_stats_syscalls(self): + self.assertAlmostEqual(psutil.cpu_stats().syscalls, + sysctl('vm.stats.sys.v_syscall'), delta=1000) + + # def test_cpu_stats_traps(self): + # self.assertAlmostEqual(psutil.cpu_stats().traps, + # sysctl('vm.stats.sys.v_trap'), delta=1000) + + # --- others + + def test_boot_time(self): + s = sysctl('sysctl kern.boottime') + s = s[s.find(" sec = ") + 7:] + s = s[:s.find(',')] + btime = int(s) + self.assertEqual(btime, psutil.boot_time()) + + # --- sensors_battery + + @unittest.skipUnless( + hasattr(psutil, "sensors_battery") and psutil.sensors_battery(), + "no battery") + def test_sensors_battery(self): + def secs2hours(secs): + m, s = divmod(secs, 60) + h, m = divmod(m, 60) + return "%d:%02d" % (h, m) + + out = sh("acpiconf -i 0") + fields = dict([(x.split('\t')[0], x.split('\t')[-1]) + for x in out.split("\n")]) + metrics = psutil.sensors_battery() + percent = int(fields['Remaining capacity:'].replace('%', '')) + remaining_time = fields['Remaining time:'] + self.assertEqual(metrics.percent, percent) + if remaining_time == 'unknown': + self.assertEqual(metrics.secsleft, psutil.POWER_TIME_UNLIMITED) + else: + self.assertEqual(secs2hours(metrics.secsleft), remaining_time) + + def test_sensors_battery_against_sysctl(self): + self.assertEqual(psutil.sensors_battery().percent, + sysctl("hw.acpi.battery.life")) + self.assertEqual(psutil.sensors_battery().power_plugged, + sysctl("hw.acpi.acline") == 1) + secsleft = psutil.sensors_battery().secsleft + if secsleft < 0: + self.assertEqual(sysctl("hw.acpi.battery.time"), -1) + else: + self.assertEqual(secsleft, sysctl("hw.acpi.battery.time") * 60) + + +# ===================================================================== +# --- OpenBSD +# ===================================================================== + + +@unittest.skipUnless(OPENBSD, "OPENBSD only") +class OpenBSDSpecificTestCase(unittest.TestCase): + + def test_boot_time(self): + s = sysctl('kern.boottime') + sys_bt = datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y") + psutil_bt = datetime.datetime.fromtimestamp(psutil.boot_time()) + self.assertEqual(sys_bt, psutil_bt) + + +# ===================================================================== +# --- NetBSD +# ===================================================================== + + +@unittest.skipUnless(NETBSD, "NETBSD only") +class NetBSDSpecificTestCase(unittest.TestCase): + + def parse_meminfo(self, look_for): + with open('/proc/meminfo', 'rb') as f: + for line in f: + if line.startswith(look_for): + return int(line.split()[1]) * 1024 + raise ValueError("can't find %s" % look_for) + + def test_vmem_total(self): + self.assertEqual( + psutil.virtual_memory().total, self.parse_meminfo("MemTotal:")) + + def test_vmem_free(self): + self.assertAlmostEqual( + psutil.virtual_memory().free, self.parse_meminfo("MemFree:"), + delta=MEMORY_TOLERANCE) + + def test_vmem_buffers(self): + self.assertAlmostEqual( + psutil.virtual_memory().buffers, self.parse_meminfo("Buffers:"), + delta=MEMORY_TOLERANCE) + + def test_vmem_shared(self): + self.assertAlmostEqual( + psutil.virtual_memory().shared, self.parse_meminfo("MemShared:"), + delta=MEMORY_TOLERANCE) + + def test_swapmem_total(self): + self.assertAlmostEqual( + psutil.swap_memory().total, self.parse_meminfo("SwapTotal:"), + delta=MEMORY_TOLERANCE) + + def test_swapmem_free(self): + self.assertAlmostEqual( + psutil.swap_memory().free, self.parse_meminfo("SwapFree:"), + delta=MEMORY_TOLERANCE) + + def test_swapmem_used(self): + smem = psutil.swap_memory() + self.assertEqual(smem.used, smem.total - smem.free) + + def test_cpu_stats_interrupts(self): + with open('/proc/stat', 'rb') as f: + for line in f: + if line.startswith(b'intr'): + interrupts = int(line.split()[1]) + break + else: + raise ValueError("couldn't find line") + self.assertAlmostEqual( + psutil.cpu_stats().interrupts, interrupts, delta=1000) + + def test_cpu_stats_ctx_switches(self): + with open('/proc/stat', 'rb') as f: + for line in f: + if line.startswith(b'ctxt'): + ctx_switches = int(line.split()[1]) + break + else: + raise ValueError("couldn't find line") + self.assertAlmostEqual( + psutil.cpu_stats().ctx_switches, ctx_switches, delta=1000) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_linux.py b/pipenv/vendor/psutil/tests/test_linux.py new file mode 100755 index 00000000..f9731bea --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_linux.py @@ -0,0 +1,1434 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Linux specific tests.""" + +from __future__ import division +import collections +import contextlib +import errno +import io +import os +import pprint +import re +import shutil +import socket +import struct +import tempfile +import textwrap +import time +import warnings + +import psutil +from psutil import LINUX +from psutil._compat import PY3 +from psutil._compat import u +from psutil.tests import call_until +from psutil.tests import get_kernel_version +from psutil.tests import importlib +from psutil.tests import MEMORY_TOLERANCE +from psutil.tests import mock +from psutil.tests import PYPY +from psutil.tests import pyrun +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import safe_rmpath +from psutil.tests import sh +from psutil.tests import skip_on_not_implemented +from psutil.tests import TESTFN +from psutil.tests import ThreadTask +from psutil.tests import TRAVIS +from psutil.tests import unittest +from psutil.tests import which + + +HERE = os.path.abspath(os.path.dirname(__file__)) +SIOCGIFADDR = 0x8915 +SIOCGIFCONF = 0x8912 +SIOCGIFHWADDR = 0x8927 +if LINUX: + SECTOR_SIZE = 512 + + +# ===================================================================== +# --- utils +# ===================================================================== + + +def get_ipv4_address(ifname): + import fcntl + ifname = ifname[:15] + if PY3: + ifname = bytes(ifname, 'ascii') + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + with contextlib.closing(s): + return socket.inet_ntoa( + fcntl.ioctl(s.fileno(), + SIOCGIFADDR, + struct.pack('256s', ifname))[20:24]) + + +def get_mac_address(ifname): + import fcntl + ifname = ifname[:15] + if PY3: + ifname = bytes(ifname, 'ascii') + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + with contextlib.closing(s): + info = fcntl.ioctl( + s.fileno(), SIOCGIFHWADDR, struct.pack('256s', ifname)) + if PY3: + def ord(x): + return x + else: + import __builtin__ + ord = __builtin__.ord + return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1] + + +def free_swap(): + """Parse 'free' cmd and return swap memory's s total, used and free + values. + """ + out = sh('free -b') + lines = out.split('\n') + for line in lines: + if line.startswith('Swap'): + _, total, used, free = line.split() + nt = collections.namedtuple('free', 'total used free') + return nt(int(total), int(used), int(free)) + raise ValueError( + "can't find 'Swap' in 'free' output:\n%s" % '\n'.join(lines)) + + +def free_physmem(): + """Parse 'free' cmd and return physical memory's total, used + and free values. + """ + # Note: free can have 2 different formats, invalidating 'shared' + # and 'cached' memory which may have different positions so we + # do not return them. + # https://github.com/giampaolo/psutil/issues/538#issuecomment-57059946 + out = sh('free -b') + lines = out.split('\n') + for line in lines: + if line.startswith('Mem'): + total, used, free, shared = \ + [int(x) for x in line.split()[1:5]] + nt = collections.namedtuple( + 'free', 'total used free shared output') + return nt(total, used, free, shared, out) + raise ValueError( + "can't find 'Mem' in 'free' output:\n%s" % '\n'.join(lines)) + + +def vmstat(stat): + out = sh("vmstat -s") + for line in out.split("\n"): + line = line.strip() + if stat in line: + return int(line.split(' ')[0]) + raise ValueError("can't find %r in 'vmstat' output" % stat) + + +def get_free_version_info(): + out = sh("free -V").strip() + return tuple(map(int, out.split()[-1].split('.'))) + + +# ===================================================================== +# --- system virtual memory +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemVirtualMemory(unittest.TestCase): + + def test_total(self): + # free_value = free_physmem().total + # psutil_value = psutil.virtual_memory().total + # self.assertEqual(free_value, psutil_value) + vmstat_value = vmstat('total memory') * 1024 + psutil_value = psutil.virtual_memory().total + self.assertAlmostEqual(vmstat_value, psutil_value) + + # Older versions of procps used slab memory to calculate used memory. + # This got changed in: + # https://gitlab.com/procps-ng/procps/commit/ + # 05d751c4f076a2f0118b914c5e51cfbb4762ad8e + @unittest.skipUnless( + LINUX and get_free_version_info() >= (3, 3, 12), "old free version") + @retry_before_failing() + def test_used(self): + free = free_physmem() + free_value = free.used + psutil_value = psutil.virtual_memory().used + self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE, + msg='%s %s \n%s' % (free_value, psutil_value, free.output)) + + @retry_before_failing() + def test_free(self): + # _, _, free_value, _ = free_physmem() + # psutil_value = psutil.virtual_memory().free + # self.assertAlmostEqual( + # free_value, psutil_value, delta=MEMORY_TOLERANCE) + vmstat_value = vmstat('free memory') * 1024 + psutil_value = psutil.virtual_memory().free + self.assertAlmostEqual( + vmstat_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_buffers(self): + vmstat_value = vmstat('buffer memory') * 1024 + psutil_value = psutil.virtual_memory().buffers + self.assertAlmostEqual( + vmstat_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_active(self): + vmstat_value = vmstat('active memory') * 1024 + psutil_value = psutil.virtual_memory().active + self.assertAlmostEqual( + vmstat_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_inactive(self): + vmstat_value = vmstat('inactive memory') * 1024 + psutil_value = psutil.virtual_memory().inactive + self.assertAlmostEqual( + vmstat_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_shared(self): + free = free_physmem() + free_value = free.shared + if free_value == 0: + raise unittest.SkipTest("free does not support 'shared' column") + psutil_value = psutil.virtual_memory().shared + self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE, + msg='%s %s \n%s' % (free_value, psutil_value, free.output)) + + @retry_before_failing() + def test_available(self): + # "free" output format has changed at some point: + # https://github.com/giampaolo/psutil/issues/538#issuecomment-147192098 + out = sh("free -b") + lines = out.split('\n') + if 'available' not in lines[0]: + raise unittest.SkipTest("free does not support 'available' column") + else: + free_value = int(lines[1].split()[-1]) + psutil_value = psutil.virtual_memory().available + self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE, + msg='%s %s \n%s' % (free_value, psutil_value, out)) + + def test_warnings_mocked(self): + def open_mock(name, *args, **kwargs): + if name == '/proc/meminfo': + return io.BytesIO(textwrap.dedent("""\ + Active(anon): 6145416 kB + Active(file): 2950064 kB + Buffers: 287952 kB + Inactive(anon): 574764 kB + Inactive(file): 1567648 kB + MemAvailable: 6574984 kB + MemFree: 2057400 kB + MemTotal: 16325648 kB + SReclaimable: 346648 kB + """).encode()) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, create=True, side_effect=open_mock) as m: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = psutil.virtual_memory() + assert m.called + self.assertEqual(len(ws), 1) + w = ws[0] + self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) + self.assertIn( + "memory stats couldn't be determined", str(w.message)) + self.assertIn("cached", str(w.message)) + self.assertIn("shared", str(w.message)) + self.assertIn("active", str(w.message)) + self.assertIn("inactive", str(w.message)) + self.assertEqual(ret.cached, 0) + self.assertEqual(ret.active, 0) + self.assertEqual(ret.inactive, 0) + self.assertEqual(ret.shared, 0) + + def test_avail_old_percent(self): + # Make sure that our calculation of avail mem for old kernels + # is off by max 10%. + from psutil._pslinux import calculate_avail_vmem + from psutil._pslinux import open_binary + + mems = {} + with open_binary('/proc/meminfo') as f: + for line in f: + fields = line.split() + mems[fields[0]] = int(fields[1]) * 1024 + + a = calculate_avail_vmem(mems) + if b'MemAvailable:' in mems: + b = mems[b'MemAvailable:'] + diff_percent = abs(a - b) / a * 100 + self.assertLess(diff_percent, 10) + + def test_avail_old_comes_from_kernel(self): + # Make sure "MemAvailable:" coluimn is used instead of relying + # on our internal algorithm to calculate avail mem. + def open_mock(name, *args, **kwargs): + if name == "/proc/meminfo": + return io.BytesIO(textwrap.dedent("""\ + Active: 9444728 kB + Active(anon): 6145416 kB + Active(file): 2950064 kB + Buffers: 287952 kB + Cached: 4818144 kB + Inactive(file): 1578132 kB + Inactive(anon): 574764 kB + Inactive(file): 1567648 kB + MemAvailable: 6574984 kB + MemFree: 2057400 kB + MemTotal: 16325648 kB + Shmem: 577588 kB + SReclaimable: 346648 kB + """).encode()) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, create=True, side_effect=open_mock) as m: + ret = psutil.virtual_memory() + assert m.called + self.assertEqual(ret.available, 6574984 * 1024) + + def test_avail_old_missing_fields(self): + # Remove Active(file), Inactive(file) and SReclaimable + # from /proc/meminfo and make sure the fallback is used + # (free + cached), + def open_mock(name, *args, **kwargs): + if name == "/proc/meminfo": + return io.BytesIO(textwrap.dedent("""\ + Active: 9444728 kB + Active(anon): 6145416 kB + Buffers: 287952 kB + Cached: 4818144 kB + Inactive(file): 1578132 kB + Inactive(anon): 574764 kB + MemFree: 2057400 kB + MemTotal: 16325648 kB + Shmem: 577588 kB + """).encode()) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, create=True, side_effect=open_mock) as m: + ret = psutil.virtual_memory() + assert m.called + self.assertEqual(ret.available, 2057400 * 1024 + 4818144 * 1024) + + def test_avail_old_missing_zoneinfo(self): + # Remove /proc/zoneinfo file. Make sure fallback is used + # (free + cached). + def open_mock(name, *args, **kwargs): + if name == "/proc/meminfo": + return io.BytesIO(textwrap.dedent("""\ + Active: 9444728 kB + Active(anon): 6145416 kB + Active(file): 2950064 kB + Buffers: 287952 kB + Cached: 4818144 kB + Inactive(file): 1578132 kB + Inactive(anon): 574764 kB + Inactive(file): 1567648 kB + MemFree: 2057400 kB + MemTotal: 16325648 kB + Shmem: 577588 kB + SReclaimable: 346648 kB + """).encode()) + elif name == "/proc/zoneinfo": + raise IOError(errno.ENOENT, 'no such file or directory') + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, create=True, side_effect=open_mock) as m: + ret = psutil.virtual_memory() + assert m.called + self.assertEqual(ret.available, 2057400 * 1024 + 4818144 * 1024) + + +# ===================================================================== +# --- system swap memory +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemSwapMemory(unittest.TestCase): + + def test_total(self): + free_value = free_swap().total + psutil_value = psutil.swap_memory().total + return self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_used(self): + free_value = free_swap().used + psutil_value = psutil.swap_memory().used + return self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_free(self): + free_value = free_swap().free + psutil_value = psutil.swap_memory().free + return self.assertAlmostEqual( + free_value, psutil_value, delta=MEMORY_TOLERANCE) + + def test_warnings_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = psutil.swap_memory() + assert m.called + self.assertEqual(len(ws), 1) + w = ws[0] + self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) + self.assertIn( + "'sin' and 'sout' swap memory stats couldn't " + "be determined", str(w.message)) + self.assertEqual(ret.sin, 0) + self.assertEqual(ret.sout, 0) + + def test_no_vmstat_mocked(self): + # see https://github.com/giampaolo/psutil/issues/722 + with mock.patch('psutil._pslinux.open', create=True, + side_effect=IOError) as m: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = psutil.swap_memory() + assert m.called + self.assertEqual(len(ws), 1) + w = ws[0] + self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) + self.assertIn( + "'sin' and 'sout' swap memory stats couldn't " + "be determined and were set to 0", + str(w.message)) + self.assertEqual(ret.sin, 0) + self.assertEqual(ret.sout, 0) + + +# ===================================================================== +# --- system CPU +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemCPU(unittest.TestCase): + + @unittest.skipIf(TRAVIS, "unknown failure on travis") + def test_cpu_times(self): + fields = psutil.cpu_times()._fields + kernel_ver = re.findall('\d+\.\d+\.\d+', os.uname()[2])[0] + kernel_ver_info = tuple(map(int, kernel_ver.split('.'))) + if kernel_ver_info >= (2, 6, 11): + self.assertIn('steal', fields) + else: + self.assertNotIn('steal', fields) + if kernel_ver_info >= (2, 6, 24): + self.assertIn('guest', fields) + else: + self.assertNotIn('guest', fields) + if kernel_ver_info >= (3, 2, 0): + self.assertIn('guest_nice', fields) + else: + self.assertNotIn('guest_nice', fields) + + @unittest.skipUnless(os.path.exists("/sys/devices/system/cpu/online"), + "/sys/devices/system/cpu/online does not exist") + def test_cpu_count_logical_w_sysdev_cpu_online(self): + with open("/sys/devices/system/cpu/online") as f: + value = f.read().strip() + if "-" in str(value): + value = int(value.split('-')[1]) + 1 + self.assertEqual(psutil.cpu_count(), value) + + @unittest.skipUnless(os.path.exists("/sys/devices/system/cpu"), + "/sys/devices/system/cpu does not exist") + def test_cpu_count_logical_w_sysdev_cpu_num(self): + ls = os.listdir("/sys/devices/system/cpu") + count = len([x for x in ls if re.search("cpu\d+$", x) is not None]) + self.assertEqual(psutil.cpu_count(), count) + + @unittest.skipUnless(which("nproc"), "nproc utility not available") + def test_cpu_count_logical_w_nproc(self): + num = int(sh("nproc --all")) + self.assertEqual(psutil.cpu_count(logical=True), num) + + @unittest.skipUnless(which("lscpu"), "lscpu utility not available") + def test_cpu_count_logical_w_lscpu(self): + out = sh("lscpu -p") + num = len([x for x in out.split('\n') if not x.startswith('#')]) + self.assertEqual(psutil.cpu_count(logical=True), num) + + def test_cpu_count_logical_mocked(self): + import psutil._pslinux + original = psutil._pslinux.cpu_count_logical() + # Here we want to mock os.sysconf("SC_NPROCESSORS_ONLN") in + # order to cause the parsing of /proc/cpuinfo and /proc/stat. + with mock.patch( + 'psutil._pslinux.os.sysconf', side_effect=ValueError) as m: + self.assertEqual(psutil._pslinux.cpu_count_logical(), original) + assert m.called + + # Let's have open() return emtpy data and make sure None is + # returned ('cause we mimick os.cpu_count()). + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertIsNone(psutil._pslinux.cpu_count_logical()) + self.assertEqual(m.call_count, 2) + # /proc/stat should be the last one + self.assertEqual(m.call_args[0][0], '/proc/stat') + + # Let's push this a bit further and make sure /proc/cpuinfo + # parsing works as expected. + with open('/proc/cpuinfo', 'rb') as f: + cpuinfo_data = f.read() + fake_file = io.BytesIO(cpuinfo_data) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + self.assertEqual(psutil._pslinux.cpu_count_logical(), original) + + # Finally, let's make /proc/cpuinfo return meaningless data; + # this way we'll fall back on relying on /proc/stat + def open_mock(name, *args, **kwargs): + if name.startswith('/proc/cpuinfo'): + return io.BytesIO(b"") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock, create=True): + self.assertEqual(psutil._pslinux.cpu_count_logical(), original) + + def test_cpu_count_physical_mocked(self): + # Have open() return emtpy data and make sure None is returned + # ('cause we want to mimick os.cpu_count()) + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertIsNone(psutil._pslinux.cpu_count_physical()) + assert m.called + + +# ===================================================================== +# --- system CPU stats +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemCPUStats(unittest.TestCase): + + @unittest.skipIf(TRAVIS, "fails on Travis") + def test_ctx_switches(self): + vmstat_value = vmstat("context switches") + psutil_value = psutil.cpu_stats().ctx_switches + self.assertAlmostEqual(vmstat_value, psutil_value, delta=500) + + @unittest.skipIf(TRAVIS, "fails on Travis") + def test_interrupts(self): + vmstat_value = vmstat("interrupts") + psutil_value = psutil.cpu_stats().interrupts + self.assertAlmostEqual(vmstat_value, psutil_value, delta=500) + + +# ===================================================================== +# --- system network +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemNetwork(unittest.TestCase): + + def test_net_if_addrs_ips(self): + for name, addrs in psutil.net_if_addrs().items(): + for addr in addrs: + if addr.family == psutil.AF_LINK: + self.assertEqual(addr.address, get_mac_address(name)) + elif addr.family == socket.AF_INET: + self.assertEqual(addr.address, get_ipv4_address(name)) + # TODO: test for AF_INET6 family + + def test_net_if_stats(self): + for name, stats in psutil.net_if_stats().items(): + try: + out = sh("ifconfig %s" % name) + except RuntimeError: + pass + else: + # Not always reliable. + # self.assertEqual(stats.isup, 'RUNNING' in out, msg=out) + self.assertEqual(stats.mtu, + int(re.findall('MTU:(\d+)', out)[0])) + + @retry_before_failing() + def test_net_io_counters(self): + def ifconfig(nic): + ret = {} + out = sh("ifconfig %s" % name) + ret['packets_recv'] = int(re.findall('RX packets:(\d+)', out)[0]) + ret['packets_sent'] = int(re.findall('TX packets:(\d+)', out)[0]) + ret['errin'] = int(re.findall('errors:(\d+)', out)[0]) + ret['errout'] = int(re.findall('errors:(\d+)', out)[1]) + ret['dropin'] = int(re.findall('dropped:(\d+)', out)[0]) + ret['dropout'] = int(re.findall('dropped:(\d+)', out)[1]) + ret['bytes_recv'] = int(re.findall('RX bytes:(\d+)', out)[0]) + ret['bytes_sent'] = int(re.findall('TX bytes:(\d+)', out)[0]) + return ret + + for name, stats in psutil.net_io_counters(pernic=True).items(): + try: + ifconfig_ret = ifconfig(name) + except RuntimeError: + continue + self.assertAlmostEqual( + stats.bytes_recv, ifconfig_ret['bytes_recv'], delta=1024 * 5) + self.assertAlmostEqual( + stats.bytes_sent, ifconfig_ret['bytes_sent'], delta=1024 * 5) + self.assertAlmostEqual( + stats.packets_recv, ifconfig_ret['packets_recv'], delta=1024) + self.assertAlmostEqual( + stats.packets_sent, ifconfig_ret['packets_sent'], delta=1024) + self.assertAlmostEqual( + stats.errin, ifconfig_ret['errin'], delta=10) + self.assertAlmostEqual( + stats.errout, ifconfig_ret['errout'], delta=10) + self.assertAlmostEqual( + stats.dropin, ifconfig_ret['dropin'], delta=10) + self.assertAlmostEqual( + stats.dropout, ifconfig_ret['dropout'], delta=10) + + @unittest.skipUnless(which('ip'), "'ip' utility not available") + @unittest.skipIf(TRAVIS, "skipped on Travis") + def test_net_if_names(self): + out = sh("ip addr").strip() + nics = [x for x in psutil.net_if_addrs().keys() if ':' not in x] + found = 0 + for line in out.split('\n'): + line = line.strip() + if re.search("^\d+:", line): + found += 1 + name = line.split(':')[1].strip() + self.assertIn(name, nics) + self.assertEqual(len(nics), found, msg="%s\n---\n%s" % ( + pprint.pformat(nics), out)) + + @mock.patch('psutil._pslinux.socket.inet_ntop', side_effect=ValueError) + @mock.patch('psutil._pslinux.supports_ipv6', return_value=False) + def test_net_connections_ipv6_unsupported(self, supports_ipv6, inet_ntop): + # see: https://github.com/giampaolo/psutil/issues/623 + try: + s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + self.addCleanup(s.close) + s.bind(("::1", 0)) + except socket.error: + pass + psutil.net_connections(kind='inet6') + + def test_net_connections_mocked(self): + def open_mock(name, *args, **kwargs): + if name == '/proc/net/unix': + return io.StringIO(textwrap.dedent(u"""\ + 0: 00000003 000 000 0001 03 462170 @/tmp/dbus-Qw2hMPIU3n + 0: 00000003 000 000 0001 03 35010 @/tmp/dbus-tB2X8h69BQ + 0: 00000003 000 000 0001 03 34424 @/tmp/dbus-cHy80Y8O + 000000000000000000000000000000000000000000000000000000 + """)) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + psutil.net_connections(kind='unix') + assert m.called + + +# ===================================================================== +# --- system disk +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestSystemDisks(unittest.TestCase): + + @unittest.skipUnless( + hasattr(os, 'statvfs'), "os.statvfs() function not available") + @skip_on_not_implemented() + def test_disk_partitions_and_usage(self): + # test psutil.disk_usage() and psutil.disk_partitions() + # against "df -a" + def df(path): + out = sh('df -P -B 1 "%s"' % path).strip() + lines = out.split('\n') + lines.pop(0) + line = lines.pop(0) + dev, total, used, free = line.split()[:4] + if dev == 'none': + dev = '' + total, used, free = int(total), int(used), int(free) + return dev, total, used, free + + for part in psutil.disk_partitions(all=False): + usage = psutil.disk_usage(part.mountpoint) + dev, total, used, free = df(part.mountpoint) + self.assertEqual(usage.total, total) + # 10 MB tollerance + if abs(usage.free - free) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % (usage.free, free)) + if abs(usage.used - used) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % (usage.used, used)) + + def test_disk_partitions_mocked(self): + # Test that ZFS partitions are returned. + with open("/proc/filesystems", "r") as f: + data = f.read() + if 'zfs' in data: + for part in psutil.disk_partitions(): + if part.fstype == 'zfs': + break + else: + self.fail("couldn't find any ZFS partition") + else: + # No ZFS partitions on this system. Let's fake one. + fake_file = io.StringIO(u("nodev\tzfs\n")) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m1: + with mock.patch( + 'psutil._pslinux.cext.disk_partitions', + return_value=[('/dev/sdb3', '/', 'zfs', 'rw')]) as m2: + ret = psutil.disk_partitions() + assert m1.called + assert m2.called + assert ret + self.assertEqual(ret[0].fstype, 'zfs') + + def test_disk_io_counters_kernel_2_4_mocked(self): + # Tests /proc/diskstats parsing format for 2.4 kernels, see: + # https://github.com/giampaolo/psutil/issues/767 + def open_mock(name, *args, **kwargs): + if name == '/proc/partitions': + return io.StringIO(textwrap.dedent(u"""\ + major minor #blocks name + + 8 0 488386584 hda + """)) + elif name == '/proc/diskstats': + return io.StringIO( + u(" 3 0 1 hda 2 3 4 5 6 7 8 9 10 11 12")) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + ret = psutil.disk_io_counters() + assert m.called + self.assertEqual(ret.read_count, 1) + self.assertEqual(ret.read_merged_count, 2) + self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE) + self.assertEqual(ret.read_time, 4) + self.assertEqual(ret.write_count, 5) + self.assertEqual(ret.write_merged_count, 6) + self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE) + self.assertEqual(ret.write_time, 8) + self.assertEqual(ret.busy_time, 10) + + def test_disk_io_counters_kernel_2_6_full_mocked(self): + # Tests /proc/diskstats parsing format for 2.6 kernels, + # lines reporting all metrics: + # https://github.com/giampaolo/psutil/issues/767 + def open_mock(name, *args, **kwargs): + if name == '/proc/partitions': + return io.StringIO(textwrap.dedent(u"""\ + major minor #blocks name + + 8 0 488386584 hda + """)) + elif name == '/proc/diskstats': + return io.StringIO( + u(" 3 0 hda 1 2 3 4 5 6 7 8 9 10 11")) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + ret = psutil.disk_io_counters() + assert m.called + self.assertEqual(ret.read_count, 1) + self.assertEqual(ret.read_merged_count, 2) + self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE) + self.assertEqual(ret.read_time, 4) + self.assertEqual(ret.write_count, 5) + self.assertEqual(ret.write_merged_count, 6) + self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE) + self.assertEqual(ret.write_time, 8) + self.assertEqual(ret.busy_time, 10) + + def test_disk_io_counters_kernel_2_6_limited_mocked(self): + # Tests /proc/diskstats parsing format for 2.6 kernels, + # where one line of /proc/partitions return a limited + # amount of metrics when it bumps into a partition + # (instead of a disk). See: + # https://github.com/giampaolo/psutil/issues/767 + def open_mock(name, *args, **kwargs): + if name == '/proc/partitions': + return io.StringIO(textwrap.dedent(u"""\ + major minor #blocks name + + 8 0 488386584 hda + """)) + elif name == '/proc/diskstats': + return io.StringIO( + u(" 3 1 hda 1 2 3 4")) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + ret = psutil.disk_io_counters() + assert m.called + self.assertEqual(ret.read_count, 1) + self.assertEqual(ret.read_bytes, 2 * SECTOR_SIZE) + self.assertEqual(ret.write_count, 3) + self.assertEqual(ret.write_bytes, 4 * SECTOR_SIZE) + + self.assertEqual(ret.read_merged_count, 0) + self.assertEqual(ret.read_time, 0) + self.assertEqual(ret.write_merged_count, 0) + self.assertEqual(ret.write_time, 0) + self.assertEqual(ret.busy_time, 0) + + +# ===================================================================== +# --- misc +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestMisc(unittest.TestCase): + + def test_boot_time(self): + vmstat_value = vmstat('boot time') + psutil_value = psutil.boot_time() + self.assertEqual(int(vmstat_value), int(psutil_value)) + + @mock.patch('psutil.traceback.print_exc') + def test_no_procfs_on_import(self, tb): + my_procfs = tempfile.mkdtemp() + + with open(os.path.join(my_procfs, 'stat'), 'w') as f: + f.write('cpu 0 0 0 0 0 0 0 0 0 0\n') + f.write('cpu0 0 0 0 0 0 0 0 0 0 0\n') + f.write('cpu1 0 0 0 0 0 0 0 0 0 0\n') + + try: + orig_open = open + + def open_mock(name, *args, **kwargs): + if name.startswith('/proc'): + raise IOError(errno.ENOENT, 'rejecting access for test') + return orig_open(name, *args, **kwargs) + + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock): + importlib.reload(psutil) + assert tb.called + + self.assertRaises(IOError, psutil.cpu_times) + self.assertRaises(IOError, psutil.cpu_times, percpu=True) + self.assertRaises(IOError, psutil.cpu_percent) + self.assertRaises(IOError, psutil.cpu_percent, percpu=True) + self.assertRaises(IOError, psutil.cpu_times_percent) + self.assertRaises( + IOError, psutil.cpu_times_percent, percpu=True) + + psutil.PROCFS_PATH = my_procfs + + self.assertEqual(psutil.cpu_percent(), 0) + self.assertEqual(sum(psutil.cpu_times_percent()), 0) + + # since we don't know the number of CPUs at import time, + # we awkwardly say there are none until the second call + per_cpu_percent = psutil.cpu_percent(percpu=True) + self.assertEqual(sum(per_cpu_percent), 0) + + # ditto awkward length + per_cpu_times_percent = psutil.cpu_times_percent(percpu=True) + self.assertEqual(sum(map(sum, per_cpu_times_percent)), 0) + + # much user, very busy + with open(os.path.join(my_procfs, 'stat'), 'w') as f: + f.write('cpu 1 0 0 0 0 0 0 0 0 0\n') + f.write('cpu0 1 0 0 0 0 0 0 0 0 0\n') + f.write('cpu1 1 0 0 0 0 0 0 0 0 0\n') + + self.assertNotEqual(psutil.cpu_percent(), 0) + self.assertNotEqual( + sum(psutil.cpu_percent(percpu=True)), 0) + self.assertNotEqual(sum(psutil.cpu_times_percent()), 0) + self.assertNotEqual( + sum(map(sum, psutil.cpu_times_percent(percpu=True))), 0) + finally: + shutil.rmtree(my_procfs) + importlib.reload(psutil) + + self.assertEqual(psutil.PROCFS_PATH, '/proc') + + @unittest.skipUnless( + get_kernel_version() >= (2, 6, 36), + "prlimit() not available on this Linux kernel version") + def test_prlimit_availability(self): + # prlimit() should be available starting from kernel 2.6.36 + p = psutil.Process(os.getpid()) + p.rlimit(psutil.RLIMIT_NOFILE) + # if prlimit() is supported *at least* these constants should + # be available + self.assertTrue(hasattr(psutil, "RLIM_INFINITY")) + self.assertTrue(hasattr(psutil, "RLIMIT_AS")) + self.assertTrue(hasattr(psutil, "RLIMIT_CORE")) + self.assertTrue(hasattr(psutil, "RLIMIT_CPU")) + self.assertTrue(hasattr(psutil, "RLIMIT_DATA")) + self.assertTrue(hasattr(psutil, "RLIMIT_FSIZE")) + self.assertTrue(hasattr(psutil, "RLIMIT_LOCKS")) + self.assertTrue(hasattr(psutil, "RLIMIT_MEMLOCK")) + self.assertTrue(hasattr(psutil, "RLIMIT_NOFILE")) + self.assertTrue(hasattr(psutil, "RLIMIT_NPROC")) + self.assertTrue(hasattr(psutil, "RLIMIT_RSS")) + self.assertTrue(hasattr(psutil, "RLIMIT_STACK")) + + @unittest.skipUnless( + get_kernel_version() >= (3, 0), + "prlimit constants not available on this Linux kernel version") + def test_resource_consts_kernel_v(self): + # more recent constants + self.assertTrue(hasattr(psutil, "RLIMIT_MSGQUEUE")) + self.assertTrue(hasattr(psutil, "RLIMIT_NICE")) + self.assertTrue(hasattr(psutil, "RLIMIT_RTPRIO")) + self.assertTrue(hasattr(psutil, "RLIMIT_RTTIME")) + self.assertTrue(hasattr(psutil, "RLIMIT_SIGPENDING")) + + def test_boot_time_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + RuntimeError, + psutil._pslinux.boot_time) + assert m.called + + def test_users_mocked(self): + # Make sure ':0' and ':0.0' (returned by C ext) are converted + # to 'localhost'. + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', ':0', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'localhost') + assert m.called + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', ':0.0', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'localhost') + assert m.called + # ...otherwise it should be returned as-is + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', 'foo', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'foo') + assert m.called + + def test_procfs_path(self): + tdir = tempfile.mkdtemp() + try: + psutil.PROCFS_PATH = tdir + self.assertRaises(IOError, psutil.virtual_memory) + self.assertRaises(IOError, psutil.cpu_times) + self.assertRaises(IOError, psutil.cpu_times, percpu=True) + self.assertRaises(IOError, psutil.boot_time) + # self.assertRaises(IOError, psutil.pids) + self.assertRaises(IOError, psutil.net_connections) + self.assertRaises(IOError, psutil.net_io_counters) + self.assertRaises(IOError, psutil.net_if_stats) + self.assertRaises(IOError, psutil.disk_io_counters) + self.assertRaises(IOError, psutil.disk_partitions) + self.assertRaises(psutil.NoSuchProcess, psutil.Process) + finally: + psutil.PROCFS_PATH = "/proc" + os.rmdir(tdir) + + def test_sector_size_mock(self): + # Test SECTOR_SIZE fallback in case 'hw_sector_size' file + # does not exist. + def open_mock(name, *args, **kwargs): + if PY3 and isinstance(name, bytes): + name = name.decode() + if "hw_sector_size" in name: + flag.append(None) + raise IOError(errno.ENOENT, '') + else: + return orig_open(name, *args, **kwargs) + + flag = [] + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock): + psutil.disk_io_counters() + self.assertTrue(flag) + + def test_issue_687(self): + # In case of thread ID: + # - pid_exists() is supposed to return False + # - Process(tid) is supposed to work + # - pids() should not return the TID + # See: https://github.com/giampaolo/psutil/issues/687 + t = ThreadTask() + t.start() + try: + p = psutil.Process() + tid = p.threads()[1].id + assert not psutil.pid_exists(tid), tid + pt = psutil.Process(tid) + pt.as_dict() + self.assertNotIn(tid, psutil.pids()) + finally: + t.stop() + + +# ===================================================================== +# --- sensors +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +@unittest.skipUnless(hasattr(psutil, "sensors_battery") and + psutil.sensors_battery() is not None, + "no battery") +class TestSensorsBattery(unittest.TestCase): + + @unittest.skipUnless(which("acpi"), "acpi utility not available") + def test_percent(self): + out = sh("acpi -b") + acpi_value = int(out.split(",")[1].strip().replace('%', '')) + psutil_value = psutil.sensors_battery().percent + self.assertAlmostEqual(acpi_value, psutil_value, delta=1) + + @unittest.skipUnless(which("acpi"), "acpi utility not available") + def test_power_plugged(self): + out = sh("acpi -b") + if 'unknown' in out.lower(): + return unittest.skip("acpi output not reliable") + plugged = "Charging" in out.split('\n')[0] + self.assertEqual(psutil.sensors_battery().power_plugged, plugged) + + def test_emulate_power_plugged(self): + # Pretend the AC power cable is connected. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/AC0/online"): + return io.BytesIO(b"1") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertEqual(psutil.sensors_battery().power_plugged, True) + self.assertEqual( + psutil.sensors_battery().secsleft, psutil.POWER_TIME_UNLIMITED) + assert m.called + + def test_emulate_power_not_plugged(self): + # Pretend the AC power cable is not connected. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/AC0/online"): + return io.BytesIO(b"0") + elif name.startswith("/sys/class/power_supply/BAT0/status"): + return io.BytesIO(b"discharging") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertEqual(psutil.sensors_battery().power_plugged, False) + assert m.called + + def test_emulate_power_undetermined(self): + # Pretend we can't know whether the AC power cable not + # connected (assert fallback to False). + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/AC0/online") or \ + name.startswith("/sys/class/power_supply/AC/online"): + raise IOError(errno.ENOENT, "") + elif name.startswith("/sys/class/power_supply/BAT0/status"): + return io.BytesIO(b"???") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertIsNone(psutil.sensors_battery().power_plugged) + assert m.called + + def test_emulate_no_base_files(self): + # Emulate a case where base metrics files are not present, + # in which case we're supposed to get None. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/BAT0/energy_now") or \ + name.startswith("/sys/class/power_supply/BAT0/charge_now"): + raise IOError(errno.ENOENT, "") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertIsNone(psutil.sensors_battery()) + assert m.called + + def test_emulate_energy_full_0(self): + # Emulate a case where energy_full files returns 0. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/BAT0/energy_full"): + return io.BytesIO(b"0") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertEqual(psutil.sensors_battery().percent, 0) + assert m.called + + def test_emulate_energy_full_not_avail(self): + # Emulate a case where energy_full file does not exist. + # Expected fallback on /capacity. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/BAT0/energy_full"): + raise IOError(errno.ENOENT, "") + elif name.startswith("/sys/class/power_supply/BAT0/capacity"): + return io.BytesIO(b"88") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertEqual(psutil.sensors_battery().percent, 88) + assert m.called + + def test_emulate_no_ac0_online(self): + # Emulate a case where /AC0/online file does not exist. + def path_exists_mock(name): + if name.startswith("/sys/class/power_supply/AC0/online"): + return False + else: + return orig_path_exists(name) + + orig_path_exists = os.path.exists + with mock.patch("psutil._pslinux.os.path.exists", + side_effect=path_exists_mock) as m: + psutil.sensors_battery() + assert m.called + + def test_emulate_no_power(self): + # Emulate a case where /AC0/online file nor /BAT0/status exist. + def open_mock(name, *args, **kwargs): + if name.startswith("/sys/class/power_supply/AC/online") or \ + name.startswith("/sys/class/power_supply/AC0/online") or \ + name.startswith("/sys/class/power_supply/BAT0/status"): + raise IOError(errno.ENOENT, "") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + self.assertIsNone(psutil.sensors_battery().power_plugged) + assert m.called + + +# ===================================================================== +# --- test process +# ===================================================================== + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestProcess(unittest.TestCase): + + def setUp(self): + safe_rmpath(TESTFN) + + tearDown = setUp + + def test_memory_full_info(self): + src = textwrap.dedent(""" + import time + with open("%s", "w") as f: + time.sleep(10) + """ % TESTFN) + sproc = pyrun(src) + self.addCleanup(reap_children) + call_until(lambda: os.listdir('.'), "'%s' not in ret" % TESTFN) + p = psutil.Process(sproc.pid) + time.sleep(.1) + mem = p.memory_full_info() + maps = p.memory_maps(grouped=False) + self.assertAlmostEqual( + mem.uss, sum([x.private_dirty + x.private_clean for x in maps]), + delta=4096) + self.assertAlmostEqual( + mem.pss, sum([x.pss for x in maps]), delta=4096) + self.assertAlmostEqual( + mem.swap, sum([x.swap for x in maps]), delta=4096) + + # On PYPY file descriptors are not closed fast enough. + @unittest.skipIf(PYPY, "unreliable on PYPY") + def test_open_files_mode(self): + def get_test_file(): + p = psutil.Process() + giveup_at = time.time() + 2 + while True: + for file in p.open_files(): + if file.path == os.path.abspath(TESTFN): + return file + elif time.time() > giveup_at: + break + raise RuntimeError("timeout looking for test file") + + # + with open(TESTFN, "w"): + self.assertEqual(get_test_file().mode, "w") + with open(TESTFN, "r"): + self.assertEqual(get_test_file().mode, "r") + with open(TESTFN, "a"): + self.assertEqual(get_test_file().mode, "a") + # + with open(TESTFN, "r+"): + self.assertEqual(get_test_file().mode, "r+") + with open(TESTFN, "w+"): + self.assertEqual(get_test_file().mode, "r+") + with open(TESTFN, "a+"): + self.assertEqual(get_test_file().mode, "a+") + # note: "x" bit is not supported + if PY3: + safe_rmpath(TESTFN) + with open(TESTFN, "x"): + self.assertEqual(get_test_file().mode, "w") + safe_rmpath(TESTFN) + with open(TESTFN, "x+"): + self.assertEqual(get_test_file().mode, "r+") + + def test_open_files_file_gone(self): + # simulates a file which gets deleted during open_files() + # execution + p = psutil.Process() + files = p.open_files() + with tempfile.NamedTemporaryFile(): + # give the kernel some time to see the new file + call_until(p.open_files, "len(ret) != %i" % len(files)) + with mock.patch('psutil._pslinux.os.readlink', + side_effect=OSError(errno.ENOENT, "")) as m: + files = p.open_files() + assert not files + assert m.called + # also simulate the case where os.readlink() returns EINVAL + # in which case psutil is supposed to 'continue' + with mock.patch('psutil._pslinux.os.readlink', + side_effect=OSError(errno.EINVAL, "")) as m: + self.assertEqual(p.open_files(), []) + assert m.called + + # --- mocked tests + + def test_terminal_mocked(self): + with mock.patch('psutil._pslinux._psposix.get_terminal_map', + return_value={}) as m: + self.assertIsNone(psutil._pslinux.Process(os.getpid()).terminal()) + assert m.called + + # TODO: re-enable this test. + # def test_num_ctx_switches_mocked(self): + # with mock.patch('psutil._pslinux.open', create=True) as m: + # self.assertRaises( + # NotImplementedError, + # psutil._pslinux.Process(os.getpid()).num_ctx_switches) + # assert m.called + + def test_cmdline_mocked(self): + # see: https://github.com/giampaolo/psutil/issues/639 + p = psutil.Process() + fake_file = io.StringIO(u('foo\x00bar\x00')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + p.cmdline() == ['foo', 'bar'] + assert m.called + fake_file = io.StringIO(u('foo\x00bar\x00\x00')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + p.cmdline() == ['foo', 'bar', ''] + assert m.called + + def test_readlink_path_deleted_mocked(self): + with mock.patch('psutil._pslinux.os.readlink', + return_value='/home/foo (deleted)'): + self.assertEqual(psutil.Process().exe(), "/home/foo") + self.assertEqual(psutil.Process().cwd(), "/home/foo") + + def test_threads_mocked(self): + # Test the case where os.listdir() returns a file (thread) + # which no longer exists by the time we open() it (race + # condition). threads() is supposed to ignore that instead + # of raising NSP. + def open_mock(name, *args, **kwargs): + if name.startswith('/proc/%s/task' % os.getpid()): + raise IOError(errno.ENOENT, "") + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, side_effect=open_mock) as m: + ret = psutil.Process().threads() + assert m.called + self.assertEqual(ret, []) + + # ...but if it bumps into something != ENOENT we want an + # exception. + def open_mock(name, *args, **kwargs): + if name.startswith('/proc/%s/task' % os.getpid()): + raise IOError(errno.EPERM, "") + else: + return orig_open(name, *args, **kwargs) + + with mock.patch(patch_point, side_effect=open_mock): + self.assertRaises(psutil.AccessDenied, psutil.Process().threads) + + # not sure why (doesn't fail locally) + # https://travis-ci.org/giampaolo/psutil/jobs/108629915 + @unittest.skipIf(TRAVIS, "unreliable on TRAVIS") + def test_exe_mocked(self): + with mock.patch('psutil._pslinux.os.readlink', + side_effect=OSError(errno.ENOENT, "")) as m: + # No such file error; might be raised also if /proc/pid/exe + # path actually exists for system processes with low pids + # (about 0-20). In this case psutil is supposed to return + # an empty string. + ret = psutil.Process().exe() + assert m.called + self.assertEqual(ret, "") + + # ...but if /proc/pid no longer exist we're supposed to treat + # it as an alias for zombie process + with mock.patch('psutil._pslinux.os.path.lexists', + return_value=False): + self.assertRaises(psutil.ZombieProcess, psutil.Process().exe) + + +@unittest.skipUnless(LINUX, "LINUX only") +class TestProcessAgainstStatus(unittest.TestCase): + """/proc/pid/stat and /proc/pid/status have many values in common. + Whenever possible, psutil uses /proc/pid/stat (it's faster). + For all those cases we check that the value found in + /proc/pid/stat (by psutil) matches the one found in + /proc/pid/status. + """ + + @classmethod + def setUpClass(cls): + cls.proc = psutil.Process() + + def read_status_file(self, linestart): + with psutil._psplatform.open_text( + '/proc/%s/status' % self.proc.pid) as f: + for line in f: + line = line.strip() + if line.startswith(linestart): + value = line.partition('\t')[2] + try: + return int(value) + except ValueError: + return value + else: + raise ValueError("can't find %r" % linestart) + + def test_name(self): + value = self.read_status_file("Name:") + self.assertEqual(self.proc.name(), value) + + def test_status(self): + value = self.read_status_file("State:") + value = value[value.find('(') + 1:value.rfind(')')] + value = value.replace(' ', '-') + self.assertEqual(self.proc.status(), value) + + def test_ppid(self): + value = self.read_status_file("PPid:") + self.assertEqual(self.proc.ppid(), value) + + def test_num_threads(self): + value = self.read_status_file("Threads:") + self.assertEqual(self.proc.num_threads(), value) + + def test_uids(self): + value = self.read_status_file("Uid:") + value = tuple(map(int, value.split()[1:4])) + self.assertEqual(self.proc.uids(), value) + + def test_gids(self): + value = self.read_status_file("Gid:") + value = tuple(map(int, value.split()[1:4])) + self.assertEqual(self.proc.gids(), value) + + @retry_before_failing() + def test_num_ctx_switches(self): + value = self.read_status_file("voluntary_ctxt_switches:") + self.assertEqual(self.proc.num_ctx_switches().voluntary, value) + value = self.read_status_file("nonvoluntary_ctxt_switches:") + self.assertEqual(self.proc.num_ctx_switches().involuntary, value) + + def test_cpu_affinity(self): + value = self.read_status_file("Cpus_allowed_list:") + if '-' in str(value): + min_, max_ = map(int, value.split('-')) + self.assertEqual( + self.proc.cpu_affinity(), list(range(min_, max_ + 1))) + + def test_cpu_affinity_eligible_cpus(self): + value = self.read_status_file("Cpus_allowed_list:") + with mock.patch("psutil._pslinux.per_cpu_times") as m: + self.proc._proc._get_eligible_cpus() + if '-' in str(value): + assert not m.called + else: + assert m.called + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_memory_leaks.py b/pipenv/vendor/psutil/tests/test_memory_leaks.py new file mode 100755 index 00000000..a55008e5 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_memory_leaks.py @@ -0,0 +1,611 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Tests for detecting function memory leaks (typically the ones +implemented in C). It does so by calling a function many times and +checking whether process memory usage keeps increasing between +calls or over time. +Note that this may produce false positives (especially on Windows +for some reason). +""" + +import errno +import functools +import gc +import os +import socket +import threading +import time + +import psutil +import psutil._common +from psutil import FREEBSD +from psutil import LINUX +from psutil import OPENBSD +from psutil import OSX +from psutil import POSIX +from psutil import SUNOS +from psutil import WINDOWS +from psutil._common import supports_ipv6 +from psutil._compat import xrange +from psutil.tests import get_test_subprocess +from psutil.tests import reap_children +from psutil.tests import RLIMIT_SUPPORT +from psutil.tests import run_test_module_by_name +from psutil.tests import safe_rmpath +from psutil.tests import TESTFN +from psutil.tests import TRAVIS +from psutil.tests import unittest + + +LOOPS = 1000 +MEMORY_TOLERANCE = 4096 +RETRY_FOR = 3 + +SKIP_PYTHON_IMPL = True if TRAVIS else False +cext = psutil._psplatform.cext +thisproc = psutil.Process() + + +# =================================================================== +# utils +# =================================================================== + + +def skip_if_linux(): + return unittest.skipIf(LINUX and SKIP_PYTHON_IMPL, + "worthless on LINUX (pure python)") + + +def bytes2human(n): + """ + http://code.activestate.com/recipes/578019 + >>> bytes2human(10000) + '9.8K' + >>> bytes2human(100001221) + '95.4M' + """ + symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') + prefix = {} + for i, s in enumerate(symbols): + prefix[s] = 1 << (i + 1) * 10 + for s in reversed(symbols): + if n >= prefix[s]: + value = float(n) / prefix[s] + return '%.2f%s' % (value, s) + return "%sB" % n + + +class TestMemLeak(unittest.TestCase): + """Base framework class which calls a function many times and + produces a failure if process memory usage keeps increasing + between calls or over time. + """ + tolerance = MEMORY_TOLERANCE + loops = LOOPS + retry_for = RETRY_FOR + + def setUp(self): + gc.collect() + + def execute(self, fun, *args, **kwargs): + """Test a callable.""" + def call_many_times(): + for x in xrange(loops): + self._call(fun, *args, **kwargs) + del x + gc.collect() + + tolerance = kwargs.pop('tolerance_', None) or self.tolerance + loops = kwargs.pop('loops_', None) or self.loops + retry_for = kwargs.pop('retry_for_', None) or self.retry_for + + self._call(fun, *args, **kwargs) + self.assertEqual(gc.garbage, []) + self.assertEqual(threading.active_count(), 1) + + # Get 2 distinct memory samples, before and after having + # called fun repeadetly. + # step 1 + call_many_times() + mem1 = self._get_mem() + # step 2 + call_many_times() + mem2 = self._get_mem() + + diff1 = mem2 - mem1 + if diff1 > tolerance: + # This doesn't necessarily mean we have a leak yet. + # At this point we assume that after having called the + # function so many times the memory usage is stabilized + # and if there are no leaks it should not increase + # anymore. + # Let's keep calling fun for 3 more seconds and fail if + # we notice any difference. + ncalls = 0 + stop_at = time.time() + retry_for + while time.time() <= stop_at: + self._call(fun, *args, **kwargs) + ncalls += 1 + + del stop_at + gc.collect() + mem3 = self._get_mem() + diff2 = mem3 - mem2 + + if mem3 > mem2: + # failure + self.fail("+%s after %s calls, +%s after another %s calls" % ( + bytes2human(diff1), + loops, + bytes2human(diff2), + ncalls + )) + + def execute_w_exc(self, exc, fun, *args, **kwargs): + """Convenience function which tests a callable raising + an exception. + """ + def call(): + self.assertRaises(exc, fun, *args, **kwargs) + + self.execute(call) + + @staticmethod + def _get_mem(): + # By using USS memory it seems it's less likely to bump + # into false positives. + if LINUX or WINDOWS or OSX: + return thisproc.memory_full_info().uss + else: + return thisproc.memory_info().rss + + @staticmethod + def _call(fun, *args, **kwargs): + fun(*args, **kwargs) + + +# =================================================================== +# Process class +# =================================================================== + + +class TestProcessObjectLeaks(TestMemLeak): + """Test leaks of Process class methods.""" + + proc = thisproc + + def test_coverage(self): + skip = set(( + "pid", "as_dict", "children", "cpu_affinity", "cpu_percent", + "ionice", "is_running", "kill", "memory_info_ex", "memory_percent", + "nice", "oneshot", "parent", "rlimit", "send_signal", "suspend", + "terminate", "wait")) + for name in dir(psutil.Process): + if name.startswith('_'): + continue + if name in skip: + continue + self.assertTrue(hasattr(self, "test_" + name), msg=name) + + @skip_if_linux() + def test_name(self): + self.execute(self.proc.name) + + @skip_if_linux() + def test_cmdline(self): + self.execute(self.proc.cmdline) + + @skip_if_linux() + def test_exe(self): + self.execute(self.proc.exe) + + @skip_if_linux() + def test_ppid(self): + self.execute(self.proc.ppid) + + @unittest.skipUnless(POSIX, "POSIX only") + @skip_if_linux() + def test_uids(self): + self.execute(self.proc.uids) + + @unittest.skipUnless(POSIX, "POSIX only") + @skip_if_linux() + def test_gids(self): + self.execute(self.proc.gids) + + @skip_if_linux() + def test_status(self): + self.execute(self.proc.status) + + def test_nice_get(self): + self.execute(self.proc.nice) + + def test_nice_set(self): + niceness = thisproc.nice() + self.execute(self.proc.nice, niceness) + + @unittest.skipUnless(hasattr(psutil.Process, 'ionice'), + "platform not supported") + def test_ionice_get(self): + self.execute(self.proc.ionice) + + @unittest.skipUnless(hasattr(psutil.Process, 'ionice'), + "platform not supported") + def test_ionice_set(self): + if WINDOWS: + value = thisproc.ionice() + self.execute(self.proc.ionice, value) + else: + self.execute(self.proc.ionice, psutil.IOPRIO_CLASS_NONE) + fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0) + self.execute_w_exc(OSError, fun) + + @unittest.skipIf(OSX or SUNOS, "platform not supported") + @skip_if_linux() + def test_io_counters(self): + self.execute(self.proc.io_counters) + + @unittest.skipIf(POSIX, "worthless on POSIX") + def test_username(self): + self.execute(self.proc.username) + + @skip_if_linux() + def test_create_time(self): + self.execute(self.proc.create_time) + + @skip_if_linux() + def test_num_threads(self): + self.execute(self.proc.num_threads) + + @unittest.skipUnless(WINDOWS, "WINDOWS only") + def test_num_handles(self): + self.execute(self.proc.num_handles) + + @unittest.skipUnless(POSIX, "POSIX only") + @skip_if_linux() + def test_num_fds(self): + self.execute(self.proc.num_fds) + + @skip_if_linux() + def test_num_ctx_switches(self): + self.execute(self.proc.num_ctx_switches) + + @skip_if_linux() + def test_threads(self): + self.execute(self.proc.threads) + + @skip_if_linux() + def test_cpu_times(self): + self.execute(self.proc.cpu_times) + + @skip_if_linux() + @unittest.skipUnless(hasattr(psutil.Process, "cpu_num"), + "platform not supported") + def test_cpu_num(self): + self.execute(self.proc.cpu_num) + + @skip_if_linux() + def test_memory_info(self): + self.execute(self.proc.memory_info) + + # also available on Linux but it's pure python + @unittest.skipUnless(OSX or WINDOWS, + "platform not supported") + def test_memory_full_info(self): + self.execute(self.proc.memory_full_info) + + @unittest.skipUnless(POSIX, "POSIX only") + @skip_if_linux() + def test_terminal(self): + self.execute(self.proc.terminal) + + @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, + "worthless on POSIX (pure python)") + def test_resume(self): + self.execute(self.proc.resume) + + @skip_if_linux() + def test_cwd(self): + self.execute(self.proc.cwd) + + @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, + "platform not supported") + def test_cpu_affinity_get(self): + self.execute(self.proc.cpu_affinity) + + @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, + "platform not supported") + def test_cpu_affinity_set(self): + affinity = thisproc.cpu_affinity() + self.execute(self.proc.cpu_affinity, affinity) + if not TRAVIS: + self.execute_w_exc(ValueError, self.proc.cpu_affinity, [-1]) + + @skip_if_linux() + def test_open_files(self): + safe_rmpath(TESTFN) # needed after UNIX socket test has run + with open(TESTFN, 'w'): + self.execute(self.proc.open_files) + + # OSX implementation is unbelievably slow + @unittest.skipIf(OSX, "too slow on OSX") + @unittest.skipIf(OPENBSD, "platform not supported") + @skip_if_linux() + def test_memory_maps(self): + self.execute(self.proc.memory_maps) + + @unittest.skipUnless(LINUX, "LINUX only") + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_get(self): + self.execute(self.proc.rlimit, psutil.RLIMIT_NOFILE) + + @unittest.skipUnless(LINUX, "LINUX only") + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_set(self): + limit = thisproc.rlimit(psutil.RLIMIT_NOFILE) + self.execute(self.proc.rlimit, psutil.RLIMIT_NOFILE, limit) + self.execute_w_exc(OSError, self.proc.rlimit, -1) + + @skip_if_linux() + # Windows implementation is based on a single system-wide + # function (tested later). + @unittest.skipIf(WINDOWS, "worthless on WINDOWS") + def test_connections(self): + def create_socket(family, type): + sock = socket.socket(family, type) + sock.bind(('', 0)) + if type == socket.SOCK_STREAM: + sock.listen(1) + return sock + + socks = [] + socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM)) + socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM)) + if supports_ipv6(): + socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM)) + socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM)) + if hasattr(socket, 'AF_UNIX'): + safe_rmpath(TESTFN) + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.bind(TESTFN) + s.listen(1) + socks.append(s) + kind = 'all' + # TODO: UNIX sockets are temporarily implemented by parsing + # 'pfiles' cmd output; we don't want that part of the code to + # be executed. + if SUNOS: + kind = 'inet' + try: + self.execute(self.proc.connections, kind) + finally: + for s in socks: + s.close() + + @unittest.skipUnless(hasattr(psutil.Process, 'environ'), + "platform not supported") + def test_environ(self): + self.execute(self.proc.environ) + + @unittest.skipUnless(WINDOWS, "WINDOWS only") + def test_proc_info(self): + self.execute(cext.proc_info, os.getpid()) + + +class TestTerminatedProcessLeaks(TestProcessObjectLeaks): + """Repeat the tests above looking for leaks occurring when dealing + with terminated processes raising NoSuchProcess exception. + The C functions are still invoked but will follow different code + paths. We'll check those code paths. + """ + + @classmethod + def setUpClass(cls): + super(TestTerminatedProcessLeaks, cls).setUpClass() + p = get_test_subprocess() + cls.proc = psutil.Process(p.pid) + cls.proc.kill() + cls.proc.wait() + + @classmethod + def tearDownClass(cls): + super(TestTerminatedProcessLeaks, cls).tearDownClass() + reap_children() + + def _call(self, fun, *args, **kwargs): + try: + fun(*args, **kwargs) + except psutil.NoSuchProcess: + pass + + if WINDOWS: + + def test_kill(self): + self.execute(self.proc.kill) + + def test_terminate(self): + self.execute(self.proc.terminate) + + def test_suspend(self): + self.execute(self.proc.suspend) + + def test_resume(self): + self.execute(self.proc.resume) + + def test_wait(self): + self.execute(self.proc.wait) + + def test_proc_info(self): + # test dual implementation + def call(): + try: + return cext.proc_info(self.proc.pid) + except OSError as err: + if err.errno != errno.ESRCH: + raise + + self.execute(call) + + +# =================================================================== +# system APIs +# =================================================================== + + +class TestModuleFunctionsLeaks(TestMemLeak): + """Test leaks of psutil module functions.""" + + def test_coverage(self): + skip = set(( + "version_info", "__version__", "process_iter", "wait_procs", + "cpu_percent", "cpu_times_percent", "cpu_count")) + for name in psutil.__all__: + if not name.islower(): + continue + if name in skip: + continue + self.assertTrue(hasattr(self, "test_" + name), msg=name) + + # --- cpu + + @skip_if_linux() + def test_cpu_count_logical(self): + self.execute(psutil.cpu_count, logical=True) + + @skip_if_linux() + def test_cpu_count_physical(self): + self.execute(psutil.cpu_count, logical=False) + + @skip_if_linux() + def test_cpu_times(self): + self.execute(psutil.cpu_times) + + @skip_if_linux() + def test_per_cpu_times(self): + self.execute(psutil.cpu_times, percpu=True) + + def test_cpu_stats(self): + self.execute(psutil.cpu_stats) + + @skip_if_linux() + @unittest.skipUnless(hasattr(psutil, "cpu_freq"), "platform not supported") + def test_cpu_freq(self): + self.execute(psutil.cpu_freq) + + # --- mem + + def test_virtual_memory(self): + self.execute(psutil.virtual_memory) + + # TODO: remove this skip when this gets fixed + @unittest.skipIf(SUNOS, + "worthless on SUNOS (uses a subprocess)") + def test_swap_memory(self): + self.execute(psutil.swap_memory) + + @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, + "worthless on POSIX (pure python)") + def test_pid_exists(self): + self.execute(psutil.pid_exists, os.getpid()) + + # --- disk + + @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, + "worthless on POSIX (pure python)") + def test_disk_usage(self): + self.execute(psutil.disk_usage, '.') + + def test_disk_partitions(self): + self.execute(psutil.disk_partitions) + + @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'), + '/proc/diskstats not available on this Linux version') + @skip_if_linux() + def test_disk_io_counters(self): + self.execute(psutil.disk_io_counters) + + # --- proc + + @skip_if_linux() + def test_pids(self): + self.execute(psutil.pids) + + # --- net + + @skip_if_linux() + def test_net_io_counters(self): + self.execute(psutil.net_io_counters) + + @unittest.skipIf(LINUX, + "worthless on Linux (pure python)") + @unittest.skipIf(OSX and os.getuid() != 0, "need root access") + def test_net_connections(self): + self.execute(psutil.net_connections) + + def test_net_if_addrs(self): + # Note: verified that on Windows this was a false positive. + self.execute(psutil.net_if_addrs, + tolerance_=80 * 1024 if WINDOWS else None) + + @unittest.skipIf(TRAVIS, "EPERM on travis") + def test_net_if_stats(self): + self.execute(psutil.net_if_stats) + + # --- sensors + + @unittest.skipUnless(hasattr(psutil, "sensors_battery"), + "platform not supported") + @skip_if_linux() + def test_sensors_battery(self): + self.execute(psutil.sensors_battery) + + @skip_if_linux() + @unittest.skipUnless(hasattr(psutil, "sensors_temperatures"), + "platform not supported") + def test_sensors_temperatures(self): + self.execute(psutil.sensors_temperatures) + + @unittest.skipUnless(hasattr(psutil, "sensors_fans"), + "platform not supported") + @skip_if_linux() + def test_sensors_fans(self): + self.execute(psutil.sensors_fans) + + # --- others + + @skip_if_linux() + def test_boot_time(self): + self.execute(psutil.boot_time) + + # XXX - on Windows this produces a false positive + @unittest.skipIf(WINDOWS, "XXX produces a false positive on Windows") + def test_users(self): + self.execute(psutil.users) + + if WINDOWS: + + # --- win services + + def test_win_service_iter(self): + self.execute(cext.winservice_enumerate) + + def test_win_service_get_config(self): + name = next(psutil.win_service_iter()).name() + self.execute(cext.winservice_query_config, name) + + def test_win_service_get_status(self): + name = next(psutil.win_service_iter()).name() + self.execute(cext.winservice_query_status, name) + + def test_win_service_get_description(self): + name = next(psutil.win_service_iter()).name() + self.execute(cext.winservice_query_descr, name) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_misc.py b/pipenv/vendor/psutil/tests/test_misc.py new file mode 100755 index 00000000..84215d30 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_misc.py @@ -0,0 +1,649 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Miscellaneous tests. +""" + +import ast +import errno +import imp +import json +import os +import pickle +import psutil +import socket +import stat +import sys + +from psutil import LINUX +from psutil import NETBSD +from psutil import OPENBSD +from psutil import OSX +from psutil import POSIX +from psutil import WINDOWS +from psutil._common import memoize +from psutil._common import memoize_when_activated +from psutil._common import supports_ipv6 +from psutil.tests import APPVEYOR +from psutil.tests import chdir +from psutil.tests import get_test_subprocess +from psutil.tests import importlib +from psutil.tests import mock +from psutil.tests import reap_children +from psutil.tests import retry +from psutil.tests import ROOT_DIR +from psutil.tests import run_test_module_by_name +from psutil.tests import safe_rmpath +from psutil.tests import SCRIPTS_DIR +from psutil.tests import sh +from psutil.tests import TESTFN +from psutil.tests import TOX +from psutil.tests import TRAVIS +from psutil.tests import unittest +from psutil.tests import wait_for_file +from psutil.tests import wait_for_pid + + +class TestMisc(unittest.TestCase): + """Misc / generic tests.""" + + def test_process__repr__(self, func=repr): + p = psutil.Process() + r = func(p) + self.assertIn("psutil.Process", r) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("name=", r) + self.assertIn(p.name(), r) + with mock.patch.object(psutil.Process, "name", + side_effect=psutil.ZombieProcess(os.getpid())): + p = psutil.Process() + r = func(p) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("zombie", r) + self.assertNotIn("name=", r) + with mock.patch.object(psutil.Process, "name", + side_effect=psutil.NoSuchProcess(os.getpid())): + p = psutil.Process() + r = func(p) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("terminated", r) + self.assertNotIn("name=", r) + with mock.patch.object(psutil.Process, "name", + side_effect=psutil.AccessDenied(os.getpid())): + p = psutil.Process() + r = func(p) + self.assertIn("pid=%s" % p.pid, r) + self.assertNotIn("name=", r) + + def test_process__str__(self): + self.test_process__repr__(func=str) + + def test_no_such_process__repr__(self, func=repr): + self.assertEqual( + repr(psutil.NoSuchProcess(321)), + "psutil.NoSuchProcess process no longer exists (pid=321)") + self.assertEqual( + repr(psutil.NoSuchProcess(321, name='foo')), + "psutil.NoSuchProcess process no longer exists (pid=321, " + "name='foo')") + self.assertEqual( + repr(psutil.NoSuchProcess(321, msg='foo')), + "psutil.NoSuchProcess foo") + + def test_zombie_process__repr__(self, func=repr): + self.assertEqual( + repr(psutil.ZombieProcess(321)), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321)") + self.assertEqual( + repr(psutil.ZombieProcess(321, name='foo')), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321, name='foo')") + self.assertEqual( + repr(psutil.ZombieProcess(321, name='foo', ppid=1)), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321, name='foo', ppid=1)") + self.assertEqual( + repr(psutil.ZombieProcess(321, msg='foo')), + "psutil.ZombieProcess foo") + + def test_access_denied__repr__(self, func=repr): + self.assertEqual( + repr(psutil.AccessDenied(321)), + "psutil.AccessDenied (pid=321)") + self.assertEqual( + repr(psutil.AccessDenied(321, name='foo')), + "psutil.AccessDenied (pid=321, name='foo')") + self.assertEqual( + repr(psutil.AccessDenied(321, msg='foo')), + "psutil.AccessDenied foo") + + def test_timeout_expired__repr__(self, func=repr): + self.assertEqual( + repr(psutil.TimeoutExpired(321)), + "psutil.TimeoutExpired timeout after 321 seconds") + self.assertEqual( + repr(psutil.TimeoutExpired(321, pid=111)), + "psutil.TimeoutExpired timeout after 321 seconds (pid=111)") + self.assertEqual( + repr(psutil.TimeoutExpired(321, pid=111, name='foo')), + "psutil.TimeoutExpired timeout after 321 seconds " + "(pid=111, name='foo')") + + def test_process__eq__(self): + p1 = psutil.Process() + p2 = psutil.Process() + self.assertEqual(p1, p2) + p2._ident = (0, 0) + self.assertNotEqual(p1, p2) + self.assertNotEqual(p1, 'foo') + + def test_process__hash__(self): + s = set([psutil.Process(), psutil.Process()]) + self.assertEqual(len(s), 1) + + def test__all__(self): + dir_psutil = dir(psutil) + for name in dir_psutil: + if name in ('callable', 'error', 'namedtuple', 'tests', + 'long', 'test', 'NUM_CPUS', 'BOOT_TIME', + 'TOTAL_PHYMEM'): + continue + if not name.startswith('_'): + try: + __import__(name) + except ImportError: + if name not in psutil.__all__: + fun = getattr(psutil, name) + if fun is None: + continue + if (fun.__doc__ is not None and + 'deprecated' not in fun.__doc__.lower()): + self.fail('%r not in psutil.__all__' % name) + + # Import 'star' will break if __all__ is inconsistent, see: + # https://github.com/giampaolo/psutil/issues/656 + # Can't do `from psutil import *` as it won't work on python 3 + # so we simply iterate over __all__. + for name in psutil.__all__: + self.assertIn(name, dir_psutil) + + def test_version(self): + self.assertEqual('.'.join([str(x) for x in psutil.version_info]), + psutil.__version__) + + def test_process_as_dict_no_new_names(self): + # See https://github.com/giampaolo/psutil/issues/813 + p = psutil.Process() + p.foo = '1' + self.assertNotIn('foo', p.as_dict()) + + def test_memoize(self): + @memoize + def foo(*args, **kwargs): + "foo docstring" + calls.append(None) + return (args, kwargs) + + calls = [] + # no args + for x in range(2): + ret = foo() + expected = ((), {}) + self.assertEqual(ret, expected) + self.assertEqual(len(calls), 1) + # with args + for x in range(2): + ret = foo(1) + expected = ((1, ), {}) + self.assertEqual(ret, expected) + self.assertEqual(len(calls), 2) + # with args + kwargs + for x in range(2): + ret = foo(1, bar=2) + expected = ((1, ), {'bar': 2}) + self.assertEqual(ret, expected) + self.assertEqual(len(calls), 3) + # clear cache + foo.cache_clear() + ret = foo() + expected = ((), {}) + self.assertEqual(ret, expected) + self.assertEqual(len(calls), 4) + # docstring + self.assertEqual(foo.__doc__, "foo docstring") + + def test_memoize_when_activated(self): + class Foo: + @memoize_when_activated + def foo(self): + calls.append(None) + + f = Foo() + calls = [] + f.foo() + f.foo() + self.assertEqual(len(calls), 2) + + # activate + calls = [] + f.foo.cache_activate() + f.foo() + f.foo() + self.assertEqual(len(calls), 1) + + # deactivate + calls = [] + f.foo.cache_deactivate() + f.foo() + f.foo() + self.assertEqual(len(calls), 2) + + def test_parse_environ_block(self): + from psutil._common import parse_environ_block + + def k(s): + return s.upper() if WINDOWS else s + + self.assertEqual(parse_environ_block("a=1\0"), + {k("a"): "1"}) + self.assertEqual(parse_environ_block("a=1\0b=2\0\0"), + {k("a"): "1", k("b"): "2"}) + self.assertEqual(parse_environ_block("a=1\0b=\0\0"), + {k("a"): "1", k("b"): ""}) + # ignore everything after \0\0 + self.assertEqual(parse_environ_block("a=1\0b=2\0\0c=3\0"), + {k("a"): "1", k("b"): "2"}) + # ignore everything that is not an assignment + self.assertEqual(parse_environ_block("xxx\0a=1\0"), {k("a"): "1"}) + self.assertEqual(parse_environ_block("a=1\0=b=2\0"), {k("a"): "1"}) + # do not fail if the block is incomplete + self.assertEqual(parse_environ_block("a=1\0b=2"), {k("a"): "1"}) + + def test_supports_ipv6(self): + if supports_ipv6(): + with mock.patch('psutil._common.socket') as s: + s.has_ipv6 = False + assert not supports_ipv6() + with mock.patch('psutil._common.socket.socket', + side_effect=socket.error) as s: + assert not supports_ipv6() + assert s.called + with mock.patch('psutil._common.socket.socket', + side_effect=socket.gaierror) as s: + assert not supports_ipv6() + assert s.called + with mock.patch('psutil._common.socket.socket.bind', + side_effect=socket.gaierror) as s: + assert not supports_ipv6() + assert s.called + else: + if hasattr(socket, 'AF_INET6'): + with self.assertRaises(Exception): + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock.bind(("::1", 0)) + + def test_isfile_strict(self): + from psutil._common import isfile_strict + this_file = os.path.abspath(__file__) + assert isfile_strict(this_file) + assert not isfile_strict(os.path.dirname(this_file)) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EPERM, "foo")): + self.assertRaises(OSError, isfile_strict, this_file) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EACCES, "foo")): + self.assertRaises(OSError, isfile_strict, this_file) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EINVAL, "foo")): + assert not isfile_strict(this_file) + with mock.patch('psutil._common.stat.S_ISREG', return_value=False): + assert not isfile_strict(this_file) + + def test_serialization(self): + def check(ret): + if json is not None: + json.loads(json.dumps(ret)) + a = pickle.dumps(ret) + b = pickle.loads(a) + self.assertEqual(ret, b) + + check(psutil.Process().as_dict()) + check(psutil.virtual_memory()) + check(psutil.swap_memory()) + check(psutil.cpu_times()) + check(psutil.cpu_times_percent(interval=0)) + check(psutil.net_io_counters()) + if LINUX and not os.path.exists('/proc/diskstats'): + pass + else: + if not APPVEYOR: + check(psutil.disk_io_counters()) + check(psutil.disk_partitions()) + check(psutil.disk_usage(os.getcwd())) + check(psutil.users()) + + def test_setup_script(self): + setup_py = os.path.join(ROOT_DIR, 'setup.py') + module = imp.load_source('setup', setup_py) + self.assertRaises(SystemExit, module.setup) + self.assertEqual(module.get_version(), psutil.__version__) + + def test_ad_on_process_creation(self): + # We are supposed to be able to instantiate Process also in case + # of zombie processes or access denied. + with mock.patch.object(psutil.Process, 'create_time', + side_effect=psutil.AccessDenied) as meth: + psutil.Process() + assert meth.called + with mock.patch.object(psutil.Process, 'create_time', + side_effect=psutil.ZombieProcess(1)) as meth: + psutil.Process() + assert meth.called + with mock.patch.object(psutil.Process, 'create_time', + side_effect=ValueError) as meth: + with self.assertRaises(ValueError): + psutil.Process() + assert meth.called + + def test_sanity_version_check(self): + # see: https://github.com/giampaolo/psutil/issues/564 + with mock.patch( + "psutil._psplatform.cext.version", return_value="0.0.0"): + with self.assertRaises(ImportError) as cm: + importlib.reload(psutil) + self.assertIn("version conflict", str(cm.exception).lower()) + + +# =================================================================== +# --- Example script tests +# =================================================================== + + +@unittest.skipIf(TOX, "can't test on TOX") +class TestScripts(unittest.TestCase): + """Tests for scripts in the "scripts" directory.""" + + def assert_stdout(self, exe, args=None): + exe = '"%s"' % os.path.join(SCRIPTS_DIR, exe) + if args: + exe = exe + ' ' + args + try: + out = sh(sys.executable + ' ' + exe).strip() + except RuntimeError as err: + if 'AccessDenied' in str(err): + return str(err) + else: + raise + assert out, out + return out + + def assert_syntax(self, exe, args=None): + exe = os.path.join(SCRIPTS_DIR, exe) + with open(exe, 'r') as f: + src = f.read() + ast.parse(src) + + def test_coverage(self): + # make sure all example scripts have a test method defined + meths = dir(self) + for name in os.listdir(SCRIPTS_DIR): + if name.endswith('.py'): + if 'test_' + os.path.splitext(name)[0] not in meths: + # self.assert_stdout(name) + self.fail('no test defined for %r script' + % os.path.join(SCRIPTS_DIR, name)) + + @unittest.skipUnless(POSIX, "POSIX only") + def test_executable(self): + for name in os.listdir(SCRIPTS_DIR): + if name.endswith('.py'): + path = os.path.join(SCRIPTS_DIR, name) + if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]: + self.fail('%r is not executable' % path) + + def test_disk_usage(self): + self.assert_stdout('disk_usage.py') + + def test_free(self): + self.assert_stdout('free.py') + + def test_meminfo(self): + self.assert_stdout('meminfo.py') + + def test_procinfo(self): + self.assert_stdout('procinfo.py', args=str(os.getpid())) + + # can't find users on APPVEYOR or TRAVIS + @unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(), + "unreliable on APPVEYOR or TRAVIS") + def test_who(self): + self.assert_stdout('who.py') + + def test_ps(self): + self.assert_stdout('ps.py') + + def test_pstree(self): + self.assert_stdout('pstree.py') + + def test_netstat(self): + self.assert_stdout('netstat.py') + + # permission denied on travis + @unittest.skipIf(TRAVIS, "unreliable on TRAVIS") + def test_ifconfig(self): + self.assert_stdout('ifconfig.py') + + @unittest.skipIf(OPENBSD or NETBSD, "platform not supported") + def test_pmap(self): + self.assert_stdout('pmap.py', args=str(os.getpid())) + + @unittest.skipUnless(OSX or WINDOWS or LINUX, "platform not supported") + def test_procsmem(self): + self.assert_stdout('procsmem.py') + + def test_killall(self): + self.assert_syntax('killall.py') + + def test_nettop(self): + self.assert_syntax('nettop.py') + + def test_top(self): + self.assert_syntax('top.py') + + def test_iotop(self): + self.assert_syntax('iotop.py') + + def test_pidof(self): + output = self.assert_stdout('pidof.py', args=psutil.Process().name()) + self.assertIn(str(os.getpid()), output) + + @unittest.skipUnless(WINDOWS, "WINDOWS only") + def test_winservices(self): + self.assert_stdout('winservices.py') + + def test_cpu_distribution(self): + self.assert_syntax('cpu_distribution.py') + + @unittest.skipIf(TRAVIS, "unreliable on travis") + def test_temperatures(self): + if hasattr(psutil, "sensors_temperatures") and \ + psutil.sensors_temperatures(): + self.assert_stdout('temperatures.py') + else: + self.assert_syntax('temperatures.py') + + @unittest.skipIf(TRAVIS, "unreliable on travis") + def test_fans(self): + if hasattr(psutil, "sensors_fans") and psutil.sensors_fans(): + self.assert_stdout('fans.py') + else: + self.assert_syntax('fans.py') + + def test_battery(self): + if hasattr(psutil, "sensors_battery") and \ + psutil.sensors_battery() is not None: + self.assert_stdout('battery.py') + else: + self.assert_syntax('battery.py') + + @unittest.skipIf(APPVEYOR or TRAVIS, "unreliable on CI") + def test_sensors(self): + self.assert_stdout('sensors.py') + + +# =================================================================== +# --- Unit tests for test utilities. +# =================================================================== + + +class TestRetryDecorator(unittest.TestCase): + + @mock.patch('time.sleep') + def test_retry_success(self, sleep): + # Fail 3 times out of 5; make sure the decorated fun returns. + + @retry(retries=5, interval=1, logfun=None) + def foo(): + while queue: + queue.pop() + 1 / 0 + return 1 + + queue = list(range(3)) + self.assertEqual(foo(), 1) + self.assertEqual(sleep.call_count, 3) + + @mock.patch('time.sleep') + def test_retry_failure(self, sleep): + # Fail 6 times out of 5; th function is supposed to raise exc. + + @retry(retries=5, interval=1, logfun=None) + def foo(): + while queue: + queue.pop() + 1 / 0 + return 1 + + queue = list(range(6)) + self.assertRaises(ZeroDivisionError, foo) + self.assertEqual(sleep.call_count, 5) + + @mock.patch('time.sleep') + def test_exception_arg(self, sleep): + @retry(exception=ValueError, interval=1) + def foo(): + raise TypeError + + self.assertRaises(TypeError, foo) + self.assertEqual(sleep.call_count, 0) + + @mock.patch('time.sleep') + def test_no_interval_arg(self, sleep): + # if interval is not specified sleep is not supposed to be called + + @retry(retries=5, interval=None, logfun=None) + def foo(): + 1 / 0 + + self.assertRaises(ZeroDivisionError, foo) + self.assertEqual(sleep.call_count, 0) + + @mock.patch('time.sleep') + def test_retries_arg(self, sleep): + + @retry(retries=5, interval=1, logfun=None) + def foo(): + 1 / 0 + + self.assertRaises(ZeroDivisionError, foo) + self.assertEqual(sleep.call_count, 5) + + @mock.patch('time.sleep') + def test_retries_and_timeout_args(self, sleep): + self.assertRaises(ValueError, retry, retries=5, timeout=1) + + +class TestSyncTestUtils(unittest.TestCase): + + def tearDown(self): + safe_rmpath(TESTFN) + + def test_wait_for_pid(self): + wait_for_pid(os.getpid()) + nopid = max(psutil.pids()) + 99999 + with mock.patch('psutil.tests.retry.__iter__', return_value=iter([0])): + self.assertRaises(psutil.NoSuchProcess, wait_for_pid, nopid) + + def test_wait_for_file(self): + with open(TESTFN, 'w') as f: + f.write('foo') + wait_for_file(TESTFN) + assert not os.path.exists(TESTFN) + + def test_wait_for_file_empty(self): + with open(TESTFN, 'w'): + pass + wait_for_file(TESTFN, empty=True) + assert not os.path.exists(TESTFN) + + def test_wait_for_file_no_file(self): + with mock.patch('psutil.tests.retry.__iter__', return_value=iter([0])): + self.assertRaises(IOError, wait_for_file, TESTFN) + + def test_wait_for_file_no_delete(self): + with open(TESTFN, 'w') as f: + f.write('foo') + wait_for_file(TESTFN, delete_file=False) + assert os.path.exists(TESTFN) + + +class TestFSTestUtils(unittest.TestCase): + + def setUp(self): + safe_rmpath(TESTFN) + + tearDown = setUp + + def test_safe_rmpath(self): + # test file is removed + open(TESTFN, 'w').close() + safe_rmpath(TESTFN) + assert not os.path.exists(TESTFN) + # test no exception if path does not exist + safe_rmpath(TESTFN) + # test dir is removed + os.mkdir(TESTFN) + safe_rmpath(TESTFN) + assert not os.path.exists(TESTFN) + # test other exceptions are raised + with mock.patch('psutil.tests.os.stat', + side_effect=OSError(errno.EINVAL, "")) as m: + with self.assertRaises(OSError): + safe_rmpath(TESTFN) + assert m.called + + def test_chdir(self): + base = os.getcwd() + os.mkdir(TESTFN) + with chdir(TESTFN): + self.assertEqual(os.getcwd(), os.path.join(base, TESTFN)) + self.assertEqual(os.getcwd(), base) + + +class TestTestUtils(unittest.TestCase): + + def test_reap_children(self): + subp = get_test_subprocess() + p = psutil.Process(subp.pid) + assert p.is_running() + reap_children() + assert not p.is_running() + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_osx.py b/pipenv/vendor/psutil/tests/test_osx.py new file mode 100755 index 00000000..69d6c840 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_osx.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""OSX specific tests.""" + +import os +import re +import subprocess +import sys +import time + +import psutil +from psutil import OSX +from psutil._compat import PY3 +from psutil.tests import get_test_subprocess +from psutil.tests import MEMORY_TOLERANCE +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import sh +from psutil.tests import unittest + + +PAGESIZE = os.sysconf("SC_PAGE_SIZE") if OSX else None + + +def sysctl(cmdline): + """Expects a sysctl command with an argument and parse the result + returning only the value of interest. + """ + p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) + result = p.communicate()[0].strip().split()[1] + if PY3: + result = str(result, sys.stdout.encoding) + try: + return int(result) + except ValueError: + return result + + +def vm_stat(field): + """Wrapper around 'vm_stat' cmdline utility.""" + out = sh('vm_stat') + for line in out.split('\n'): + if field in line: + break + else: + raise ValueError("line not found") + return int(re.search('\d+', line).group(0)) * PAGESIZE + + +# http://code.activestate.com/recipes/578019/ +def human2bytes(s): + SYMBOLS = { + 'customary': ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'), + } + init = s + num = "" + while s and s[0:1].isdigit() or s[0:1] == '.': + num += s[0] + s = s[1:] + num = float(num) + letter = s.strip() + for name, sset in SYMBOLS.items(): + if letter in sset: + break + else: + if letter == 'k': + sset = SYMBOLS['customary'] + letter = letter.upper() + else: + raise ValueError("can't interpret %r" % init) + prefix = {sset[0]: 1} + for i, s in enumerate(sset[1:]): + prefix[s] = 1 << (i + 1) * 10 + return int(num * prefix[letter]) + + +@unittest.skipUnless(OSX, "OSX only") +class TestProcess(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + + def test_process_create_time(self): + cmdline = "ps -o lstart -p %s" % self.pid + p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) + output = p.communicate()[0] + if PY3: + output = str(output, sys.stdout.encoding) + start_ps = output.replace('STARTED', '').strip() + hhmmss = start_ps.split(' ')[-2] + year = start_ps.split(' ')[-1] + start_psutil = psutil.Process(self.pid).create_time() + self.assertEqual( + hhmmss, + time.strftime("%H:%M:%S", time.localtime(start_psutil))) + self.assertEqual( + year, + time.strftime("%Y", time.localtime(start_psutil))) + + +@unittest.skipUnless(OSX, "OSX only") +class TestSystemAPIs(unittest.TestCase): + + # --- disk + + def test_disks(self): + # test psutil.disk_usage() and psutil.disk_partitions() + # against "df -a" + def df(path): + out = sh('df -k "%s"' % path).strip() + lines = out.split('\n') + lines.pop(0) + line = lines.pop(0) + dev, total, used, free = line.split()[:4] + if dev == 'none': + dev = '' + total = int(total) * 1024 + used = int(used) * 1024 + free = int(free) * 1024 + return dev, total, used, free + + for part in psutil.disk_partitions(all=False): + usage = psutil.disk_usage(part.mountpoint) + dev, total, used, free = df(part.mountpoint) + self.assertEqual(part.device, dev) + self.assertEqual(usage.total, total) + # 10 MB tollerance + if abs(usage.free - free) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % usage.free, free) + if abs(usage.used - used) > 10 * 1024 * 1024: + self.fail("psutil=%s, df=%s" % usage.used, used) + + # --- cpu + + def test_cpu_count_logical(self): + num = sysctl("sysctl hw.logicalcpu") + self.assertEqual(num, psutil.cpu_count(logical=True)) + + def test_cpu_count_physical(self): + num = sysctl("sysctl hw.physicalcpu") + self.assertEqual(num, psutil.cpu_count(logical=False)) + + def test_cpu_freq(self): + freq = psutil.cpu_freq() + self.assertEqual( + freq.current * 1000 * 1000, sysctl("sysctl hw.cpufrequency")) + self.assertEqual( + freq.min * 1000 * 1000, sysctl("sysctl hw.cpufrequency_min")) + self.assertEqual( + freq.max * 1000 * 1000, sysctl("sysctl hw.cpufrequency_max")) + + # --- virtual mem + + def test_vmem_total(self): + sysctl_hwphymem = sysctl('sysctl hw.memsize') + self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total) + + @retry_before_failing() + def test_vmem_free(self): + vmstat_val = vm_stat("free") + psutil_val = psutil.virtual_memory().free + self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_available(self): + vmstat_val = vm_stat("inactive") + vm_stat("free") + psutil_val = psutil.virtual_memory().available + self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_active(self): + vmstat_val = vm_stat("active") + psutil_val = psutil.virtual_memory().active + self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_inactive(self): + vmstat_val = vm_stat("inactive") + psutil_val = psutil.virtual_memory().inactive + self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE) + + @retry_before_failing() + def test_vmem_wired(self): + vmstat_val = vm_stat("wired") + psutil_val = psutil.virtual_memory().wired + self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE) + + # --- swap mem + + @retry_before_failing() + def test_swapmem_sin(self): + vmstat_val = vm_stat("Pageins") + psutil_val = psutil.swap_memory().sin + self.assertEqual(psutil_val, vmstat_val) + + @retry_before_failing() + def test_swapmem_sout(self): + vmstat_val = vm_stat("Pageout") + psutil_val = psutil.swap_memory().sout + self.assertEqual(psutil_val, vmstat_val) + + # Not very reliable. + # def test_swapmem_total(self): + # out = sh('sysctl vm.swapusage') + # out = out.replace('vm.swapusage: ', '') + # total, used, free = re.findall('\d+.\d+\w', out) + # psutil_smem = psutil.swap_memory() + # self.assertEqual(psutil_smem.total, human2bytes(total)) + # self.assertEqual(psutil_smem.used, human2bytes(used)) + # self.assertEqual(psutil_smem.free, human2bytes(free)) + + # --- network + + def test_net_if_stats(self): + for name, stats in psutil.net_if_stats().items(): + try: + out = sh("ifconfig %s" % name) + except RuntimeError: + pass + else: + self.assertEqual(stats.isup, 'RUNNING' in out, msg=out) + self.assertEqual(stats.mtu, + int(re.findall('mtu (\d+)', out)[0])) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_posix.py b/pipenv/vendor/psutil/tests/test_posix.py new file mode 100755 index 00000000..16d1eb7e --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_posix.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""POSIX specific tests.""" + +import datetime +import errno +import os +import subprocess +import sys +import time + +import psutil +from psutil import BSD +from psutil import LINUX +from psutil import OSX +from psutil import POSIX +from psutil import SUNOS +from psutil._compat import callable +from psutil._compat import PY3 +from psutil.tests import APPVEYOR +from psutil.tests import get_kernel_version +from psutil.tests import get_test_subprocess +from psutil.tests import mock +from psutil.tests import PYTHON +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import sh +from psutil.tests import skip_on_access_denied +from psutil.tests import TRAVIS +from psutil.tests import unittest +from psutil.tests import wait_for_pid + + +def ps(cmd): + """Expects a ps command with a -o argument and parse the result + returning only the value of interest. + """ + if not LINUX: + cmd = cmd.replace(" --no-headers ", " ") + if SUNOS: + cmd = cmd.replace("-o command", "-o comm") + cmd = cmd.replace("-o start", "-o stime") + p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE) + output = p.communicate()[0].strip() + if PY3: + output = str(output, sys.stdout.encoding) + if not LINUX: + output = output.split('\n')[1].strip() + try: + return int(output) + except ValueError: + return output + + +@unittest.skipUnless(POSIX, "POSIX only") +class TestProcess(unittest.TestCase): + """Compare psutil results against 'ps' command line utility (mainly).""" + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess([PYTHON, "-E", "-O"], + stdin=subprocess.PIPE).pid + wait_for_pid(cls.pid) + + @classmethod + def tearDownClass(cls): + reap_children() + + # for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps + + def test_ppid(self): + ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid) + ppid_psutil = psutil.Process(self.pid).ppid() + self.assertEqual(ppid_ps, ppid_psutil) + + def test_uid(self): + uid_ps = ps("ps --no-headers -o uid -p %s" % self.pid) + uid_psutil = psutil.Process(self.pid).uids().real + self.assertEqual(uid_ps, uid_psutil) + + def test_gid(self): + gid_ps = ps("ps --no-headers -o rgid -p %s" % self.pid) + gid_psutil = psutil.Process(self.pid).gids().real + self.assertEqual(gid_ps, gid_psutil) + + def test_username(self): + username_ps = ps("ps --no-headers -o user -p %s" % self.pid) + username_psutil = psutil.Process(self.pid).username() + self.assertEqual(username_ps, username_psutil) + + @skip_on_access_denied() + @retry_before_failing() + def test_rss_memory(self): + # give python interpreter some time to properly initialize + # so that the results are the same + time.sleep(0.1) + rss_ps = ps("ps --no-headers -o rss -p %s" % self.pid) + rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024 + self.assertEqual(rss_ps, rss_psutil) + + @skip_on_access_denied() + @retry_before_failing() + def test_vsz_memory(self): + # give python interpreter some time to properly initialize + # so that the results are the same + time.sleep(0.1) + vsz_ps = ps("ps --no-headers -o vsz -p %s" % self.pid) + vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024 + self.assertEqual(vsz_ps, vsz_psutil) + + def test_name(self): + # use command + arg since "comm" keyword not supported on all platforms + name_ps = ps("ps --no-headers -o command -p %s" % ( + self.pid)).split(' ')[0] + # remove path if there is any, from the command + name_ps = os.path.basename(name_ps).lower() + name_psutil = psutil.Process(self.pid).name().lower() + self.assertEqual(name_ps, name_psutil) + + @unittest.skipIf(OSX or BSD, 'ps -o start not available') + def test_create_time(self): + time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0] + time_psutil = psutil.Process(self.pid).create_time() + time_psutil_tstamp = datetime.datetime.fromtimestamp( + time_psutil).strftime("%H:%M:%S") + # sometimes ps shows the time rounded up instead of down, so we check + # for both possible values + round_time_psutil = round(time_psutil) + round_time_psutil_tstamp = datetime.datetime.fromtimestamp( + round_time_psutil).strftime("%H:%M:%S") + self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp]) + + def test_exe(self): + ps_pathname = ps("ps --no-headers -o command -p %s" % + self.pid).split(' ')[0] + psutil_pathname = psutil.Process(self.pid).exe() + try: + self.assertEqual(ps_pathname, psutil_pathname) + except AssertionError: + # certain platforms such as BSD are more accurate returning: + # "/usr/local/bin/python2.7" + # ...instead of: + # "/usr/local/bin/python" + # We do not want to consider this difference in accuracy + # an error. + adjusted_ps_pathname = ps_pathname[:len(ps_pathname)] + self.assertEqual(ps_pathname, adjusted_ps_pathname) + + def test_cmdline(self): + ps_cmdline = ps("ps --no-headers -o command -p %s" % self.pid) + psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline()) + if SUNOS: + # ps on Solaris only shows the first part of the cmdline + psutil_cmdline = psutil_cmdline.split(" ")[0] + self.assertEqual(ps_cmdline, psutil_cmdline) + + def test_nice(self): + ps_nice = ps("ps --no-headers -o nice -p %s" % self.pid) + psutil_nice = psutil.Process().nice() + self.assertEqual(ps_nice, psutil_nice) + + def test_num_fds(self): + # Note: this fails from time to time; I'm keen on thinking + # it doesn't mean something is broken + def call(p, attr): + args = () + attr = getattr(p, name, None) + if attr is not None and callable(attr): + if name == 'rlimit': + args = (psutil.RLIMIT_NOFILE,) + attr(*args) + else: + attr + + p = psutil.Process(os.getpid()) + failures = [] + ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice', + 'send_signal', 'wait', 'children', 'as_dict'] + if LINUX and get_kernel_version() < (2, 6, 36): + ignored_names.append('rlimit') + if LINUX and get_kernel_version() < (2, 6, 23): + ignored_names.append('num_ctx_switches') + for name in dir(psutil.Process): + if (name.startswith('_') or name in ignored_names): + continue + else: + try: + num1 = p.num_fds() + for x in range(2): + call(p, name) + num2 = p.num_fds() + except psutil.AccessDenied: + pass + else: + if abs(num2 - num1) > 1: + fail = "failure while processing Process.%s method " \ + "(before=%s, after=%s)" % (name, num1, num2) + failures.append(fail) + if failures: + self.fail('\n' + '\n'.join(failures)) + + @unittest.skipUnless(os.path.islink("/proc/%s/cwd" % os.getpid()), + "/proc fs not available") + def test_cwd(self): + self.assertEqual(os.readlink("/proc/%s/cwd" % os.getpid()), + psutil.Process().cwd()) + + +@unittest.skipUnless(POSIX, "POSIX only") +class TestSystemAPIs(unittest.TestCase): + """Test some system APIs.""" + + @retry_before_failing() + def test_pids(self): + # Note: this test might fail if the OS is starting/killing + # other processes in the meantime + if SUNOS: + cmd = ["ps", "-A", "-o", "pid"] + else: + cmd = ["ps", "ax", "-o", "pid"] + p = get_test_subprocess(cmd, stdout=subprocess.PIPE) + output = p.communicate()[0].strip() + assert p.poll() == 0 + if PY3: + output = str(output, sys.stdout.encoding) + pids_ps = [] + for line in output.split('\n')[1:]: + if line: + pid = int(line.split()[0].strip()) + pids_ps.append(pid) + # remove ps subprocess pid which is supposed to be dead in meantime + pids_ps.remove(p.pid) + pids_psutil = psutil.pids() + pids_ps.sort() + pids_psutil.sort() + + # on OSX ps doesn't show pid 0 + if OSX and 0 not in pids_ps: + pids_ps.insert(0, 0) + + if pids_ps != pids_psutil: + difference = [x for x in pids_psutil if x not in pids_ps] + \ + [x for x in pids_ps if x not in pids_psutil] + self.fail("difference: " + str(difference)) + + # for some reason ifconfig -a does not report all interfaces + # returned by psutil + @unittest.skipIf(SUNOS, "unreliable on SUNOS") + @unittest.skipIf(TRAVIS, "unreliable on TRAVIS") + def test_nic_names(self): + p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE) + output = p.communicate()[0].strip() + if p.returncode != 0: + raise unittest.SkipTest('ifconfig returned no output') + if PY3: + output = str(output, sys.stdout.encoding) + for nic in psutil.net_io_counters(pernic=True).keys(): + for line in output.split(): + if line.startswith(nic): + break + else: + self.fail( + "couldn't find %s nic in 'ifconfig -a' output\n%s" % ( + nic, output)) + + # can't find users on APPVEYOR or TRAVIS + @unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(), + "unreliable on APPVEYOR or TRAVIS") + @retry_before_failing() + def test_users(self): + out = sh("who") + lines = out.split('\n') + users = [x.split()[0] for x in lines] + self.assertEqual(len(users), len(psutil.users())) + terminals = [x.split()[1] for x in lines] + for u in psutil.users(): + self.assertTrue(u.name in users, u.name) + self.assertTrue(u.terminal in terminals, u.terminal) + + def test_pid_exists_let_raise(self): + # According to "man 2 kill" possible error values for kill + # are (EINVAL, EPERM, ESRCH). Test that any other errno + # results in an exception. + with mock.patch("psutil._psposix.os.kill", + side_effect=OSError(errno.EBADF, "")) as m: + self.assertRaises(OSError, psutil._psposix.pid_exists, os.getpid()) + assert m.called + + def test_os_waitpid_let_raise(self): + # os.waitpid() is supposed to catch EINTR and ECHILD only. + # Test that any other errno results in an exception. + with mock.patch("psutil._psposix.os.waitpid", + side_effect=OSError(errno.EBADF, "")) as m: + self.assertRaises(OSError, psutil._psposix.wait_pid, os.getpid()) + assert m.called + + def test_os_waitpid_eintr(self): + # os.waitpid() is supposed to "retry" on EINTR. + with mock.patch("psutil._psposix.os.waitpid", + side_effect=OSError(errno.EINTR, "")) as m: + self.assertRaises( + psutil._psposix.TimeoutExpired, + psutil._psposix.wait_pid, os.getpid(), timeout=0.01) + assert m.called + + def test_os_waitpid_bad_ret_status(self): + # Simulate os.waitpid() returning a bad status. + with mock.patch("psutil._psposix.os.waitpid", + return_value=(1, -1)) as m: + self.assertRaises(ValueError, + psutil._psposix.wait_pid, os.getpid()) + assert m.called + + def test_disk_usage(self): + def df(device): + out = sh("df -k %s" % device).strip() + line = out.split('\n')[1] + fields = line.split() + total = int(fields[1]) * 1024 + used = int(fields[2]) * 1024 + free = int(fields[3]) * 1024 + percent = float(fields[4].replace('%', '')) + return (total, used, free, percent) + + tolerance = 4 * 1024 * 1024 # 4MB + for part in psutil.disk_partitions(all=False): + usage = psutil.disk_usage(part.mountpoint) + try: + total, used, free, percent = df(part.device) + except RuntimeError as err: + # see: + # https://travis-ci.org/giampaolo/psutil/jobs/138338464 + # https://travis-ci.org/giampaolo/psutil/jobs/138343361 + if "no such file or directory" in str(err).lower() or \ + "raw devices not supported" in str(err).lower(): + continue + else: + raise + else: + self.assertAlmostEqual(usage.total, total, delta=tolerance) + self.assertAlmostEqual(usage.used, used, delta=tolerance) + self.assertAlmostEqual(usage.free, free, delta=tolerance) + self.assertAlmostEqual(usage.percent, percent, delta=1) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_process.py b/pipenv/vendor/psutil/tests/test_process.py new file mode 100755 index 00000000..6580fe9b --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_process.py @@ -0,0 +1,2103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Tests for psutil.Process class.""" + +import collections +import contextlib +import errno +import os +import select +import signal +import socket +import stat +import subprocess +import sys +import tempfile +import textwrap +import time +import traceback +import types +from socket import AF_INET +from socket import SOCK_DGRAM +from socket import SOCK_STREAM + +import psutil + +from psutil import BSD +from psutil import FREEBSD +from psutil import LINUX +from psutil import NETBSD +from psutil import OPENBSD +from psutil import OSX +from psutil import POSIX +from psutil import SUNOS +from psutil import WINDOWS +from psutil._common import supports_ipv6 +from psutil._compat import callable +from psutil._compat import long +from psutil._compat import PY3 +from psutil._compat import unicode +from psutil.tests import AF_INET6 +from psutil.tests import AF_UNIX +from psutil.tests import APPVEYOR +from psutil.tests import call_until +from psutil.tests import chdir +from psutil.tests import check_connection_ntuple +from psutil.tests import create_exe +from psutil.tests import enum +from psutil.tests import get_test_subprocess +from psutil.tests import get_winver +from psutil.tests import GLOBAL_TIMEOUT +from psutil.tests import mock +from psutil.tests import PYPY +from psutil.tests import pyrun +from psutil.tests import PYTHON +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import RLIMIT_SUPPORT +from psutil.tests import run_test_module_by_name +from psutil.tests import safe_rmpath +from psutil.tests import sh +from psutil.tests import skip_on_access_denied +from psutil.tests import skip_on_not_implemented +from psutil.tests import TESTFILE_PREFIX +from psutil.tests import TESTFN +from psutil.tests import ThreadTask +from psutil.tests import TOX +from psutil.tests import TRAVIS +from psutil.tests import unittest +from psutil.tests import VALID_PROC_STATUSES +from psutil.tests import wait_for_file +from psutil.tests import wait_for_pid +from psutil.tests import warn +from psutil.tests import WIN_VISTA + + +# =================================================================== +# --- psutil.Process class tests +# =================================================================== + +class TestProcess(unittest.TestCase): + """Tests for psutil.Process class.""" + + def setUp(self): + safe_rmpath(TESTFN) + + def tearDown(self): + reap_children() + + def test_pid(self): + p = psutil.Process() + self.assertEqual(p.pid, os.getpid()) + sproc = get_test_subprocess() + self.assertEqual(psutil.Process(sproc.pid).pid, sproc.pid) + with self.assertRaises(AttributeError): + p.pid = 33 + + def test_kill(self): + sproc = get_test_subprocess() + test_pid = sproc.pid + p = psutil.Process(test_pid) + p.kill() + sig = p.wait() + self.assertFalse(psutil.pid_exists(test_pid)) + if POSIX: + self.assertEqual(sig, -signal.SIGKILL) + + def test_terminate(self): + sproc = get_test_subprocess() + test_pid = sproc.pid + p = psutil.Process(test_pid) + p.terminate() + sig = p.wait() + self.assertFalse(psutil.pid_exists(test_pid)) + if POSIX: + self.assertEqual(sig, -signal.SIGTERM) + + def test_send_signal(self): + sig = signal.SIGKILL if POSIX else signal.SIGTERM + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.send_signal(sig) + exit_sig = p.wait() + self.assertFalse(psutil.pid_exists(p.pid)) + if POSIX: + self.assertEqual(exit_sig, -sig) + # + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.send_signal(sig) + with mock.patch('psutil.os.kill', + side_effect=OSError(errno.ESRCH, "")): + with self.assertRaises(psutil.NoSuchProcess): + p.send_signal(sig) + # + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.send_signal(sig) + with mock.patch('psutil.os.kill', + side_effect=OSError(errno.EPERM, "")): + with self.assertRaises(psutil.AccessDenied): + psutil.Process().send_signal(sig) + # Sending a signal to process with PID 0 is not allowed as + # it would affect every process in the process group of + # the calling process (os.getpid()) instead of PID 0"). + if 0 in psutil.pids(): + p = psutil.Process(0) + self.assertRaises(ValueError, p.send_signal, signal.SIGTERM) + + def test_wait(self): + # check exit code signal + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.kill() + code = p.wait() + if POSIX: + self.assertEqual(code, -signal.SIGKILL) + else: + self.assertEqual(code, 0) + self.assertFalse(p.is_running()) + + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.terminate() + code = p.wait() + if POSIX: + self.assertEqual(code, -signal.SIGTERM) + else: + self.assertEqual(code, 0) + self.assertFalse(p.is_running()) + + # check sys.exit() code + code = "import time, sys; time.sleep(0.01); sys.exit(5);" + sproc = get_test_subprocess([PYTHON, "-c", code]) + p = psutil.Process(sproc.pid) + self.assertEqual(p.wait(), 5) + self.assertFalse(p.is_running()) + + # Test wait() issued twice. + # It is not supposed to raise NSP when the process is gone. + # On UNIX this should return None, on Windows it should keep + # returning the exit code. + sproc = get_test_subprocess([PYTHON, "-c", code]) + p = psutil.Process(sproc.pid) + self.assertEqual(p.wait(), 5) + self.assertIn(p.wait(), (5, None)) + + # test timeout + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.name() + self.assertRaises(psutil.TimeoutExpired, p.wait, 0.01) + + # timeout < 0 not allowed + self.assertRaises(ValueError, p.wait, -1) + + # XXX why is this skipped on Windows? + @unittest.skipUnless(POSIX, 'skipped on Windows') + def test_wait_non_children(self): + # test wait() against processes which are not our children + code = "import sys;" + code += "from subprocess import Popen, PIPE;" + code += "cmd = ['%s', '-c', 'import time; time.sleep(60)'];" % PYTHON + code += "sp = Popen(cmd, stdout=PIPE);" + code += "sys.stdout.write(str(sp.pid));" + sproc = get_test_subprocess([PYTHON, "-c", code], + stdout=subprocess.PIPE) + grandson_pid = int(sproc.stdout.read()) + grandson_proc = psutil.Process(grandson_pid) + try: + self.assertRaises(psutil.TimeoutExpired, grandson_proc.wait, 0.01) + grandson_proc.kill() + ret = grandson_proc.wait() + self.assertEqual(ret, None) + finally: + reap_children(recursive=True) + + def test_wait_timeout_0(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + self.assertRaises(psutil.TimeoutExpired, p.wait, 0) + p.kill() + stop_at = time.time() + 2 + while True: + try: + code = p.wait(0) + except psutil.TimeoutExpired: + if time.time() >= stop_at: + raise + else: + break + if POSIX: + self.assertEqual(code, -signal.SIGKILL) + else: + self.assertEqual(code, 0) + self.assertFalse(p.is_running()) + + def test_cpu_percent(self): + p = psutil.Process() + p.cpu_percent(interval=0.001) + p.cpu_percent(interval=0.001) + for x in range(100): + percent = p.cpu_percent(interval=None) + self.assertIsInstance(percent, float) + self.assertGreaterEqual(percent, 0.0) + if not POSIX: + self.assertLessEqual(percent, 100.0) + else: + self.assertGreaterEqual(percent, 0.0) + with self.assertRaises(ValueError): + p.cpu_percent(interval=-1) + + def test_cpu_times(self): + times = psutil.Process().cpu_times() + assert (times.user > 0.0) or (times.system > 0.0), times + assert (times.children_user >= 0.0), times + assert (times.children_system >= 0.0), times + # make sure returned values can be pretty printed with strftime + for name in times._fields: + time.strftime("%H:%M:%S", time.localtime(getattr(times, name))) + + # Test Process.cpu_times() against os.times() + # os.times() is broken on Python 2.6 + # http://bugs.python.org/issue1040026 + # XXX fails on OSX: not sure if it's for os.times(). We should + # try this with Python 2.7 and re-enable the test. + + @unittest.skipUnless(sys.version_info > (2, 6, 1) and not OSX, + 'os.times() broken on OSX + PY2.6.1') + def test_cpu_times_2(self): + user_time, kernel_time = psutil.Process().cpu_times()[:2] + utime, ktime = os.times()[:2] + + # Use os.times()[:2] as base values to compare our results + # using a tolerance of +/- 0.1 seconds. + # It will fail if the difference between the values is > 0.1s. + if (max([user_time, utime]) - min([user_time, utime])) > 0.1: + self.fail("expected: %s, found: %s" % (utime, user_time)) + + if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1: + self.fail("expected: %s, found: %s" % (ktime, kernel_time)) + + @unittest.skipUnless(hasattr(psutil.Process, "cpu_num"), + "platform not supported") + def test_cpu_num(self): + p = psutil.Process() + num = p.cpu_num() + self.assertGreaterEqual(num, 0) + if psutil.cpu_count() == 1: + self.assertEqual(num, 0) + self.assertIn(p.cpu_num(), range(psutil.cpu_count())) + + def test_create_time(self): + sproc = get_test_subprocess() + now = time.time() + p = psutil.Process(sproc.pid) + create_time = p.create_time() + + # Use time.time() as base value to compare our result using a + # tolerance of +/- 1 second. + # It will fail if the difference between the values is > 2s. + difference = abs(create_time - now) + if difference > 2: + self.fail("expected: %s, found: %s, difference: %s" + % (now, create_time, difference)) + + # make sure returned value can be pretty printed with strftime + time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time())) + + @unittest.skipUnless(POSIX, 'POSIX only') + @unittest.skipIf(TRAVIS, 'not reliable on TRAVIS') + def test_terminal(self): + terminal = psutil.Process().terminal() + if sys.stdin.isatty() or sys.stdout.isatty(): + tty = os.path.realpath(sh('tty')) + self.assertEqual(terminal, tty) + else: + self.assertIsNone(terminal) + + @unittest.skipUnless(LINUX or BSD or WINDOWS, + 'platform not supported') + @skip_on_not_implemented(only_if=LINUX) + def test_io_counters(self): + p = psutil.Process() + + # test reads + io1 = p.io_counters() + with open(PYTHON, 'rb') as f: + f.read() + io2 = p.io_counters() + if not BSD: + self.assertGreater(io2.read_count, io1.read_count) + self.assertEqual(io2.write_count, io1.write_count) + if LINUX: + self.assertGreater(io2.read_chars, io1.read_chars) + self.assertEqual(io2.write_chars, io1.write_chars) + else: + self.assertGreaterEqual(io2.read_bytes, io1.read_bytes) + self.assertGreaterEqual(io2.write_bytes, io1.write_bytes) + + # test writes + io1 = p.io_counters() + with tempfile.TemporaryFile(prefix=TESTFILE_PREFIX) as f: + if PY3: + f.write(bytes("x" * 1000000, 'ascii')) + else: + f.write("x" * 1000000) + io2 = p.io_counters() + self.assertGreaterEqual(io2.write_count, io1.write_count) + self.assertGreaterEqual(io2.write_bytes, io1.write_bytes) + self.assertGreaterEqual(io2.read_count, io1.read_count) + self.assertGreaterEqual(io2.read_bytes, io1.read_bytes) + if LINUX: + self.assertGreater(io2.write_chars, io1.write_chars) + self.assertGreaterEqual(io2.read_chars, io1.read_chars) + + # sanity check + for i in range(len(io2)): + self.assertGreaterEqual(io2[i], 0) + self.assertGreaterEqual(io2[i], 0) + + @unittest.skipUnless(LINUX or (WINDOWS and get_winver() >= WIN_VISTA), + 'platform not supported') + @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") + def test_ionice(self): + if LINUX: + from psutil import (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE) + self.assertEqual(IOPRIO_CLASS_NONE, 0) + self.assertEqual(IOPRIO_CLASS_RT, 1) + self.assertEqual(IOPRIO_CLASS_BE, 2) + self.assertEqual(IOPRIO_CLASS_IDLE, 3) + p = psutil.Process() + try: + p.ionice(2) + ioclass, value = p.ionice() + if enum is not None: + self.assertIsInstance(ioclass, enum.IntEnum) + self.assertEqual(ioclass, 2) + self.assertEqual(value, 4) + # + p.ionice(3) + ioclass, value = p.ionice() + self.assertEqual(ioclass, 3) + self.assertEqual(value, 0) + # + p.ionice(2, 0) + ioclass, value = p.ionice() + self.assertEqual(ioclass, 2) + self.assertEqual(value, 0) + p.ionice(2, 7) + ioclass, value = p.ionice() + self.assertEqual(ioclass, 2) + self.assertEqual(value, 7) + # + self.assertRaises(ValueError, p.ionice, 2, 10) + self.assertRaises(ValueError, p.ionice, 2, -1) + self.assertRaises(ValueError, p.ionice, 4) + self.assertRaises(TypeError, p.ionice, 2, "foo") + self.assertRaisesRegex( + ValueError, "can't specify value with IOPRIO_CLASS_NONE", + p.ionice, psutil.IOPRIO_CLASS_NONE, 1) + self.assertRaisesRegex( + ValueError, "can't specify value with IOPRIO_CLASS_IDLE", + p.ionice, psutil.IOPRIO_CLASS_IDLE, 1) + self.assertRaisesRegex( + ValueError, "'ioclass' argument must be specified", + p.ionice, value=1) + finally: + p.ionice(IOPRIO_CLASS_NONE) + else: + p = psutil.Process() + original = p.ionice() + self.assertIsInstance(original, int) + try: + value = 0 # very low + if original == value: + value = 1 # low + p.ionice(value) + self.assertEqual(p.ionice(), value) + finally: + p.ionice(original) + # + self.assertRaises(ValueError, p.ionice, 3) + self.assertRaises(TypeError, p.ionice, 2, 1) + + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_get(self): + import resource + p = psutil.Process(os.getpid()) + names = [x for x in dir(psutil) if x.startswith('RLIMIT')] + assert names, names + for name in names: + value = getattr(psutil, name) + self.assertGreaterEqual(value, 0) + if name in dir(resource): + self.assertEqual(value, getattr(resource, name)) + # XXX - On PyPy RLIMIT_INFINITY returned by + # resource.getrlimit() is reported as a very big long + # number instead of -1. It looks like a bug with PyPy. + if PYPY: + continue + self.assertEqual(p.rlimit(value), resource.getrlimit(value)) + else: + ret = p.rlimit(value) + self.assertEqual(len(ret), 2) + self.assertGreaterEqual(ret[0], -1) + self.assertGreaterEqual(ret[1], -1) + + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_set(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) + self.assertEqual(p.rlimit(psutil.RLIMIT_NOFILE), (5, 5)) + # If pid is 0 prlimit() applies to the calling process and + # we don't want that. + with self.assertRaises(ValueError): + psutil._psplatform.Process(0).rlimit(0) + with self.assertRaises(ValueError): + p.rlimit(psutil.RLIMIT_NOFILE, (5, 5, 5)) + + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit(self): + p = psutil.Process() + soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) + try: + p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard)) + with open(TESTFN, "wb") as f: + f.write(b"X" * 1024) + # write() or flush() doesn't always cause the exception + # but close() will. + with self.assertRaises(IOError) as exc: + with open(TESTFN, "wb") as f: + f.write(b"X" * 1025) + self.assertEqual(exc.exception.errno if PY3 else exc.exception[0], + errno.EFBIG) + finally: + p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) + self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard)) + + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_infinity(self): + # First set a limit, then re-set it by specifying INFINITY + # and assume we overridden the previous limit. + p = psutil.Process() + soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) + try: + p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard)) + p.rlimit(psutil.RLIMIT_FSIZE, (psutil.RLIM_INFINITY, hard)) + with open(TESTFN, "wb") as f: + f.write(b"X" * 2048) + finally: + p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) + self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard)) + + @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "LINUX >= 2.6.36 only") + def test_rlimit_infinity_value(self): + # RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really + # big number on a platform with large file support. On these + # platforms we need to test that the get/setrlimit functions + # properly convert the number to a C long long and that the + # conversion doesn't raise an error. + p = psutil.Process() + soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) + self.assertEqual(psutil.RLIM_INFINITY, hard) + p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) + + def test_num_threads(self): + # on certain platforms such as Linux we might test for exact + # thread number, since we always have with 1 thread per process, + # but this does not apply across all platforms (OSX, Windows) + p = psutil.Process() + if OPENBSD: + try: + step1 = p.num_threads() + except psutil.AccessDenied: + raise unittest.SkipTest("on OpenBSD this requires root access") + else: + step1 = p.num_threads() + + thread = ThreadTask() + thread.start() + try: + step2 = p.num_threads() + self.assertEqual(step2, step1 + 1) + finally: + thread.stop() + + @unittest.skipUnless(WINDOWS, 'WINDOWS only') + def test_num_handles(self): + # a better test is done later into test/_windows.py + p = psutil.Process() + self.assertGreater(p.num_handles(), 0) + + def test_threads(self): + p = psutil.Process() + if OPENBSD: + try: + step1 = p.threads() + except psutil.AccessDenied: + raise unittest.SkipTest("on OpenBSD this requires root access") + else: + step1 = p.threads() + + thread = ThreadTask() + thread.start() + try: + step2 = p.threads() + self.assertEqual(len(step2), len(step1) + 1) + # on Linux, first thread id is supposed to be this process + if LINUX: + self.assertEqual(step2[0].id, os.getpid()) + athread = step2[0] + # test named tuple + self.assertEqual(athread.id, athread[0]) + self.assertEqual(athread.user_time, athread[1]) + self.assertEqual(athread.system_time, athread[2]) + finally: + thread.stop() + + @retry_before_failing() + # see: https://travis-ci.org/giampaolo/psutil/jobs/111842553 + @unittest.skipIf(OSX and TRAVIS, "fails on TRAVIS + OSX") + @skip_on_access_denied(only_if=OSX) + def test_threads_2(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + if OPENBSD: + try: + p.threads() + except psutil.AccessDenied: + raise unittest.SkipTest( + "on OpenBSD this requires root access") + self.assertAlmostEqual( + p.cpu_times().user, + sum([x.user_time for x in p.threads()]), delta=0.1) + self.assertAlmostEqual( + p.cpu_times().system, + sum([x.system_time for x in p.threads()]), delta=0.1) + + def test_memory_info(self): + p = psutil.Process() + + # step 1 - get a base value to compare our results + rss1, vms1 = p.memory_info()[:2] + percent1 = p.memory_percent() + self.assertGreater(rss1, 0) + self.assertGreater(vms1, 0) + + # step 2 - allocate some memory + memarr = [None] * 1500000 + + rss2, vms2 = p.memory_info()[:2] + percent2 = p.memory_percent() + + # step 3 - make sure that the memory usage bumped up + self.assertGreater(rss2, rss1) + self.assertGreaterEqual(vms2, vms1) # vms might be equal + self.assertGreater(percent2, percent1) + del memarr + + if WINDOWS: + mem = p.memory_info() + self.assertEqual(mem.rss, mem.wset) + self.assertEqual(mem.vms, mem.pagefile) + + mem = p.memory_info() + for name in mem._fields: + self.assertGreaterEqual(getattr(mem, name), 0) + + def test_memory_full_info(self): + total = psutil.virtual_memory().total + mem = psutil.Process().memory_full_info() + for name in mem._fields: + value = getattr(mem, name) + self.assertGreaterEqual(value, 0, msg=(name, value)) + self.assertLessEqual(value, total, msg=(name, value, total)) + if LINUX or WINDOWS or OSX: + mem.uss + if LINUX: + mem.pss + self.assertGreater(mem.pss, mem.uss) + + @unittest.skipIf(OPENBSD or NETBSD, "platfform not supported") + def test_memory_maps(self): + p = psutil.Process() + maps = p.memory_maps() + paths = [x for x in maps] + self.assertEqual(len(paths), len(set(paths))) + ext_maps = p.memory_maps(grouped=False) + + for nt in maps: + if not nt.path.startswith('['): + assert os.path.isabs(nt.path), nt.path + if POSIX: + try: + assert os.path.exists(nt.path) or \ + os.path.islink(nt.path), nt.path + except AssertionError: + if not LINUX: + raise + else: + # https://github.com/giampaolo/psutil/issues/759 + with open('/proc/self/smaps') as f: + data = f.read() + if "%s (deleted)" % nt.path not in data: + raise + else: + # XXX - On Windows we have this strange behavior with + # 64 bit dlls: they are visible via explorer but cannot + # be accessed via os.stat() (wtf?). + if '64' not in os.path.basename(nt.path): + assert os.path.exists(nt.path), nt.path + for nt in ext_maps: + for fname in nt._fields: + value = getattr(nt, fname) + if fname == 'path': + continue + elif fname in ('addr', 'perms'): + assert value, value + else: + self.assertIsInstance(value, (int, long)) + assert value >= 0, value + + def test_memory_percent(self): + p = psutil.Process() + ret = p.memory_percent() + assert 0 <= ret <= 100, ret + ret = p.memory_percent(memtype='vms') + assert 0 <= ret <= 100, ret + assert 0 <= ret <= 100, ret + self.assertRaises(ValueError, p.memory_percent, memtype="?!?") + if LINUX or OSX or WINDOWS: + ret = p.memory_percent(memtype='uss') + assert 0 <= ret <= 100, ret + assert 0 <= ret <= 100, ret + + def test_is_running(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + assert p.is_running() + assert p.is_running() + p.kill() + p.wait() + assert not p.is_running() + assert not p.is_running() + + def test_exe(self): + sproc = get_test_subprocess() + exe = psutil.Process(sproc.pid).exe() + try: + self.assertEqual(exe, PYTHON) + except AssertionError: + if WINDOWS and len(exe) == len(PYTHON): + # on Windows we don't care about case sensitivity + normcase = os.path.normcase + self.assertEqual(normcase(exe), normcase(PYTHON)) + else: + # certain platforms such as BSD are more accurate returning: + # "/usr/local/bin/python2.7" + # ...instead of: + # "/usr/local/bin/python" + # We do not want to consider this difference in accuracy + # an error. + ver = "%s.%s" % (sys.version_info[0], sys.version_info[1]) + try: + self.assertEqual(exe.replace(ver, ''), + PYTHON.replace(ver, '')) + except AssertionError: + # Tipically OSX. Really not sure what to do here. + pass + + subp = subprocess.Popen([exe, '-c', 'import os; print("hey")'], + stdout=subprocess.PIPE) + out, _ = subp.communicate() + self.assertEqual(out.strip(), b'hey') + + def test_cmdline(self): + cmdline = [PYTHON, "-c", "import time; time.sleep(60)"] + sproc = get_test_subprocess(cmdline) + try: + self.assertEqual(' '.join(psutil.Process(sproc.pid).cmdline()), + ' '.join(cmdline)) + except AssertionError: + # XXX - most of the times the underlying sysctl() call on Net + # and Open BSD returns a truncated string. + # Also /proc/pid/cmdline behaves the same so it looks + # like this is a kernel bug. + if NETBSD or OPENBSD: + self.assertEqual( + psutil.Process(sproc.pid).cmdline()[0], PYTHON) + else: + raise + + def test_name(self): + sproc = get_test_subprocess(PYTHON) + name = psutil.Process(sproc.pid).name().lower() + pyexe = os.path.basename(os.path.realpath(sys.executable)).lower() + assert pyexe.startswith(name), (pyexe, name) + + # XXX + @unittest.skipIf(SUNOS, "broken on SUNOS") + def test_prog_w_funky_name(self): + # Test that name(), exe() and cmdline() correctly handle programs + # with funky chars such as spaces and ")", see: + # https://github.com/giampaolo/psutil/issues/628 + funky_path = TESTFN + 'foo bar )' + create_exe(funky_path) + self.addCleanup(safe_rmpath, funky_path) + cmdline = [funky_path, "-c", + "import time; [time.sleep(0.01) for x in range(3000)];" + "arg1", "arg2", "", "arg3", ""] + sproc = get_test_subprocess(cmdline) + p = psutil.Process(sproc.pid) + # ...in order to try to prevent occasional failures on travis + if TRAVIS: + wait_for_pid(p.pid) + self.assertEqual(p.cmdline(), cmdline) + self.assertEqual(p.name(), os.path.basename(funky_path)) + self.assertEqual(os.path.normcase(p.exe()), + os.path.normcase(funky_path)) + + @unittest.skipUnless(POSIX, 'POSIX only') + def test_uids(self): + p = psutil.Process() + real, effective, saved = p.uids() + # os.getuid() refers to "real" uid + self.assertEqual(real, os.getuid()) + # os.geteuid() refers to "effective" uid + self.assertEqual(effective, os.geteuid()) + # No such thing as os.getsuid() ("saved" uid), but starting + # from python 2.7 we have os.getresuid() which returns all + # of them. + if hasattr(os, "getresuid"): + self.assertEqual(os.getresuid(), p.uids()) + + @unittest.skipUnless(POSIX, 'POSIX only') + def test_gids(self): + p = psutil.Process() + real, effective, saved = p.gids() + # os.getuid() refers to "real" uid + self.assertEqual(real, os.getgid()) + # os.geteuid() refers to "effective" uid + self.assertEqual(effective, os.getegid()) + # No such thing as os.getsgid() ("saved" gid), but starting + # from python 2.7 we have os.getresgid() which returns all + # of them. + if hasattr(os, "getresuid"): + self.assertEqual(os.getresgid(), p.gids()) + + def test_nice(self): + p = psutil.Process() + self.assertRaises(TypeError, p.nice, "str") + if WINDOWS: + try: + init = p.nice() + if sys.version_info > (3, 4): + self.assertIsInstance(init, enum.IntEnum) + else: + self.assertIsInstance(init, int) + self.assertEqual(init, psutil.NORMAL_PRIORITY_CLASS) + p.nice(psutil.HIGH_PRIORITY_CLASS) + self.assertEqual(p.nice(), psutil.HIGH_PRIORITY_CLASS) + p.nice(psutil.NORMAL_PRIORITY_CLASS) + self.assertEqual(p.nice(), psutil.NORMAL_PRIORITY_CLASS) + finally: + p.nice(psutil.NORMAL_PRIORITY_CLASS) + else: + first_nice = p.nice() + try: + if hasattr(os, "getpriority"): + self.assertEqual( + os.getpriority(os.PRIO_PROCESS, os.getpid()), p.nice()) + p.nice(1) + self.assertEqual(p.nice(), 1) + if hasattr(os, "getpriority"): + self.assertEqual( + os.getpriority(os.PRIO_PROCESS, os.getpid()), p.nice()) + # XXX - going back to previous nice value raises + # AccessDenied on OSX + if not OSX: + p.nice(0) + self.assertEqual(p.nice(), 0) + except psutil.AccessDenied: + pass + finally: + try: + p.nice(first_nice) + except psutil.AccessDenied: + pass + + def test_status(self): + p = psutil.Process() + self.assertEqual(p.status(), psutil.STATUS_RUNNING) + + def test_username(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + if POSIX: + import pwd + self.assertEqual(p.username(), pwd.getpwuid(os.getuid()).pw_name) + with mock.patch("psutil.pwd.getpwuid", + side_effect=KeyError) as fun: + p.username() == str(p.uids().real) + assert fun.called + + elif WINDOWS and 'USERNAME' in os.environ: + expected_username = os.environ['USERNAME'] + expected_domain = os.environ['USERDOMAIN'] + domain, username = p.username().split('\\') + self.assertEqual(domain, expected_domain) + self.assertEqual(username, expected_username) + else: + p.username() + + def test_cwd(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + self.assertEqual(p.cwd(), os.getcwd()) + + def test_cwd_2(self): + cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(60)"] + sproc = get_test_subprocess(cmd) + p = psutil.Process(sproc.pid) + call_until(p.cwd, "ret == os.path.dirname(os.getcwd())") + + @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, 'platform not supported') + @unittest.skipIf(LINUX and TRAVIS, "unreliable on TRAVIS") + def test_cpu_affinity(self): + p = psutil.Process() + initial = p.cpu_affinity() + assert initial, initial + self.addCleanup(p.cpu_affinity, initial) + + if hasattr(os, "sched_getaffinity"): + self.assertEqual(initial, list(os.sched_getaffinity(p.pid))) + self.assertEqual(len(initial), len(set(initial))) + + all_cpus = list(range(len(psutil.cpu_percent(percpu=True)))) + # setting on travis doesn't seem to work (always return all + # CPUs on get): + # AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, ... != [0] + for n in all_cpus: + p.cpu_affinity([n]) + self.assertEqual(p.cpu_affinity(), [n]) + if hasattr(os, "sched_getaffinity"): + self.assertEqual(p.cpu_affinity(), + list(os.sched_getaffinity(p.pid))) + # also test num_cpu() + if hasattr(p, "num_cpu"): + self.assertEqual(p.cpu_affinity()[0], p.num_cpu()) + + # [] is an alias for "all eligible CPUs"; on Linux this may + # not be equal to all available CPUs, see: + # https://github.com/giampaolo/psutil/issues/956 + p.cpu_affinity([]) + if LINUX: + self.assertEqual(p.cpu_affinity(), p._proc._get_eligible_cpus()) + else: + self.assertEqual(p.cpu_affinity(), all_cpus) + if hasattr(os, "sched_getaffinity"): + self.assertEqual(p.cpu_affinity(), + list(os.sched_getaffinity(p.pid))) + # + self.assertRaises(TypeError, p.cpu_affinity, 1) + p.cpu_affinity(initial) + # it should work with all iterables, not only lists + p.cpu_affinity(set(all_cpus)) + p.cpu_affinity(tuple(all_cpus)) + invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10] + self.assertRaises(ValueError, p.cpu_affinity, invalid_cpu) + self.assertRaises(ValueError, p.cpu_affinity, range(10000, 11000)) + self.assertRaises(TypeError, p.cpu_affinity, [0, "1"]) + self.assertRaises(ValueError, p.cpu_affinity, [0, -1]) + + # TODO: #595 + @unittest.skipIf(BSD, "broken on BSD") + # can't find any process file on Appveyor + @unittest.skipIf(APPVEYOR, "unreliable on APPVEYOR") + def test_open_files(self): + # current process + p = psutil.Process() + files = p.open_files() + self.assertFalse(TESTFN in files) + with open(TESTFN, 'wb') as f: + f.write(b'x' * 1024) + f.flush() + # give the kernel some time to see the new file + files = call_until(p.open_files, "len(ret) != %i" % len(files)) + for file in files: + if file.path == TESTFN: + if LINUX: + self.assertEqual(file.position, 1024) + break + else: + self.fail("no file found; files=%s" % repr(files)) + for file in files: + assert os.path.isfile(file.path), file + + # another process + cmdline = "import time; f = open(r'%s', 'r'); time.sleep(60);" % TESTFN + sproc = get_test_subprocess([PYTHON, "-c", cmdline]) + p = psutil.Process(sproc.pid) + + for x in range(100): + filenames = [x.path for x in p.open_files()] + if TESTFN in filenames: + break + time.sleep(.01) + else: + self.assertIn(TESTFN, filenames) + for file in filenames: + assert os.path.isfile(file), file + + # TODO: #595 + @unittest.skipIf(BSD, "broken on BSD") + # can't find any process file on Appveyor + @unittest.skipIf(APPVEYOR, "unreliable on APPVEYOR") + def test_open_files_2(self): + # test fd and path fields + with open(TESTFN, 'w') as fileobj: + p = psutil.Process() + for file in p.open_files(): + if file.path == fileobj.name or file.fd == fileobj.fileno(): + break + else: + self.fail("no file found; files=%s" % repr(p.open_files())) + self.assertEqual(file.path, fileobj.name) + if WINDOWS: + self.assertEqual(file.fd, -1) + else: + self.assertEqual(file.fd, fileobj.fileno()) + # test positions + ntuple = p.open_files()[0] + self.assertEqual(ntuple[0], ntuple.path) + self.assertEqual(ntuple[1], ntuple.fd) + # test file is gone + self.assertTrue(fileobj.name not in p.open_files()) + + def compare_proc_sys_cons(self, pid, proc_cons): + from psutil._common import pconn + sys_cons = [c[:-1] for c in psutil.net_connections(kind='all') + if c.pid == pid] + if FREEBSD: + # on FreeBSD all fds are set to -1 + proc_cons = [pconn(*[-1] + list(x[1:])) for x in proc_cons] + self.assertEqual(sorted(proc_cons), sorted(sys_cons)) + + @skip_on_access_denied(only_if=OSX) + def test_connections(self): + def check_conn(proc, conn, family, type, laddr, raddr, status, kinds): + all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", + "tcp6", "udp", "udp4", "udp6") + check_connection_ntuple(conn) + self.assertEqual(conn.family, family) + self.assertEqual(conn.type, type) + self.assertEqual(conn.laddr, laddr) + self.assertEqual(conn.raddr, raddr) + self.assertEqual(conn.status, status) + for kind in all_kinds: + cons = proc.connections(kind=kind) + if kind in kinds: + self.assertNotEqual(cons, []) + else: + self.assertEqual(cons, []) + # compare against system-wide connections + # XXX Solaris can't retrieve system-wide UNIX + # sockets. + if not SUNOS: + self.compare_proc_sys_cons(proc.pid, [conn]) + + tcp_template = textwrap.dedent(""" + import socket, time + s = socket.socket($family, socket.SOCK_STREAM) + s.bind(('$addr', 0)) + s.listen(1) + with open('$testfn', 'w') as f: + f.write(str(s.getsockname()[:2])) + time.sleep(60) + """) + + udp_template = textwrap.dedent(""" + import socket, time + s = socket.socket($family, socket.SOCK_DGRAM) + s.bind(('$addr', 0)) + with open('$testfn', 'w') as f: + f.write(str(s.getsockname()[:2])) + time.sleep(60) + """) + + from string import Template + testfile = os.path.basename(TESTFN) + tcp4_template = Template(tcp_template).substitute( + family=int(AF_INET), addr="127.0.0.1", testfn=testfile) + udp4_template = Template(udp_template).substitute( + family=int(AF_INET), addr="127.0.0.1", testfn=testfile) + tcp6_template = Template(tcp_template).substitute( + family=int(AF_INET6), addr="::1", testfn=testfile) + udp6_template = Template(udp_template).substitute( + family=int(AF_INET6), addr="::1", testfn=testfile) + + # launch various subprocess instantiating a socket of various + # families and types to enrich psutil results + tcp4_proc = pyrun(tcp4_template) + tcp4_addr = eval(wait_for_file(testfile)) + udp4_proc = pyrun(udp4_template) + udp4_addr = eval(wait_for_file(testfile)) + if supports_ipv6(): + tcp6_proc = pyrun(tcp6_template) + tcp6_addr = eval(wait_for_file(testfile)) + udp6_proc = pyrun(udp6_template) + udp6_addr = eval(wait_for_file(testfile)) + else: + tcp6_proc = None + udp6_proc = None + tcp6_addr = None + udp6_addr = None + + for p in psutil.Process().children(): + cons = p.connections() + self.assertEqual(len(cons), 1) + for conn in cons: + # TCP v4 + if p.pid == tcp4_proc.pid: + check_conn(p, conn, AF_INET, SOCK_STREAM, tcp4_addr, (), + psutil.CONN_LISTEN, + ("all", "inet", "inet4", "tcp", "tcp4")) + # UDP v4 + elif p.pid == udp4_proc.pid: + check_conn(p, conn, AF_INET, SOCK_DGRAM, udp4_addr, (), + psutil.CONN_NONE, + ("all", "inet", "inet4", "udp", "udp4")) + # TCP v6 + elif p.pid == getattr(tcp6_proc, "pid", None): + check_conn(p, conn, AF_INET6, SOCK_STREAM, tcp6_addr, (), + psutil.CONN_LISTEN, + ("all", "inet", "inet6", "tcp", "tcp6")) + # UDP v6 + elif p.pid == getattr(udp6_proc, "pid", None): + check_conn(p, conn, AF_INET6, SOCK_DGRAM, udp6_addr, (), + psutil.CONN_NONE, + ("all", "inet", "inet6", "udp", "udp6")) + + @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'AF_UNIX not supported') + @skip_on_access_denied(only_if=OSX) + def test_connections_unix(self): + def check(type): + safe_rmpath(TESTFN) + tfile = tempfile.mktemp(prefix=TESTFILE_PREFIX) if OSX else TESTFN + sock = socket.socket(AF_UNIX, type) + with contextlib.closing(sock): + sock.bind(tfile) + cons = psutil.Process().connections(kind='unix') + conn = cons[0] + check_connection_ntuple(conn) + if conn.fd != -1: # != sunos and windows + self.assertEqual(conn.fd, sock.fileno()) + self.assertEqual(conn.family, AF_UNIX) + self.assertEqual(conn.type, type) + self.assertEqual(conn.laddr, tfile) + if not SUNOS: + # XXX Solaris can't retrieve system-wide UNIX + # sockets. + self.compare_proc_sys_cons(os.getpid(), cons) + + check(SOCK_STREAM) + check(SOCK_DGRAM) + + @unittest.skipUnless(hasattr(socket, "fromfd"), + 'socket.fromfd() not supported') + @unittest.skipIf(WINDOWS or SUNOS, + 'connection fd not available on this platform') + def test_connection_fromfd(self): + with contextlib.closing(socket.socket()) as sock: + sock.bind(('localhost', 0)) + sock.listen(1) + p = psutil.Process() + for conn in p.connections(): + if conn.fd == sock.fileno(): + break + else: + self.fail("couldn't find socket fd") + dupsock = socket.fromfd(conn.fd, conn.family, conn.type) + with contextlib.closing(dupsock): + self.assertEqual(dupsock.getsockname(), conn.laddr) + self.assertNotEqual(sock.fileno(), dupsock.fileno()) + + def test_connection_constants(self): + ints = [] + strs = [] + for name in dir(psutil): + if name.startswith('CONN_'): + num = getattr(psutil, name) + str_ = str(num) + assert str_.isupper(), str_ + assert str_ not in strs, str_ + assert num not in ints, num + ints.append(num) + strs.append(str_) + if SUNOS: + psutil.CONN_IDLE + psutil.CONN_BOUND + if WINDOWS: + psutil.CONN_DELETE_TCB + + @unittest.skipUnless(POSIX, 'POSIX only') + def test_num_fds(self): + p = psutil.Process() + start = p.num_fds() + file = open(TESTFN, 'w') + self.addCleanup(file.close) + self.assertEqual(p.num_fds(), start + 1) + sock = socket.socket() + self.addCleanup(sock.close) + self.assertEqual(p.num_fds(), start + 2) + file.close() + sock.close() + self.assertEqual(p.num_fds(), start) + + @skip_on_not_implemented(only_if=LINUX) + @unittest.skipIf(OPENBSD or NETBSD, "not reliable on OPENBSD & NETBSD") + def test_num_ctx_switches(self): + p = psutil.Process() + before = sum(p.num_ctx_switches()) + for x in range(500000): + after = sum(p.num_ctx_switches()) + if after > before: + return + self.fail("num ctx switches still the same after 50.000 iterations") + + def test_ppid(self): + if hasattr(os, 'getppid'): + self.assertEqual(psutil.Process().ppid(), os.getppid()) + this_parent = os.getpid() + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + self.assertEqual(p.ppid(), this_parent) + self.assertEqual(p.parent().pid, this_parent) + # no other process is supposed to have us as parent + reap_children(recursive=True) + if APPVEYOR: + # Occasional failures, see: + # https://ci.appveyor.com/project/giampaolo/psutil/build/ + # job/0hs623nenj7w4m33 + return + for p in psutil.process_iter(): + if p.pid == sproc.pid: + continue + # XXX: sometimes this fails on Windows; not sure why. + self.assertNotEqual(p.ppid(), this_parent, msg=p) + + def test_children(self): + p = psutil.Process() + self.assertEqual(p.children(), []) + self.assertEqual(p.children(recursive=True), []) + sproc = get_test_subprocess() + children1 = p.children() + children2 = p.children(recursive=True) + for children in (children1, children2): + self.assertEqual(len(children), 1) + self.assertEqual(children[0].pid, sproc.pid) + self.assertEqual(children[0].ppid(), os.getpid()) + + def test_children_recursive(self): + # here we create a subprocess which creates another one as in: + # A (parent) -> B (child) -> C (grandchild) + s = "import subprocess, os, sys, time;" + s += "PYTHON = os.path.realpath(sys.executable);" + s += "cmd = [PYTHON, '-c', 'import time; time.sleep(60);'];" + s += "subprocess.Popen(cmd);" + s += "time.sleep(60);" + get_test_subprocess(cmd=[PYTHON, "-c", s]) + p = psutil.Process() + self.assertEqual(len(p.children(recursive=False)), 1) + # give the grandchild some time to start + stop_at = time.time() + GLOBAL_TIMEOUT + while time.time() < stop_at: + children = p.children(recursive=True) + if len(children) > 1: + break + self.assertEqual(len(children), 2) + self.assertEqual(children[0].ppid(), os.getpid()) + self.assertEqual(children[1].ppid(), children[0].pid) + + def test_children_duplicates(self): + # find the process which has the highest number of children + table = collections.defaultdict(int) + for p in psutil.process_iter(): + try: + table[p.ppid()] += 1 + except psutil.Error: + pass + # this is the one, now let's make sure there are no duplicates + pid = sorted(table.items(), key=lambda x: x[1])[-1][0] + p = psutil.Process(pid) + try: + c = p.children(recursive=True) + except psutil.AccessDenied: # windows + pass + else: + self.assertEqual(len(c), len(set(c))) + + def test_suspend_resume(self): + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.suspend() + for x in range(100): + if p.status() == psutil.STATUS_STOPPED: + break + time.sleep(0.01) + p.resume() + self.assertNotEqual(p.status(), psutil.STATUS_STOPPED) + + def test_invalid_pid(self): + self.assertRaises(TypeError, psutil.Process, "1") + self.assertRaises(ValueError, psutil.Process, -1) + + def test_as_dict(self): + p = psutil.Process() + d = p.as_dict(attrs=['exe', 'name']) + self.assertEqual(sorted(d.keys()), ['exe', 'name']) + + p = psutil.Process(min(psutil.pids())) + d = p.as_dict(attrs=['connections'], ad_value='foo') + if not isinstance(d['connections'], list): + self.assertEqual(d['connections'], 'foo') + + # Test ad_value is set on AccessDenied. + with mock.patch('psutil.Process.nice', create=True, + side_effect=psutil.AccessDenied): + self.assertEqual( + p.as_dict(attrs=["nice"], ad_value=1), {"nice": 1}) + + # Test that NoSuchProcess bubbles up. + with mock.patch('psutil.Process.nice', create=True, + side_effect=psutil.NoSuchProcess(p.pid, "name")): + self.assertRaises( + psutil.NoSuchProcess, p.as_dict, attrs=["nice"]) + + # Test that ZombieProcess is swallowed. + with mock.patch('psutil.Process.nice', create=True, + side_effect=psutil.ZombieProcess(p.pid, "name")): + self.assertEqual( + p.as_dict(attrs=["nice"], ad_value="foo"), {"nice": "foo"}) + + # By default APIs raising NotImplementedError are + # supposed to be skipped. + with mock.patch('psutil.Process.nice', create=True, + side_effect=NotImplementedError): + d = p.as_dict() + self.assertNotIn('nice', list(d.keys())) + # ...unless the user explicitly asked for some attr. + with self.assertRaises(NotImplementedError): + p.as_dict(attrs=["nice"]) + + # errors + with self.assertRaises(TypeError): + p.as_dict('name') + with self.assertRaises(ValueError): + p.as_dict(['foo']) + with self.assertRaises(ValueError): + p.as_dict(['foo', 'bar']) + + def test_oneshot(self): + with mock.patch("psutil._psplatform.Process.cpu_times") as m: + p = psutil.Process() + with p.oneshot(): + p.cpu_times() + p.cpu_times() + self.assertEqual(m.call_count, 1) + + with mock.patch("psutil._psplatform.Process.cpu_times") as m: + p.cpu_times() + p.cpu_times() + self.assertEqual(m.call_count, 2) + + def test_oneshot_twice(self): + # Test the case where the ctx manager is __enter__ed twice. + # The second __enter__ is supposed to resut in a NOOP. + with mock.patch("psutil._psplatform.Process.cpu_times") as m1: + with mock.patch("psutil._psplatform.Process.oneshot_enter") as m2: + p = psutil.Process() + with p.oneshot(): + p.cpu_times() + p.cpu_times() + with p.oneshot(): + p.cpu_times() + p.cpu_times() + self.assertEqual(m1.call_count, 1) + self.assertEqual(m2.call_count, 1) + + with mock.patch("psutil._psplatform.Process.cpu_times") as m: + p.cpu_times() + p.cpu_times() + self.assertEqual(m.call_count, 2) + + def test_halfway_terminated_process(self): + # Test that NoSuchProcess exception gets raised in case the + # process dies after we create the Process object. + # Example: + # >>> proc = Process(1234) + # >>> time.sleep(2) # time-consuming task, process dies in meantime + # >>> proc.name() + # Refers to Issue #15 + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.terminate() + p.wait() + if WINDOWS: + call_until(psutil.pids, "%s not in ret" % p.pid) + self.assertFalse(p.is_running()) + # self.assertFalse(p.pid in psutil.pids(), msg="retcode = %s" % + # retcode) + + excluded_names = ['pid', 'is_running', 'wait', 'create_time', + 'oneshot', 'memory_info_ex'] + if LINUX and not RLIMIT_SUPPORT: + excluded_names.append('rlimit') + for name in dir(p): + if (name.startswith('_') or + name in excluded_names): + continue + try: + meth = getattr(p, name) + # get/set methods + if name == 'nice': + if POSIX: + ret = meth(1) + else: + ret = meth(psutil.NORMAL_PRIORITY_CLASS) + elif name == 'ionice': + ret = meth() + ret = meth(2) + elif name == 'rlimit': + ret = meth(psutil.RLIMIT_NOFILE) + ret = meth(psutil.RLIMIT_NOFILE, (5, 5)) + elif name == 'cpu_affinity': + ret = meth() + ret = meth([0]) + elif name == 'send_signal': + ret = meth(signal.SIGTERM) + else: + ret = meth() + except psutil.ZombieProcess: + self.fail("ZombieProcess for %r was not supposed to happen" % + name) + except psutil.NoSuchProcess: + pass + except psutil.AccessDenied: + if OPENBSD and name in ('threads', 'num_threads'): + pass + else: + raise + except NotImplementedError: + pass + else: + self.fail( + "NoSuchProcess exception not raised for %r, retval=%s" % ( + name, ret)) + + @unittest.skipUnless(POSIX, 'POSIX only') + def test_zombie_process(self): + def succeed_or_zombie_p_exc(fun, *args, **kwargs): + try: + return fun(*args, **kwargs) + except (psutil.ZombieProcess, psutil.AccessDenied): + pass + + # Note: in this test we'll be creating two sub processes. + # Both of them are supposed to be freed / killed by + # reap_children() as they are attributable to 'us' + # (os.getpid()) via children(recursive=True). + unix_file = tempfile.mktemp(prefix=TESTFILE_PREFIX) if OSX else TESTFN + src = textwrap.dedent("""\ + import os, sys, time, socket, contextlib + child_pid = os.fork() + if child_pid > 0: + time.sleep(3000) + else: + # this is the zombie process + s = socket.socket(socket.AF_UNIX) + with contextlib.closing(s): + s.connect('%s') + if sys.version_info < (3, ): + pid = str(os.getpid()) + else: + pid = bytes(str(os.getpid()), 'ascii') + s.sendall(pid) + """ % unix_file) + with contextlib.closing(socket.socket(socket.AF_UNIX)) as sock: + try: + sock.settimeout(GLOBAL_TIMEOUT) + sock.bind(unix_file) + sock.listen(1) + pyrun(src) + conn, _ = sock.accept() + self.addCleanup(conn.close) + select.select([conn.fileno()], [], [], GLOBAL_TIMEOUT) + zpid = int(conn.recv(1024)) + zproc = psutil.Process(zpid) + call_until(lambda: zproc.status(), + "ret == psutil.STATUS_ZOMBIE") + # A zombie process should always be instantiable + zproc = psutil.Process(zpid) + # ...and at least its status always be querable + self.assertEqual(zproc.status(), psutil.STATUS_ZOMBIE) + # ...and it should be considered 'running' + self.assertTrue(zproc.is_running()) + # ...and as_dict() shouldn't crash + zproc.as_dict() + # if cmdline succeeds it should be an empty list + ret = succeed_or_zombie_p_exc(zproc.suspend) + if ret is not None: + self.assertEqual(ret, []) + + if hasattr(zproc, "rlimit"): + succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE) + succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE, + (5, 5)) + # set methods + succeed_or_zombie_p_exc(zproc.parent) + if hasattr(zproc, 'cpu_affinity'): + succeed_or_zombie_p_exc(zproc.cpu_affinity, [0]) + succeed_or_zombie_p_exc(zproc.nice, 0) + if hasattr(zproc, 'ionice'): + if LINUX: + succeed_or_zombie_p_exc(zproc.ionice, 2, 0) + else: + succeed_or_zombie_p_exc(zproc.ionice, 0) # Windows + if hasattr(zproc, 'rlimit'): + succeed_or_zombie_p_exc(zproc.rlimit, + psutil.RLIMIT_NOFILE, (5, 5)) + succeed_or_zombie_p_exc(zproc.suspend) + succeed_or_zombie_p_exc(zproc.resume) + succeed_or_zombie_p_exc(zproc.terminate) + succeed_or_zombie_p_exc(zproc.kill) + + # ...its parent should 'see' it + # edit: not true on BSD and OSX + # descendants = [x.pid for x in psutil.Process().children( + # recursive=True)] + # self.assertIn(zpid, descendants) + # XXX should we also assume ppid be usable? Note: this + # would be an important use case as the only way to get + # rid of a zombie is to kill its parent. + # self.assertEqual(zpid.ppid(), os.getpid()) + # ...and all other APIs should be able to deal with it + self.assertTrue(psutil.pid_exists(zpid)) + self.assertIn(zpid, psutil.pids()) + self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) + psutil._pmap = {} + self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) + finally: + reap_children(recursive=True) + + def test_pid_0(self): + # Process(0) is supposed to work on all platforms except Linux + if 0 not in psutil.pids(): + self.assertRaises(psutil.NoSuchProcess, psutil.Process, 0) + return + + # test all methods + p = psutil.Process(0) + for name in psutil._as_dict_attrnames: + if name == 'pid': + continue + meth = getattr(p, name) + try: + ret = meth() + except psutil.AccessDenied: + pass + else: + if name in ("uids", "gids"): + self.assertEqual(ret.real, 0) + elif name == "username": + if POSIX: + self.assertEqual(p.username(), 'root') + elif WINDOWS: + self.assertEqual(p.username(), 'NT AUTHORITY\\SYSTEM') + elif name == "name": + assert name, name + + if hasattr(p, 'rlimit'): + try: + p.rlimit(psutil.RLIMIT_FSIZE) + except psutil.AccessDenied: + pass + + p.as_dict() + + if not OPENBSD: + self.assertIn(0, psutil.pids()) + self.assertTrue(psutil.pid_exists(0)) + + def test_Popen(self): + # XXX this test causes a ResourceWarning on Python 3 because + # psutil.__subproc instance doesn't get propertly freed. + # Not sure what to do though. + cmd = [PYTHON, "-c", "import time; time.sleep(60);"] + proc = psutil.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + try: + proc.name() + proc.cpu_times() + proc.stdin + self.assertTrue(dir(proc)) + self.assertRaises(AttributeError, getattr, proc, 'foo') + finally: + proc.kill() + proc.wait() + + def test_Popen_ctx_manager(self): + with psutil.Popen([PYTHON, "-V"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE) as proc: + pass + assert proc.stdout.closed + assert proc.stderr.closed + assert proc.stdin.closed + + @unittest.skipUnless(hasattr(psutil.Process, "environ"), + "platform not supported") + def test_environ(self): + self.maxDiff = None + p = psutil.Process() + d = p.environ() + d2 = os.environ.copy() + + removes = [] + if OSX: + removes.extend([ + "__CF_USER_TEXT_ENCODING", + "VERSIONER_PYTHON_PREFER_32_BIT", + "VERSIONER_PYTHON_VERSION"]) + if LINUX or OSX: + removes.extend(['PLAT']) + if TOX: + removes.extend(['HOME']) + for key in removes: + d.pop(key, None) + d2.pop(key, None) + + self.assertEqual(d, d2) + + @unittest.skipUnless(hasattr(psutil.Process, "environ"), + "platform not supported") + @unittest.skipUnless(POSIX, "posix only") + def test_weird_environ(self): + # environment variables can contain values without an equals sign + code = textwrap.dedent(""" + #include + #include + char * const argv[] = {"cat", 0}; + char * const envp[] = {"A=1", "X", "C=3", 0}; + int main(void) { + /* Close stderr on exec so parent can wait for the execve to + * finish. */ + if (fcntl(2, F_SETFD, FD_CLOEXEC) != 0) + return 0; + return execve("/bin/cat", argv, envp); + } + """) + path = TESTFN + create_exe(path, c_code=code) + self.addCleanup(safe_rmpath, path) + sproc = get_test_subprocess([path], + stdin=subprocess.PIPE, + stderr=subprocess.PIPE) + p = psutil.Process(sproc.pid) + wait_for_pid(p.pid) + self.assertTrue(p.is_running()) + # Wait for process to exec or exit. + self.assertEqual(sproc.stderr.read(), b"") + self.assertEqual(p.environ(), {"A": "1", "C": "3"}) + sproc.communicate() + self.assertEqual(sproc.returncode, 0) + + +# =================================================================== +# --- Featch all processes test +# =================================================================== + +class TestFetchAllProcesses(unittest.TestCase): + """Test which iterates over all running processes and performs + some sanity checks against Process API's returned values. + """ + + def setUp(self): + if POSIX: + import pwd + import grp + users = pwd.getpwall() + groups = grp.getgrall() + self.all_uids = set([x.pw_uid for x in users]) + self.all_usernames = set([x.pw_name for x in users]) + self.all_gids = set([x.gr_gid for x in groups]) + + def test_fetch_all(self): + valid_procs = 0 + excluded_names = set([ + 'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', + 'as_dict', 'cpu_percent', 'parent', 'children', 'pid', + 'memory_info_ex', 'oneshot', + ]) + if LINUX and not RLIMIT_SUPPORT: + excluded_names.add('rlimit') + attrs = [] + for name in dir(psutil.Process): + if name.startswith("_"): + continue + if name in excluded_names: + continue + attrs.append(name) + + default = object() + failures = [] + for p in psutil.process_iter(): + with p.oneshot(): + for name in attrs: + ret = default + try: + args = () + attr = getattr(p, name, None) + if attr is not None and callable(attr): + if name == 'rlimit': + args = (psutil.RLIMIT_NOFILE,) + ret = attr(*args) + else: + ret = attr + valid_procs += 1 + except NotImplementedError: + msg = "%r was skipped because not implemented" % ( + self.__class__.__name__ + '.test_' + name) + warn(msg) + except (psutil.NoSuchProcess, psutil.AccessDenied) as err: + self.assertEqual(err.pid, p.pid) + if err.name: + # make sure exception's name attr is set + # with the actual process name + self.assertEqual(err.name, p.name()) + self.assertTrue(str(err)) + self.assertTrue(err.msg) + except Exception as err: + s = '\n' + '=' * 70 + '\n' + s += "FAIL: test_%s (proc=%s" % (name, p) + if ret != default: + s += ", ret=%s)" % repr(ret) + s += ')\n' + s += '-' * 70 + s += "\n%s" % traceback.format_exc() + s = "\n".join((" " * 4) + i for i in s.splitlines()) + s += '\n' + failures.append(s) + break + else: + if ret not in (0, 0.0, [], None, '', {}): + assert ret, ret + meth = getattr(self, name) + meth(ret, p) + + if failures: + self.fail(''.join(failures)) + + # we should always have a non-empty list, not including PID 0 etc. + # special cases. + self.assertTrue(valid_procs > 0) + + def cmdline(self, ret, proc): + pass + + def exe(self, ret, proc): + if not ret: + self.assertEqual(ret, '') + else: + assert os.path.isabs(ret), ret + # Note: os.stat() may return False even if the file is there + # hence we skip the test, see: + # http://stackoverflow.com/questions/3112546/os-path-exists-lies + if POSIX and os.path.isfile(ret): + if hasattr(os, 'access') and hasattr(os, "X_OK"): + # XXX may fail on OSX + self.assertTrue(os.access(ret, os.X_OK)) + + def ppid(self, ret, proc): + self.assertTrue(ret >= 0) + + def name(self, ret, proc): + self.assertIsInstance(ret, (str, unicode)) + self.assertTrue(ret) + + def create_time(self, ret, proc): + try: + self.assertGreaterEqual(ret, 0) + except AssertionError: + if OPENBSD and proc.status == psutil.STATUS_ZOMBIE: + pass + else: + raise + # this can't be taken for granted on all platforms + # self.assertGreaterEqual(ret, psutil.boot_time()) + # make sure returned value can be pretty printed + # with strftime + time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret)) + + def uids(self, ret, proc): + for uid in ret: + self.assertGreaterEqual(uid, 0) + self.assertIn(uid, self.all_uids) + + def gids(self, ret, proc): + # note: testing all gids as above seems not to be reliable for + # gid == 30 (nodoby); not sure why. + for gid in ret: + if not OSX and not NETBSD: + self.assertGreaterEqual(gid, 0) + self.assertIn(gid, self.all_gids) + + def username(self, ret, proc): + self.assertTrue(ret) + if POSIX: + self.assertIn(ret, self.all_usernames) + + def status(self, ret, proc): + self.assertTrue(ret != "") + self.assertTrue(ret != '?') + self.assertIn(ret, VALID_PROC_STATUSES) + + def io_counters(self, ret, proc): + for field in ret: + if field != -1: + self.assertTrue(field >= 0) + + def ionice(self, ret, proc): + if LINUX: + self.assertTrue(ret.ioclass >= 0) + self.assertTrue(ret.value >= 0) + else: + self.assertTrue(ret >= 0) + self.assertIn(ret, (0, 1, 2)) + + def num_threads(self, ret, proc): + self.assertTrue(ret >= 1) + + def threads(self, ret, proc): + for t in ret: + self.assertTrue(t.id >= 0) + self.assertTrue(t.user_time >= 0) + self.assertTrue(t.system_time >= 0) + + def cpu_times(self, ret, proc): + self.assertTrue(ret.user >= 0) + self.assertTrue(ret.system >= 0) + + def cpu_num(self, ret, proc): + self.assertGreaterEqual(ret, 0) + if psutil.cpu_count() == 1: + self.assertEqual(ret, 0) + self.assertIn(ret, range(psutil.cpu_count())) + + def memory_info(self, ret, proc): + for name in ret._fields: + self.assertGreaterEqual(getattr(ret, name), 0) + if POSIX and ret.vms != 0: + # VMS is always supposed to be the highest + for name in ret._fields: + if name != 'vms': + value = getattr(ret, name) + assert ret.vms > value, ret + elif WINDOWS: + assert ret.peak_wset >= ret.wset, ret + assert ret.peak_paged_pool >= ret.paged_pool, ret + assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret + assert ret.peak_pagefile >= ret.pagefile, ret + + def memory_full_info(self, ret, proc): + total = psutil.virtual_memory().total + for name in ret._fields: + value = getattr(ret, name) + self.assertGreaterEqual(value, 0, msg=(name, value)) + self.assertLessEqual(value, total, msg=(name, value, total)) + + if LINUX: + self.assertGreaterEqual(ret.pss, ret.uss) + + def open_files(self, ret, proc): + for f in ret: + if WINDOWS: + assert f.fd == -1, f + else: + self.assertIsInstance(f.fd, int) + if LINUX: + self.assertIsInstance(f.position, int) + self.assertGreaterEqual(f.position, 0) + self.assertIn(f.mode, ('r', 'w', 'a', 'r+', 'a+')) + self.assertGreater(f.flags, 0) + if BSD and not f.path: + # XXX see: https://github.com/giampaolo/psutil/issues/595 + continue + assert os.path.isabs(f.path), f + assert os.path.isfile(f.path), f + + def num_fds(self, ret, proc): + self.assertTrue(ret >= 0) + + def connections(self, ret, proc): + self.assertEqual(len(ret), len(set(ret))) + for conn in ret: + check_connection_ntuple(conn) + + def cwd(self, ret, proc): + if ret is not None: # BSD may return None + assert os.path.isabs(ret), ret + try: + st = os.stat(ret) + except OSError as err: + if WINDOWS and err.errno in \ + psutil._psplatform.ACCESS_DENIED_SET: + pass + # directory has been removed in mean time + elif err.errno != errno.ENOENT: + raise + else: + self.assertTrue(stat.S_ISDIR(st.st_mode)) + + def memory_percent(self, ret, proc): + assert 0 <= ret <= 100, ret + + def is_running(self, ret, proc): + self.assertTrue(ret) + + def cpu_affinity(self, ret, proc): + assert ret != [], ret + cpus = range(psutil.cpu_count()) + for n in ret: + self.assertIn(n, cpus) + + def terminal(self, ret, proc): + if ret is not None: + assert os.path.isabs(ret), ret + assert os.path.exists(ret), ret + + def memory_maps(self, ret, proc): + for nt in ret: + for fname in nt._fields: + value = getattr(nt, fname) + if fname == 'path': + if not value.startswith('['): + assert os.path.isabs(nt.path), nt.path + # commented as on Linux we might get + # '/foo/bar (deleted)' + # assert os.path.exists(nt.path), nt.path + elif fname in ('addr', 'perms'): + self.assertTrue(value) + else: + self.assertIsInstance(value, (int, long)) + assert value >= 0, value + + def num_handles(self, ret, proc): + if WINDOWS: + self.assertGreaterEqual(ret, 0) + else: + self.assertGreaterEqual(ret, 0) + + def nice(self, ret, proc): + if POSIX: + assert -20 <= ret <= 20, ret + else: + priorities = [getattr(psutil, x) for x in dir(psutil) + if x.endswith('_PRIORITY_CLASS')] + self.assertIn(ret, priorities) + + def num_ctx_switches(self, ret, proc): + self.assertGreaterEqual(ret.voluntary, 0) + self.assertGreaterEqual(ret.involuntary, 0) + + def rlimit(self, ret, proc): + self.assertEqual(len(ret), 2) + self.assertGreaterEqual(ret[0], -1) + self.assertGreaterEqual(ret[1], -1) + + def environ(self, ret, proc): + self.assertIsInstance(ret, dict) + + +# =================================================================== +# --- Limited user tests +# =================================================================== + + +if POSIX and os.getuid() == 0: + class LimitedUserTestCase(TestProcess): + """Repeat the previous tests by using a limited user. + Executed only on UNIX and only if the user who run the test script + is root. + """ + # the uid/gid the test suite runs under + if hasattr(os, 'getuid'): + PROCESS_UID = os.getuid() + PROCESS_GID = os.getgid() + + def __init__(self, *args, **kwargs): + TestProcess.__init__(self, *args, **kwargs) + # re-define all existent test methods in order to + # ignore AccessDenied exceptions + for attr in [x for x in dir(self) if x.startswith('test')]: + meth = getattr(self, attr) + + def test_(self): + try: + meth() + except psutil.AccessDenied: + pass + setattr(self, attr, types.MethodType(test_, self)) + + def setUp(self): + safe_rmpath(TESTFN) + TestProcess.setUp(self) + os.setegid(1000) + os.seteuid(1000) + + def tearDown(self): + os.setegid(self.PROCESS_UID) + os.seteuid(self.PROCESS_GID) + TestProcess.tearDown(self) + + def test_nice(self): + try: + psutil.Process().nice(-1) + except psutil.AccessDenied: + pass + else: + self.fail("exception not raised") + + def test_zombie_process(self): + # causes problems if test test suite is run as root + pass + + +# =================================================================== +# --- Unicode tests +# =================================================================== + + +class TestUnicode(unittest.TestCase): + """ + Make sure that APIs returning a string are able to handle unicode, + see: https://github.com/giampaolo/psutil/issues/655 + """ + uexe = TESTFN + 'èfile' + udir = TESTFN + 'èdir' + + @classmethod + def setUpClass(cls): + safe_rmpath(cls.uexe) + safe_rmpath(cls.udir) + create_exe(cls.uexe) + os.mkdir(cls.udir) + + @classmethod + def tearDownClass(cls): + if not APPVEYOR: + safe_rmpath(cls.uexe) + safe_rmpath(cls.udir) + + def setUp(self): + reap_children() + + tearDown = setUp + + def test_proc_exe(self): + subp = get_test_subprocess(cmd=[self.uexe]) + p = psutil.Process(subp.pid) + self.assertIsInstance(p.name(), str) + if not OSX and TRAVIS: + self.assertEqual(p.exe(), self.uexe) + else: + p.exe() + + def test_proc_name(self): + subp = get_test_subprocess(cmd=[self.uexe]) + if WINDOWS: + # XXX: why is this like this? + from psutil._pswindows import py2_strencode + name = py2_strencode(psutil._psplatform.cext.proc_name(subp.pid)) + else: + name = psutil.Process(subp.pid).name() + if not OSX and TRAVIS: + self.assertEqual(name, os.path.basename(self.uexe)) + + def test_proc_cmdline(self): + subp = get_test_subprocess(cmd=[self.uexe]) + p = psutil.Process(subp.pid) + self.assertIsInstance("".join(p.cmdline()), str) + if not OSX and TRAVIS: + self.assertEqual(p.cmdline(), [self.uexe]) + else: + p.cmdline() + + def test_proc_cwd(self): + with chdir(self.udir): + p = psutil.Process() + self.assertIsInstance(p.cwd(), str) + if not OSX and TRAVIS: + self.assertEqual(p.cwd(), self.udir) + else: + p.cwd() + + # @unittest.skipIf(APPVEYOR, "unreliable on APPVEYOR") + def test_proc_open_files(self): + p = psutil.Process() + start = set(p.open_files()) + with open(self.uexe, 'rb'): + new = set(p.open_files()) + path = (new - start).pop().path + if BSD and not path: + # XXX + # see https://github.com/giampaolo/psutil/issues/595 + self.skipTest("open_files on BSD is broken") + self.assertIsInstance(path, str) + if not OSX and TRAVIS: + self.assertEqual(os.path.normcase(path), + os.path.normcase(self.uexe)) + + @unittest.skipUnless(hasattr(psutil.Process, "environ"), + "platform not supported") + def test_proc_environ(self): + env = os.environ.copy() + env['FUNNY_ARG'] = self.uexe + sproc = get_test_subprocess(env=env) + p = psutil.Process(sproc.pid) + if WINDOWS and not PY3: + uexe = self.uexe.decode(sys.getfilesystemencoding()) + else: + uexe = self.uexe + if not OSX and TRAVIS: + self.assertEqual(p.environ()['FUNNY_ARG'], uexe) + else: + p.environ() + + def test_disk_usage(self): + psutil.disk_usage(self.udir) + + +class TestInvalidUnicode(TestUnicode): + """Test handling of invalid utf8 data.""" + if PY3: + uexe = (TESTFN.encode('utf8') + b"f\xc0\x80").decode( + 'utf8', 'surrogateescape') + udir = (TESTFN.encode('utf8') + b"d\xc0\x80").decode( + 'utf8', 'surrogateescape') + else: + uexe = TESTFN + b"f\xc0\x80" + udir = TESTFN + b"d\xc0\x80" + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_sunos.py b/pipenv/vendor/psutil/tests/test_sunos.py new file mode 100755 index 00000000..0e770444 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_sunos.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Sun OS specific tests.""" + +import os + +import psutil +from psutil import SUNOS +from psutil.tests import run_test_module_by_name +from psutil.tests import sh +from psutil.tests import unittest + + +@unittest.skipUnless(SUNOS, "SUNOS only") +class SunOSSpecificTestCase(unittest.TestCase): + + def test_swap_memory(self): + out = sh('env PATH=/usr/sbin:/sbin:%s swap -l' % os.environ['PATH']) + lines = out.strip().split('\n')[1:] + if not lines: + raise ValueError('no swap device(s) configured') + total = free = 0 + for line in lines: + line = line.split() + t, f = line[-2:] + total += int(int(t) * 512) + free += int(int(f) * 512) + used = total - free + + psutil_swap = psutil.swap_memory() + self.assertEqual(psutil_swap.total, total) + self.assertEqual(psutil_swap.used, used) + self.assertEqual(psutil_swap.free, free) + + def test_cpu_count(self): + out = sh("/usr/sbin/psrinfo") + self.assertEqual(psutil.cpu_count(), len(out.split('\n'))) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_system.py b/pipenv/vendor/psutil/tests/test_system.py new file mode 100755 index 00000000..013ae8e3 --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_system.py @@ -0,0 +1,813 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Tests for system APIS.""" + +import contextlib +import datetime +import errno +import os +import pprint +import shutil +import signal +import socket +import sys +import tempfile +import time + +import psutil +from psutil import BSD +from psutil import FREEBSD +from psutil import LINUX +from psutil import NETBSD +from psutil import OPENBSD +from psutil import OSX +from psutil import POSIX +from psutil import SUNOS +from psutil import WINDOWS +from psutil._compat import long +from psutil._compat import unicode +from psutil.tests import AF_INET6 +from psutil.tests import APPVEYOR +from psutil.tests import check_net_address +from psutil.tests import DEVNULL +from psutil.tests import enum +from psutil.tests import get_test_subprocess +from psutil.tests import mock +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import safe_rmpath +from psutil.tests import skip_on_access_denied +from psutil.tests import TESTFN +from psutil.tests import TESTFN_UNICODE +from psutil.tests import TRAVIS +from psutil.tests import unittest + + +# =================================================================== +# --- System-related API tests +# =================================================================== + + +class TestSystemAPIs(unittest.TestCase): + """Tests for system-related APIs.""" + + def setUp(self): + safe_rmpath(TESTFN) + + def tearDown(self): + reap_children() + + def test_process_iter(self): + self.assertIn(os.getpid(), [x.pid for x in psutil.process_iter()]) + sproc = get_test_subprocess() + self.assertIn(sproc.pid, [x.pid for x in psutil.process_iter()]) + p = psutil.Process(sproc.pid) + p.kill() + p.wait() + self.assertNotIn(sproc.pid, [x.pid for x in psutil.process_iter()]) + + with mock.patch('psutil.Process', + side_effect=psutil.NoSuchProcess(os.getpid())): + self.assertEqual(list(psutil.process_iter()), []) + with mock.patch('psutil.Process', + side_effect=psutil.AccessDenied(os.getpid())): + with self.assertRaises(psutil.AccessDenied): + list(psutil.process_iter()) + + def test_wait_procs(self): + def callback(p): + pids.append(p.pid) + + pids = [] + sproc1 = get_test_subprocess() + sproc2 = get_test_subprocess() + sproc3 = get_test_subprocess() + procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] + self.assertRaises(ValueError, psutil.wait_procs, procs, timeout=-1) + self.assertRaises(TypeError, psutil.wait_procs, procs, callback=1) + t = time.time() + gone, alive = psutil.wait_procs(procs, timeout=0.01, callback=callback) + + self.assertLess(time.time() - t, 0.5) + self.assertEqual(gone, []) + self.assertEqual(len(alive), 3) + self.assertEqual(pids, []) + for p in alive: + self.assertFalse(hasattr(p, 'returncode')) + + @retry_before_failing(30) + def test(procs, callback): + gone, alive = psutil.wait_procs(procs, timeout=0.03, + callback=callback) + self.assertEqual(len(gone), 1) + self.assertEqual(len(alive), 2) + return gone, alive + + sproc3.terminate() + gone, alive = test(procs, callback) + self.assertIn(sproc3.pid, [x.pid for x in gone]) + if POSIX: + self.assertEqual(gone.pop().returncode, -signal.SIGTERM) + else: + self.assertEqual(gone.pop().returncode, 1) + self.assertEqual(pids, [sproc3.pid]) + for p in alive: + self.assertFalse(hasattr(p, 'returncode')) + + @retry_before_failing(30) + def test(procs, callback): + gone, alive = psutil.wait_procs(procs, timeout=0.03, + callback=callback) + self.assertEqual(len(gone), 3) + self.assertEqual(len(alive), 0) + return gone, alive + + sproc1.terminate() + sproc2.terminate() + gone, alive = test(procs, callback) + self.assertEqual(set(pids), set([sproc1.pid, sproc2.pid, sproc3.pid])) + for p in gone: + self.assertTrue(hasattr(p, 'returncode')) + + def test_wait_procs_no_timeout(self): + sproc1 = get_test_subprocess() + sproc2 = get_test_subprocess() + sproc3 = get_test_subprocess() + procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] + for p in procs: + p.terminate() + gone, alive = psutil.wait_procs(procs) + + def test_boot_time(self): + bt = psutil.boot_time() + self.assertIsInstance(bt, float) + self.assertGreater(bt, 0) + self.assertLess(bt, time.time()) + + @unittest.skipUnless(POSIX, 'POSIX only') + def test_PAGESIZE(self): + # pagesize is used internally to perform different calculations + # and it's determined by using SC_PAGE_SIZE; make sure + # getpagesize() returns the same value. + import resource + self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize()) + + def test_virtual_memory(self): + mem = psutil.virtual_memory() + assert mem.total > 0, mem + assert mem.available > 0, mem + assert 0 <= mem.percent <= 100, mem + assert mem.used > 0, mem + assert mem.free >= 0, mem + for name in mem._fields: + value = getattr(mem, name) + if name != 'percent': + self.assertIsInstance(value, (int, long)) + if name != 'total': + if not value >= 0: + self.fail("%r < 0 (%s)" % (name, value)) + if value > mem.total: + self.fail("%r > total (total=%s, %s=%s)" + % (name, mem.total, name, value)) + + def test_swap_memory(self): + mem = psutil.swap_memory() + assert mem.total >= 0, mem + assert mem.used >= 0, mem + if mem.total > 0: + # likely a system with no swap partition + assert mem.free > 0, mem + else: + assert mem.free == 0, mem + assert 0 <= mem.percent <= 100, mem + assert mem.sin >= 0, mem + assert mem.sout >= 0, mem + + def test_pid_exists(self): + sproc = get_test_subprocess() + self.assertTrue(psutil.pid_exists(sproc.pid)) + p = psutil.Process(sproc.pid) + p.kill() + p.wait() + self.assertFalse(psutil.pid_exists(sproc.pid)) + self.assertFalse(psutil.pid_exists(-1)) + self.assertEqual(psutil.pid_exists(0), 0 in psutil.pids()) + # pid 0 + psutil.pid_exists(0) == 0 in psutil.pids() + + def test_pid_exists_2(self): + reap_children() + pids = psutil.pids() + for pid in pids: + try: + assert psutil.pid_exists(pid) + except AssertionError: + # in case the process disappeared in meantime fail only + # if it is no longer in psutil.pids() + time.sleep(.1) + if pid in psutil.pids(): + self.fail(pid) + pids = range(max(pids) + 5000, max(pids) + 6000) + for pid in pids: + self.assertFalse(psutil.pid_exists(pid), msg=pid) + + def test_pids(self): + plist = [x.pid for x in psutil.process_iter()] + pidlist = psutil.pids() + self.assertEqual(plist.sort(), pidlist.sort()) + # make sure every pid is unique + self.assertEqual(len(pidlist), len(set(pidlist))) + + def test_test(self): + # test for psutil.test() function + stdout = sys.stdout + sys.stdout = DEVNULL + try: + psutil.test() + finally: + sys.stdout = stdout + + def test_cpu_count(self): + logical = psutil.cpu_count() + self.assertEqual(logical, len(psutil.cpu_times(percpu=True))) + self.assertGreaterEqual(logical, 1) + # + if os.path.exists("/proc/cpuinfo"): + with open("/proc/cpuinfo") as fd: + cpuinfo_data = fd.read() + if "physical id" not in cpuinfo_data: + raise unittest.SkipTest("cpuinfo doesn't include physical id") + physical = psutil.cpu_count(logical=False) + self.assertGreaterEqual(physical, 1) + self.assertGreaterEqual(logical, physical) + + def test_cpu_times(self): + # Check type, value >= 0, str(). + total = 0 + times = psutil.cpu_times() + sum(times) + for cp_time in times: + self.assertIsInstance(cp_time, float) + self.assertGreaterEqual(cp_time, 0.0) + total += cp_time + self.assertEqual(total, sum(times)) + str(times) + # CPU times are always supposed to increase over time + # or at least remain the same and that's because time + # cannot go backwards. + # Surprisingly sometimes this might not be the case (at + # least on Windows and Linux), see: + # https://github.com/giampaolo/psutil/issues/392 + # https://github.com/giampaolo/psutil/issues/645 + # if not WINDOWS: + # last = psutil.cpu_times() + # for x in range(100): + # new = psutil.cpu_times() + # for field in new._fields: + # new_t = getattr(new, field) + # last_t = getattr(last, field) + # self.assertGreaterEqual(new_t, last_t, + # msg="%s %s" % (new_t, last_t)) + # last = new + + def test_cpu_times_time_increases(self): + # Make sure time increases between calls. + t1 = sum(psutil.cpu_times()) + time.sleep(0.1) + t2 = sum(psutil.cpu_times()) + difference = t2 - t1 + if not difference >= 0.05: + self.fail("difference %s" % difference) + + def test_per_cpu_times(self): + # Check type, value >= 0, str(). + for times in psutil.cpu_times(percpu=True): + total = 0 + sum(times) + for cp_time in times: + self.assertIsInstance(cp_time, float) + self.assertGreaterEqual(cp_time, 0.0) + total += cp_time + self.assertEqual(total, sum(times)) + str(times) + self.assertEqual(len(psutil.cpu_times(percpu=True)[0]), + len(psutil.cpu_times(percpu=False))) + + # Note: in theory CPU times are always supposed to increase over + # time or remain the same but never go backwards. In practice + # sometimes this is not the case. + # This issue seemd to be afflict Windows: + # https://github.com/giampaolo/psutil/issues/392 + # ...but it turns out also Linux (rarely) behaves the same. + # last = psutil.cpu_times(percpu=True) + # for x in range(100): + # new = psutil.cpu_times(percpu=True) + # for index in range(len(new)): + # newcpu = new[index] + # lastcpu = last[index] + # for field in newcpu._fields: + # new_t = getattr(newcpu, field) + # last_t = getattr(lastcpu, field) + # self.assertGreaterEqual( + # new_t, last_t, msg="%s %s" % (lastcpu, newcpu)) + # last = new + + def test_per_cpu_times_2(self): + # Simulate some work load then make sure time have increased + # between calls. + tot1 = psutil.cpu_times(percpu=True) + stop_at = time.time() + 0.1 + while True: + if time.time() >= stop_at: + break + tot2 = psutil.cpu_times(percpu=True) + for t1, t2 in zip(tot1, tot2): + t1, t2 = sum(t1), sum(t2) + difference = t2 - t1 + if difference >= 0.05: + return + self.fail() + + def test_cpu_times_comparison(self): + # Make sure the sum of all per cpu times is almost equal to + # base "one cpu" times. + base = psutil.cpu_times() + per_cpu = psutil.cpu_times(percpu=True) + summed_values = base._make([sum(num) for num in zip(*per_cpu)]) + for field in base._fields: + self.assertAlmostEqual( + getattr(base, field), getattr(summed_values, field), delta=1) + + def _test_cpu_percent(self, percent, last_ret, new_ret): + try: + self.assertIsInstance(percent, float) + self.assertGreaterEqual(percent, 0.0) + self.assertIsNot(percent, -0.0) + self.assertLessEqual(percent, 100.0 * psutil.cpu_count()) + except AssertionError as err: + raise AssertionError("\n%s\nlast=%s\nnew=%s" % ( + err, pprint.pformat(last_ret), pprint.pformat(new_ret))) + + def test_cpu_percent(self): + last = psutil.cpu_percent(interval=0.001) + for x in range(100): + new = psutil.cpu_percent(interval=None) + self._test_cpu_percent(new, last, new) + last = new + with self.assertRaises(ValueError): + psutil.cpu_percent(interval=-1) + + def test_per_cpu_percent(self): + last = psutil.cpu_percent(interval=0.001, percpu=True) + self.assertEqual(len(last), psutil.cpu_count()) + for x in range(100): + new = psutil.cpu_percent(interval=None, percpu=True) + for percent in new: + self._test_cpu_percent(percent, last, new) + last = new + with self.assertRaises(ValueError): + psutil.cpu_percent(interval=-1, percpu=True) + + def test_cpu_times_percent(self): + last = psutil.cpu_times_percent(interval=0.001) + for x in range(100): + new = psutil.cpu_times_percent(interval=None) + for percent in new: + self._test_cpu_percent(percent, last, new) + self._test_cpu_percent(sum(new), last, new) + last = new + + def test_per_cpu_times_percent(self): + last = psutil.cpu_times_percent(interval=0.001, percpu=True) + self.assertEqual(len(last), psutil.cpu_count()) + for x in range(100): + new = psutil.cpu_times_percent(interval=None, percpu=True) + for cpu in new: + for percent in cpu: + self._test_cpu_percent(percent, last, new) + self._test_cpu_percent(sum(cpu), last, new) + last = new + + def test_per_cpu_times_percent_negative(self): + # see: https://github.com/giampaolo/psutil/issues/645 + psutil.cpu_times_percent(percpu=True) + zero_times = [x._make([0 for x in range(len(x._fields))]) + for x in psutil.cpu_times(percpu=True)] + with mock.patch('psutil.cpu_times', return_value=zero_times): + for cpu in psutil.cpu_times_percent(percpu=True): + for percent in cpu: + self._test_cpu_percent(percent, None, None) + + @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), + "os.statvfs() not available") + def test_disk_usage(self): + usage = psutil.disk_usage(os.getcwd()) + assert usage.total > 0, usage + assert usage.used > 0, usage + assert usage.free > 0, usage + assert usage.total > usage.used, usage + assert usage.total > usage.free, usage + assert 0 <= usage.percent <= 100, usage.percent + if hasattr(shutil, 'disk_usage'): + # py >= 3.3, see: http://bugs.python.org/issue12442 + shutil_usage = shutil.disk_usage(os.getcwd()) + tolerance = 5 * 1024 * 1024 # 5MB + self.assertEqual(usage.total, shutil_usage.total) + self.assertAlmostEqual(usage.free, shutil_usage.free, + delta=tolerance) + self.assertAlmostEqual(usage.used, shutil_usage.used, + delta=tolerance) + + # if path does not exist OSError ENOENT is expected across + # all platforms + fname = tempfile.mktemp() + try: + psutil.disk_usage(fname) + except OSError as err: + if err.args[0] != errno.ENOENT: + raise + else: + self.fail("OSError not raised") + + @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), + "os.statvfs() not available") + def test_disk_usage_unicode(self): + # see: https://github.com/giampaolo/psutil/issues/416 + safe_rmpath(TESTFN_UNICODE) + self.addCleanup(safe_rmpath, TESTFN_UNICODE) + os.mkdir(TESTFN_UNICODE) + psutil.disk_usage(TESTFN_UNICODE) + + @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), + "os.statvfs() not available") + @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") + def test_disk_partitions(self): + # all = False + ls = psutil.disk_partitions(all=False) + # on travis we get: + # self.assertEqual(p.cpu_affinity(), [n]) + # AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7,... != [0] + self.assertTrue(ls, msg=ls) + for disk in ls: + self.assertIsInstance(disk.device, (str, unicode)) + self.assertIsInstance(disk.mountpoint, (str, unicode)) + self.assertIsInstance(disk.fstype, (str, unicode)) + self.assertIsInstance(disk.opts, (str, unicode)) + if WINDOWS and 'cdrom' in disk.opts: + continue + if not POSIX: + assert os.path.exists(disk.device), disk + else: + # we cannot make any assumption about this, see: + # http://goo.gl/p9c43 + disk.device + if SUNOS: + # on solaris apparently mount points can also be files + assert os.path.exists(disk.mountpoint), disk + else: + assert os.path.isdir(disk.mountpoint), disk + assert disk.fstype, disk + + # all = True + ls = psutil.disk_partitions(all=True) + self.assertTrue(ls, msg=ls) + for disk in psutil.disk_partitions(all=True): + if not WINDOWS: + try: + os.stat(disk.mountpoint) + except OSError as err: + if TRAVIS and OSX and err.errno == errno.EIO: + continue + # http://mail.python.org/pipermail/python-dev/ + # 2012-June/120787.html + if err.errno not in (errno.EPERM, errno.EACCES): + raise + else: + if SUNOS: + # on solaris apparently mount points can also be files + assert os.path.exists(disk.mountpoint), disk + else: + assert os.path.isdir(disk.mountpoint), disk + self.assertIsInstance(disk.fstype, str) + self.assertIsInstance(disk.opts, str) + + def find_mount_point(path): + path = os.path.abspath(path) + while not os.path.ismount(path): + path = os.path.dirname(path) + return path.lower() + + mount = find_mount_point(__file__) + mounts = [x.mountpoint.lower() for x in + psutil.disk_partitions(all=True)] + self.assertIn(mount, mounts) + psutil.disk_usage(mount) + + @skip_on_access_denied() + def test_net_connections(self): + def check(cons, families, types_): + for conn in cons: + self.assertIn(conn.family, families, msg=conn) + if conn.family != getattr(socket, 'AF_UNIX', object()): + self.assertIn(conn.type, types_, msg=conn) + self.assertIsInstance(conn.status, (str, unicode)) + + from psutil._common import conn_tmap + for kind, groups in conn_tmap.items(): + if SUNOS and kind == 'unix': + continue + families, types_ = groups + cons = psutil.net_connections(kind) + self.assertEqual(len(cons), len(set(cons))) + check(cons, families, types_) + + def test_net_io_counters(self): + def check_ntuple(nt): + self.assertEqual(nt[0], nt.bytes_sent) + self.assertEqual(nt[1], nt.bytes_recv) + self.assertEqual(nt[2], nt.packets_sent) + self.assertEqual(nt[3], nt.packets_recv) + self.assertEqual(nt[4], nt.errin) + self.assertEqual(nt[5], nt.errout) + self.assertEqual(nt[6], nt.dropin) + self.assertEqual(nt[7], nt.dropout) + assert nt.bytes_sent >= 0, nt + assert nt.bytes_recv >= 0, nt + assert nt.packets_sent >= 0, nt + assert nt.packets_recv >= 0, nt + assert nt.errin >= 0, nt + assert nt.errout >= 0, nt + assert nt.dropin >= 0, nt + assert nt.dropout >= 0, nt + + ret = psutil.net_io_counters(pernic=False) + check_ntuple(ret) + ret = psutil.net_io_counters(pernic=True) + self.assertNotEqual(ret, []) + for key in ret: + self.assertTrue(key) + self.assertIsInstance(key, (str, unicode)) + check_ntuple(ret[key]) + + def test_net_if_addrs(self): + nics = psutil.net_if_addrs() + assert nics, nics + + nic_stats = psutil.net_if_stats() + + # Not reliable on all platforms (net_if_addrs() reports more + # interfaces). + # self.assertEqual(sorted(nics.keys()), + # sorted(psutil.net_io_counters(pernic=True).keys())) + + families = set([socket.AF_INET, AF_INET6, psutil.AF_LINK]) + for nic, addrs in nics.items(): + self.assertIsInstance(nic, (str, unicode)) + self.assertEqual(len(set(addrs)), len(addrs)) + for addr in addrs: + self.assertIsInstance(addr.family, int) + self.assertIsInstance(addr.address, str) + self.assertIsInstance(addr.netmask, (str, type(None))) + self.assertIsInstance(addr.broadcast, (str, type(None))) + self.assertIn(addr.family, families) + if sys.version_info >= (3, 4): + self.assertIsInstance(addr.family, enum.IntEnum) + if nic_stats[nic].isup: + # Do not test binding to addresses of interfaces + # that are down + if addr.family == socket.AF_INET: + s = socket.socket(addr.family) + with contextlib.closing(s): + s.bind((addr.address, 0)) + elif addr.family == socket.AF_INET6: + info = socket.getaddrinfo( + addr.address, 0, socket.AF_INET6, + socket.SOCK_STREAM, 0, socket.AI_PASSIVE)[0] + af, socktype, proto, canonname, sa = info + s = socket.socket(af, socktype, proto) + with contextlib.closing(s): + s.bind(sa) + for ip in (addr.address, addr.netmask, addr.broadcast, + addr.ptp): + if ip is not None: + # TODO: skip AF_INET6 for now because I get: + # AddressValueError: Only hex digits permitted in + # u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0' + if addr.family != AF_INET6: + check_net_address(ip, addr.family) + # broadcast and ptp addresses are mutually exclusive + if addr.broadcast: + self.assertIsNone(addr.ptp) + elif addr.ptp: + self.assertIsNone(addr.broadcast) + + if BSD or OSX or SUNOS: + if hasattr(socket, "AF_LINK"): + self.assertEqual(psutil.AF_LINK, socket.AF_LINK) + elif LINUX: + self.assertEqual(psutil.AF_LINK, socket.AF_PACKET) + elif WINDOWS: + self.assertEqual(psutil.AF_LINK, -1) + + def test_net_if_addrs_mac_null_bytes(self): + # Simulate that the underlying C function returns an incomplete + # MAC address. psutil is supposed to fill it with null bytes. + # https://github.com/giampaolo/psutil/issues/786 + if POSIX: + ret = [('em1', psutil.AF_LINK, '06:3d:29', None, None, None)] + else: + ret = [('em1', -1, '06-3d-29', None, None, None)] + with mock.patch('psutil._psplatform.net_if_addrs', + return_value=ret) as m: + addr = psutil.net_if_addrs()['em1'][0] + assert m.called + if POSIX: + self.assertEqual(addr.address, '06:3d:29:00:00:00') + else: + self.assertEqual(addr.address, '06-3d-29-00-00-00') + + @unittest.skipIf(TRAVIS, "unreliable on TRAVIS") # raises EPERM + def test_net_if_stats(self): + nics = psutil.net_if_stats() + assert nics, nics + all_duplexes = (psutil.NIC_DUPLEX_FULL, + psutil.NIC_DUPLEX_HALF, + psutil.NIC_DUPLEX_UNKNOWN) + for nic, stats in nics.items(): + isup, duplex, speed, mtu = stats + self.assertIsInstance(isup, bool) + self.assertIn(duplex, all_duplexes) + self.assertIn(duplex, all_duplexes) + self.assertGreaterEqual(speed, 0) + self.assertGreaterEqual(mtu, 0) + + @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'), + '/proc/diskstats not available on this linux version') + @unittest.skipIf(APPVEYOR, "unreliable on APPVEYOR") # no visible disks + def test_disk_io_counters(self): + def check_ntuple(nt): + self.assertEqual(nt[0], nt.read_count) + self.assertEqual(nt[1], nt.write_count) + self.assertEqual(nt[2], nt.read_bytes) + self.assertEqual(nt[3], nt.write_bytes) + if not (OPENBSD or NETBSD): + self.assertEqual(nt[4], nt.read_time) + self.assertEqual(nt[5], nt.write_time) + if LINUX: + self.assertEqual(nt[6], nt.read_merged_count) + self.assertEqual(nt[7], nt.write_merged_count) + self.assertEqual(nt[8], nt.busy_time) + elif FREEBSD: + self.assertEqual(nt[6], nt.busy_time) + for name in nt._fields: + assert getattr(nt, name) >= 0, nt + + ret = psutil.disk_io_counters(perdisk=False) + check_ntuple(ret) + ret = psutil.disk_io_counters(perdisk=True) + # make sure there are no duplicates + self.assertEqual(len(ret), len(set(ret))) + for key in ret: + assert key, key + check_ntuple(ret[key]) + if LINUX and key[-1].isdigit(): + # if 'sda1' is listed 'sda' shouldn't, see: + # https://github.com/giampaolo/psutil/issues/338 + while key[-1].isdigit(): + key = key[:-1] + self.assertNotIn(key, ret.keys()) + + # can't find users on APPVEYOR or TRAVIS + @unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(), + "unreliable on APPVEYOR or TRAVIS") + def test_users(self): + users = psutil.users() + self.assertNotEqual(users, []) + for user in users: + assert user.name, user + self.assertIsInstance(user.name, (str, unicode)) + self.assertIsInstance(user.terminal, (str, unicode, None)) + if user.host is not None: + self.assertIsInstance(user.host, (str, unicode, None)) + user.terminal + user.host + assert user.started > 0.0, user + datetime.datetime.fromtimestamp(user.started) + + def test_cpu_stats(self): + # Tested more extensively in per-platform test modules. + infos = psutil.cpu_stats() + for name in infos._fields: + value = getattr(infos, name) + self.assertGreaterEqual(value, 0) + if name in ('ctx_switches', 'interrupts'): + self.assertGreater(value, 0) + + @unittest.skipUnless(hasattr(psutil, "cpu_freq"), + "platform not suported") + def test_cpu_freq(self): + def check_ls(ls): + for nt in ls: + self.assertLessEqual(nt.current, nt.max) + for name in nt._fields: + value = getattr(nt, name) + self.assertIsInstance(value, (int, long, float)) + self.assertGreaterEqual(value, 0) + + ls = psutil.cpu_freq(percpu=True) + if TRAVIS and not ls: + return + + assert ls, ls + check_ls([psutil.cpu_freq(percpu=False)]) + + if LINUX: + self.assertEqual(len(ls), psutil.cpu_count()) + + def test_os_constants(self): + names = ["POSIX", "WINDOWS", "LINUX", "OSX", "FREEBSD", "OPENBSD", + "NETBSD", "BSD", "SUNOS"] + for name in names: + self.assertIsInstance(getattr(psutil, name), bool, msg=name) + + if os.name == 'posix': + assert psutil.POSIX + assert not psutil.WINDOWS + names.remove("POSIX") + if "linux" in sys.platform.lower(): + assert psutil.LINUX + names.remove("LINUX") + elif "bsd" in sys.platform.lower(): + assert psutil.BSD + self.assertEqual([psutil.FREEBSD, psutil.OPENBSD, + psutil.NETBSD].count(True), 1) + names.remove("BSD") + names.remove("FREEBSD") + names.remove("OPENBSD") + names.remove("NETBSD") + elif "sunos" in sys.platform.lower() or \ + "solaris" in sys.platform.lower(): + assert psutil.SUNOS + names.remove("SUNOS") + elif "darwin" in sys.platform.lower(): + assert psutil.OSX + names.remove("OSX") + else: + assert psutil.WINDOWS + assert not psutil.POSIX + names.remove("WINDOWS") + + # assert all other constants are set to False + for name in names: + self.assertIs(getattr(psutil, name), False, msg=name) + + @unittest.skipUnless(hasattr(psutil, "sensors_temperatures"), + "platform not supported") + def test_sensors_temperatures(self): + temps = psutil.sensors_temperatures() + for name, entries in temps.items(): + self.assertIsInstance(name, (str, unicode)) + for entry in entries: + self.assertIsInstance(entry.label, (str, unicode)) + if entry.current is not None: + self.assertGreaterEqual(entry.current, 0) + if entry.high is not None: + self.assertGreaterEqual(entry.high, 0) + if entry.critical is not None: + self.assertGreaterEqual(entry.critical, 0) + + @unittest.skipUnless(hasattr(psutil, "sensors_battery"), + "platform not supported") + def test_sensors_battery(self): + ret = psutil.sensors_battery() + if ret is None: + return # no battery + self.assertGreaterEqual(ret.percent, 0) + self.assertLessEqual(ret.percent, 100) + if ret.secsleft not in (psutil.POWER_TIME_UNKNOWN, + psutil.POWER_TIME_UNLIMITED): + self.assertGreaterEqual(ret.secsleft, 0) + else: + if ret.secsleft == psutil.POWER_TIME_UNLIMITED: + self.assertTrue(ret.power_plugged) + self.assertIsInstance(ret.power_plugged, bool) + + @unittest.skipUnless(hasattr(psutil, "sensors_fans"), + "platform not supported") + def test_sensors_fans(self): + fans = psutil.sensors_fans() + for name, entries in fans.items(): + self.assertIsInstance(name, (str, unicode)) + for entry in entries: + self.assertIsInstance(entry.label, (str, unicode)) + self.assertIsInstance(entry.current, (int, long)) + self.assertGreaterEqual(entry.current, 0) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/psutil/tests/test_windows.py b/pipenv/vendor/psutil/tests/test_windows.py new file mode 100755 index 00000000..3fcc20ed --- /dev/null +++ b/pipenv/vendor/psutil/tests/test_windows.py @@ -0,0 +1,815 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -* + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Windows specific tests.""" + +import errno +import glob +import os +import platform +import re +import signal +import subprocess +import sys +import time + +try: + import win32api # requires "pip install pypiwin32" / "make setup-dev-env" + import win32con + import win32process + import wmi # requires "pip install wmi" / "make setup-dev-env" +except ImportError: + if os.name == 'nt': + raise + +import psutil +from psutil import WINDOWS +from psutil._compat import basestring +from psutil._compat import callable +from psutil._compat import PY3 +from psutil.tests import APPVEYOR +from psutil.tests import get_test_subprocess +from psutil.tests import mock +from psutil.tests import reap_children +from psutil.tests import retry_before_failing +from psutil.tests import run_test_module_by_name +from psutil.tests import unittest + + +cext = psutil._psplatform.cext + +# are we a 64 bit process +IS_64_BIT = sys.maxsize > 2**32 + + +def wrap_exceptions(fun): + def wrapper(self, *args, **kwargs): + try: + return fun(self, *args, **kwargs) + except OSError as err: + from psutil._pswindows import ACCESS_DENIED_SET + if err.errno in ACCESS_DENIED_SET: + raise psutil.AccessDenied(None, None) + if err.errno == errno.ESRCH: + raise psutil.NoSuchProcess(None, None) + raise + return wrapper + + +# =================================================================== +# System APIs +# =================================================================== + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestSystemAPIs(unittest.TestCase): + + def test_nic_names(self): + p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE) + out = p.communicate()[0] + if PY3: + out = str(out, sys.stdout.encoding or sys.getfilesystemencoding()) + nics = psutil.net_io_counters(pernic=True).keys() + for nic in nics: + if "pseudo-interface" in nic.replace(' ', '-').lower(): + continue + if nic not in out: + self.fail( + "%r nic wasn't found in 'ipconfig /all' output" % nic) + + @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ, + 'NUMBER_OF_PROCESSORS env var is not available') + def test_cpu_count(self): + num_cpus = int(os.environ['NUMBER_OF_PROCESSORS']) + self.assertEqual(num_cpus, psutil.cpu_count()) + + def test_cpu_count_2(self): + sys_value = win32api.GetSystemInfo()[5] + psutil_value = psutil.cpu_count() + self.assertEqual(sys_value, psutil_value) + + def test_cpu_freq(self): + w = wmi.WMI() + proc = w.Win32_Processor()[0] + self.assertEqual(proc.CurrentClockSpeed, psutil.cpu_freq().current) + self.assertEqual(proc.MaxClockSpeed, psutil.cpu_freq().max) + + def test_total_phymem(self): + w = wmi.WMI().Win32_ComputerSystem()[0] + self.assertEqual(int(w.TotalPhysicalMemory), + psutil.virtual_memory().total) + + # @unittest.skipIf(wmi is None, "wmi module is not installed") + # def test__UPTIME(self): + # # _UPTIME constant is not public but it is used internally + # # as value to return for pid 0 creation time. + # # WMI behaves the same. + # w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + # p = psutil.Process(0) + # wmic_create = str(w.CreationDate.split('.')[0]) + # psutil_create = time.strftime("%Y%m%d%H%M%S", + # time.localtime(p.create_time())) + + # Note: this test is not very reliable + @unittest.skipIf(APPVEYOR, "test not relieable on appveyor") + @retry_before_failing() + def test_pids(self): + # Note: this test might fail if the OS is starting/killing + # other processes in the meantime + w = wmi.WMI().Win32_Process() + wmi_pids = set([x.ProcessId for x in w]) + psutil_pids = set(psutil.pids()) + self.assertEqual(wmi_pids, psutil_pids) + + @retry_before_failing() + def test_disks(self): + ps_parts = psutil.disk_partitions(all=True) + wmi_parts = wmi.WMI().Win32_LogicalDisk() + for ps_part in ps_parts: + for wmi_part in wmi_parts: + if ps_part.device.replace('\\', '') == wmi_part.DeviceID: + if not ps_part.mountpoint: + # this is usually a CD-ROM with no disk inserted + break + try: + usage = psutil.disk_usage(ps_part.mountpoint) + except OSError as err: + if err.errno == errno.ENOENT: + # usually this is the floppy + break + else: + raise + self.assertEqual(usage.total, int(wmi_part.Size)) + wmi_free = int(wmi_part.FreeSpace) + self.assertEqual(usage.free, wmi_free) + # 10 MB tollerance + if abs(usage.free - wmi_free) > 10 * 1024 * 1024: + self.fail("psutil=%s, wmi=%s" % ( + usage.free, wmi_free)) + break + else: + self.fail("can't find partition %s" % repr(ps_part)) + + def test_disk_usage(self): + for disk in psutil.disk_partitions(): + sys_value = win32api.GetDiskFreeSpaceEx(disk.mountpoint) + psutil_value = psutil.disk_usage(disk.mountpoint) + self.assertAlmostEqual(sys_value[0], psutil_value.free, + delta=1024 * 1024) + self.assertAlmostEqual(sys_value[1], psutil_value.total, + delta=1024 * 1024) + self.assertEqual(psutil_value.used, + psutil_value.total - psutil_value.free) + + def test_disk_partitions(self): + sys_value = [ + x + '\\' for x in win32api.GetLogicalDriveStrings().split("\\\x00") + if x and not x.startswith('A:')] + psutil_value = [x.mountpoint for x in psutil.disk_partitions(all=True)] + self.assertEqual(sys_value, psutil_value) + + def test_net_if_stats(self): + ps_names = set(cext.net_if_stats()) + wmi_adapters = wmi.WMI().Win32_NetworkAdapter() + wmi_names = set() + for wmi_adapter in wmi_adapters: + wmi_names.add(wmi_adapter.Name) + wmi_names.add(wmi_adapter.NetConnectionID) + self.assertTrue(ps_names & wmi_names, + "no common entries in %s, %s" % (ps_names, wmi_names)) + + +# =================================================================== +# sensors_battery() +# =================================================================== + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestSensorsBattery(unittest.TestCase): + + def test_percent(self): + w = wmi.WMI() + battery_psutil = psutil.sensors_battery() + if battery_psutil is None: + with self.assertRaises(IndexError): + w.query('select * from Win32_Battery')[0] + else: + battery_wmi = w.query('select * from Win32_Battery')[0] + if battery_psutil is None: + self.assertNot(battery_wmi.EstimatedChargeRemaining) + return + + self.assertAlmostEqual( + battery_psutil.percent, battery_wmi.EstimatedChargeRemaining, + delta=1) + self.assertEqual( + battery_psutil.power_plugged, battery_wmi.BatteryStatus == 1) + + def test_battery_present(self): + if win32api.GetPwrCapabilities()['SystemBatteriesPresent']: + self.assertIsNotNone(psutil.sensors_battery()) + else: + self.assertIsNone(psutil.sensors_battery()) + + def test_emulate_no_battery(self): + with mock.patch("psutil._pswindows.cext.sensors_battery", + return_value=(0, 128, 0, 0)) as m: + self.assertIsNone(psutil.sensors_battery()) + assert m.called + + def test_emulate_power_connected(self): + with mock.patch("psutil._pswindows.cext.sensors_battery", + return_value=(1, 0, 0, 0)) as m: + self.assertEqual(psutil.sensors_battery().secsleft, + psutil.POWER_TIME_UNLIMITED) + assert m.called + + def test_emulate_power_charging(self): + with mock.patch("psutil._pswindows.cext.sensors_battery", + return_value=(0, 8, 0, 0)) as m: + self.assertEqual(psutil.sensors_battery().secsleft, + psutil.POWER_TIME_UNLIMITED) + assert m.called + + def test_emulate_secs_left_unknown(self): + with mock.patch("psutil._pswindows.cext.sensors_battery", + return_value=(0, 0, 0, -1)) as m: + self.assertEqual(psutil.sensors_battery().secsleft, + psutil.POWER_TIME_UNKNOWN) + assert m.called + + +# =================================================================== +# Process APIs +# =================================================================== + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestProcess(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + + def test_issue_24(self): + p = psutil.Process(0) + self.assertRaises(psutil.AccessDenied, p.kill) + + def test_special_pid(self): + p = psutil.Process(4) + self.assertEqual(p.name(), 'System') + # use __str__ to access all common Process properties to check + # that nothing strange happens + str(p) + p.username() + self.assertTrue(p.create_time() >= 0.0) + try: + rss, vms = p.memory_info()[:2] + except psutil.AccessDenied: + # expected on Windows Vista and Windows 7 + if not platform.uname()[1] in ('vista', 'win-7', 'win7'): + raise + else: + self.assertTrue(rss > 0) + + def test_send_signal(self): + p = psutil.Process(self.pid) + self.assertRaises(ValueError, p.send_signal, signal.SIGINT) + + def test_exe(self): + for p in psutil.process_iter(): + try: + self.assertEqual(os.path.basename(p.exe()), p.name()) + except psutil.Error: + pass + + def test_num_handles_increment(self): + p = psutil.Process(os.getpid()) + before = p.num_handles() + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, os.getpid()) + after = p.num_handles() + self.assertEqual(after, before + 1) + win32api.CloseHandle(handle) + self.assertEqual(p.num_handles(), before) + + def test_handles_leak(self): + # Call all Process methods and make sure no handles are left + # open. This is here mainly to make sure functions using + # OpenProcess() always call CloseHandle(). + def call(p, attr): + attr = getattr(p, name, None) + if attr is not None and callable(attr): + attr() + else: + attr + + p = psutil.Process(self.pid) + failures = [] + for name in dir(psutil.Process): + if name.startswith('_') \ + or name in ('terminate', 'kill', 'suspend', 'resume', + 'nice', 'send_signal', 'wait', 'children', + 'as_dict'): + continue + else: + try: + call(p, name) + num1 = p.num_handles() + call(p, name) + num2 = p.num_handles() + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + else: + if num2 > num1: + fail = \ + "failure while processing Process.%s method " \ + "(before=%s, after=%s)" % (name, num1, num2) + failures.append(fail) + if failures: + self.fail('\n' + '\n'.join(failures)) + + def test_name_always_available(self): + # On Windows name() is never supposed to raise AccessDenied, + # see https://github.com/giampaolo/psutil/issues/627 + for p in psutil.process_iter(): + try: + p.name() + except psutil.NoSuchProcess: + pass + + @unittest.skipUnless(sys.version_info >= (2, 7), + "CTRL_* signals not supported") + def test_ctrl_signals(self): + p = psutil.Process(get_test_subprocess().pid) + p.send_signal(signal.CTRL_C_EVENT) + p.send_signal(signal.CTRL_BREAK_EVENT) + p.kill() + p.wait() + self.assertRaises(psutil.NoSuchProcess, + p.send_signal, signal.CTRL_C_EVENT) + self.assertRaises(psutil.NoSuchProcess, + p.send_signal, signal.CTRL_BREAK_EVENT) + + def test_compare_name_exe(self): + for p in psutil.process_iter(): + try: + a = os.path.basename(p.exe()) + b = p.name() + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + else: + self.assertEqual(a, b) + + def test_username(self): + sys_value = win32api.GetUserName() + psutil_value = psutil.Process().username() + self.assertEqual(sys_value, psutil_value.split('\\')[1]) + + def test_cmdline(self): + sys_value = re.sub(' +', ' ', win32api.GetCommandLine()).strip() + psutil_value = ' '.join(psutil.Process().cmdline()) + self.assertEqual(sys_value, psutil_value) + + # XXX - occasional failures + + # def test_cpu_times(self): + # handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + # win32con.FALSE, os.getpid()) + # self.addCleanup(win32api.CloseHandle, handle) + # sys_value = win32process.GetProcessTimes(handle) + # psutil_value = psutil.Process().cpu_times() + # self.assertAlmostEqual( + # psutil_value.user, sys_value['UserTime'] / 10000000.0, + # delta=0.2) + # self.assertAlmostEqual( + # psutil_value.user, sys_value['KernelTime'] / 10000000.0, + # delta=0.2) + + def test_nice(self): + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, os.getpid()) + self.addCleanup(win32api.CloseHandle, handle) + sys_value = win32process.GetPriorityClass(handle) + psutil_value = psutil.Process().nice() + self.assertEqual(psutil_value, sys_value) + + def test_memory_info(self): + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, self.pid) + self.addCleanup(win32api.CloseHandle, handle) + sys_value = win32process.GetProcessMemoryInfo(handle) + psutil_value = psutil.Process(self.pid).memory_info() + self.assertEqual( + sys_value['PeakWorkingSetSize'], psutil_value.peak_wset) + self.assertEqual( + sys_value['WorkingSetSize'], psutil_value.wset) + self.assertEqual( + sys_value['QuotaPeakPagedPoolUsage'], psutil_value.peak_paged_pool) + self.assertEqual( + sys_value['QuotaPagedPoolUsage'], psutil_value.paged_pool) + self.assertEqual( + sys_value['QuotaPeakNonPagedPoolUsage'], + psutil_value.peak_nonpaged_pool) + self.assertEqual( + sys_value['QuotaNonPagedPoolUsage'], psutil_value.nonpaged_pool) + self.assertEqual( + sys_value['PagefileUsage'], psutil_value.pagefile) + self.assertEqual( + sys_value['PeakPagefileUsage'], psutil_value.peak_pagefile) + + self.assertEqual(psutil_value.rss, psutil_value.wset) + self.assertEqual(psutil_value.vms, psutil_value.pagefile) + + def test_wait(self): + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, self.pid) + self.addCleanup(win32api.CloseHandle, handle) + p = psutil.Process(self.pid) + p.terminate() + psutil_value = p.wait() + sys_value = win32process.GetExitCodeProcess(handle) + self.assertEqual(psutil_value, sys_value) + + def test_cpu_affinity(self): + def from_bitmask(x): + return [i for i in range(64) if (1 << i) & x] + + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, self.pid) + self.addCleanup(win32api.CloseHandle, handle) + sys_value = from_bitmask( + win32process.GetProcessAffinityMask(handle)[0]) + psutil_value = psutil.Process(self.pid).cpu_affinity() + self.assertEqual(psutil_value, sys_value) + + def test_io_counters(self): + handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, + win32con.FALSE, os.getpid()) + self.addCleanup(win32api.CloseHandle, handle) + sys_value = win32process.GetProcessIoCounters(handle) + psutil_value = psutil.Process().io_counters() + self.assertEqual( + psutil_value.read_count, sys_value['ReadOperationCount']) + self.assertEqual( + psutil_value.write_count, sys_value['WriteOperationCount']) + self.assertEqual( + psutil_value.read_bytes, sys_value['ReadTransferCount']) + self.assertEqual( + psutil_value.write_bytes, sys_value['WriteTransferCount']) + self.assertEqual( + psutil_value.other_count, sys_value['OtherOperationCount']) + self.assertEqual( + psutil_value.other_bytes, sys_value['OtherTransferCount']) + + def test_num_handles(self): + import ctypes + import ctypes.wintypes + PROCESS_QUERY_INFORMATION = 0x400 + handle = ctypes.windll.kernel32.OpenProcess( + PROCESS_QUERY_INFORMATION, 0, os.getpid()) + self.addCleanup(ctypes.windll.kernel32.CloseHandle, handle) + hndcnt = ctypes.wintypes.DWORD() + ctypes.windll.kernel32.GetProcessHandleCount( + handle, ctypes.byref(hndcnt)) + sys_value = hndcnt.value + psutil_value = psutil.Process().num_handles() + ctypes.windll.kernel32.CloseHandle(handle) + self.assertEqual(psutil_value, sys_value + 1) + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestProcessWMI(unittest.TestCase): + """Compare Process API results with WMI.""" + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + + def test_name(self): + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + self.assertEqual(p.name(), w.Caption) + + def test_exe(self): + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + # Note: wmi reports the exe as a lower case string. + # Being Windows paths case-insensitive we ignore that. + self.assertEqual(p.exe().lower(), w.ExecutablePath.lower()) + + def test_cmdline(self): + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + self.assertEqual(' '.join(p.cmdline()), + w.CommandLine.replace('"', '')) + + def test_username(self): + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + domain, _, username = w.GetOwner() + username = "%s\\%s" % (domain, username) + self.assertEqual(p.username(), username) + + def test_memory_rss(self): + time.sleep(0.1) + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + rss = p.memory_info().rss + self.assertEqual(rss, int(w.WorkingSetSize)) + + def test_memory_vms(self): + time.sleep(0.1) + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + vms = p.memory_info().vms + # http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx + # ...claims that PageFileUsage is represented in Kilo + # bytes but funnily enough on certain platforms bytes are + # returned instead. + wmi_usage = int(w.PageFileUsage) + if (vms != wmi_usage) and (vms != wmi_usage * 1024): + self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms)) + + def test_create_time(self): + w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] + p = psutil.Process(self.pid) + wmic_create = str(w.CreationDate.split('.')[0]) + psutil_create = time.strftime("%Y%m%d%H%M%S", + time.localtime(p.create_time())) + self.assertEqual(wmic_create, psutil_create) + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestDualProcessImplementation(unittest.TestCase): + """ + Certain APIs on Windows have 2 internal implementations, one + based on documented Windows APIs, another one based + NtQuerySystemInformation() which gets called as fallback in + case the first fails because of limited permission error. + Here we test that the two methods return the exact same value, + see: + https://github.com/giampaolo/psutil/issues/304 + """ + + @classmethod + def setUpClass(cls): + cls.pid = get_test_subprocess().pid + + @classmethod + def tearDownClass(cls): + reap_children() + # --- + # same tests as above but mimicks the AccessDenied failure of + # the first (fast) method failing with AD. + + def test_name(self): + name = psutil.Process(self.pid).name() + with mock.patch("psutil._psplatform.cext.proc_exe", + side_effect=psutil.AccessDenied(os.getpid())) as fun: + self.assertEqual(psutil.Process(self.pid).name(), name) + assert fun.called + + def test_memory_info(self): + mem_1 = psutil.Process(self.pid).memory_info() + with mock.patch("psutil._psplatform.cext.proc_memory_info", + side_effect=OSError(errno.EPERM, "msg")) as fun: + mem_2 = psutil.Process(self.pid).memory_info() + self.assertEqual(len(mem_1), len(mem_2)) + for i in range(len(mem_1)): + self.assertGreaterEqual(mem_1[i], 0) + self.assertGreaterEqual(mem_2[i], 0) + self.assertAlmostEqual(mem_1[i], mem_2[i], delta=512) + assert fun.called + + def test_create_time(self): + ctime = psutil.Process(self.pid).create_time() + with mock.patch("psutil._psplatform.cext.proc_create_time", + side_effect=OSError(errno.EPERM, "msg")) as fun: + self.assertEqual(psutil.Process(self.pid).create_time(), ctime) + assert fun.called + + def test_cpu_times(self): + cpu_times_1 = psutil.Process(self.pid).cpu_times() + with mock.patch("psutil._psplatform.cext.proc_cpu_times", + side_effect=OSError(errno.EPERM, "msg")) as fun: + cpu_times_2 = psutil.Process(self.pid).cpu_times() + assert fun.called + self.assertAlmostEqual( + cpu_times_1.user, cpu_times_2.user, delta=0.01) + self.assertAlmostEqual( + cpu_times_1.system, cpu_times_2.system, delta=0.01) + + def test_io_counters(self): + io_counters_1 = psutil.Process(self.pid).io_counters() + with mock.patch("psutil._psplatform.cext.proc_io_counters", + side_effect=OSError(errno.EPERM, "msg")) as fun: + io_counters_2 = psutil.Process(self.pid).io_counters() + for i in range(len(io_counters_1)): + self.assertAlmostEqual( + io_counters_1[i], io_counters_2[i], delta=5) + assert fun.called + + def test_num_handles(self): + num_handles = psutil.Process(self.pid).num_handles() + with mock.patch("psutil._psplatform.cext.proc_num_handles", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process(self.pid).num_handles() == num_handles + assert fun.called + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class RemoteProcessTestCase(unittest.TestCase): + """Certain functions require calling ReadProcessMemory. + This trivially works when called on the current process. + Check that this works on other processes, especially when they + have a different bitness. + """ + + @staticmethod + def find_other_interpreter(): + # find a python interpreter that is of the opposite bitness from us + code = "import sys; sys.stdout.write(str(sys.maxsize > 2**32))" + + # XXX: a different and probably more stable approach might be to access + # the registry but accessing 64 bit paths from a 32 bit process + for filename in glob.glob(r"C:\Python*\python.exe"): + proc = subprocess.Popen(args=[filename, "-c", code], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output, _ = proc.communicate() + if output == str(not IS_64_BIT): + return filename + + @classmethod + def setUpClass(cls): + other_python = cls.find_other_interpreter() + + if other_python is None: + raise unittest.SkipTest( + "could not find interpreter with opposite bitness") + + if IS_64_BIT: + cls.python64 = sys.executable + cls.python32 = other_python + else: + cls.python64 = other_python + cls.python32 = sys.executable + + test_args = ["-c", "import sys; sys.stdin.read()"] + + def setUp(self): + env = os.environ.copy() + env["THINK_OF_A_NUMBER"] = str(os.getpid()) + self.proc32 = get_test_subprocess([self.python32] + self.test_args, + env=env, + stdin=subprocess.PIPE) + self.proc64 = get_test_subprocess([self.python64] + self.test_args, + env=env, + stdin=subprocess.PIPE) + + def tearDown(self): + self.proc32.communicate() + self.proc64.communicate() + reap_children() + + @classmethod + def tearDownClass(cls): + reap_children() + + def test_cmdline_32(self): + p = psutil.Process(self.proc32.pid) + self.assertEqual(len(p.cmdline()), 3) + self.assertEqual(p.cmdline()[1:], self.test_args) + + def test_cmdline_64(self): + p = psutil.Process(self.proc64.pid) + self.assertEqual(len(p.cmdline()), 3) + self.assertEqual(p.cmdline()[1:], self.test_args) + + def test_cwd_32(self): + p = psutil.Process(self.proc32.pid) + self.assertEqual(p.cwd(), os.getcwd()) + + def test_cwd_64(self): + p = psutil.Process(self.proc64.pid) + self.assertEqual(p.cwd(), os.getcwd()) + + def test_environ_32(self): + p = psutil.Process(self.proc32.pid) + e = p.environ() + self.assertIn("THINK_OF_A_NUMBER", e) + self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid())) + + def test_environ_64(self): + p = psutil.Process(self.proc64.pid) + e = p.environ() + self.assertIn("THINK_OF_A_NUMBER", e) + self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid())) + + +# =================================================================== +# Windows services +# =================================================================== + + +@unittest.skipUnless(WINDOWS, "WINDOWS only") +class TestServices(unittest.TestCase): + + def test_win_service_iter(self): + valid_statuses = set([ + "running", + "paused", + "start", + "pause", + "continue", + "stop", + "stopped", + ]) + valid_start_types = set([ + "automatic", + "manual", + "disabled", + ]) + valid_statuses = set([ + "running", + "paused", + "start_pending", + "pause_pending", + "continue_pending", + "stop_pending", + "stopped" + ]) + for serv in psutil.win_service_iter(): + data = serv.as_dict() + self.assertIsInstance(data['name'], basestring) + self.assertNotEqual(data['name'].strip(), "") + self.assertIsInstance(data['display_name'], basestring) + self.assertIsInstance(data['username'], basestring) + self.assertIn(data['status'], valid_statuses) + if data['pid'] is not None: + psutil.Process(data['pid']) + self.assertIsInstance(data['binpath'], basestring) + self.assertIsInstance(data['username'], basestring) + self.assertIsInstance(data['start_type'], basestring) + self.assertIn(data['start_type'], valid_start_types) + self.assertIn(data['status'], valid_statuses) + self.assertIsInstance(data['description'], basestring) + pid = serv.pid() + if pid is not None: + p = psutil.Process(pid) + self.assertTrue(p.is_running()) + # win_service_get + s = psutil.win_service_get(serv.name()) + # test __eq__ + self.assertEqual(serv, s) + + def test_win_service_get(self): + name = next(psutil.win_service_iter()).name() + + with self.assertRaises(psutil.NoSuchProcess) as cm: + psutil.win_service_get(name + '???') + self.assertEqual(cm.exception.name, name + '???') + + # test NoSuchProcess + service = psutil.win_service_get(name) + exc = WindowsError( + psutil._psplatform.cext.ERROR_SERVICE_DOES_NOT_EXIST, "") + with mock.patch("psutil._psplatform.cext.winservice_query_status", + side_effect=exc): + self.assertRaises(psutil.NoSuchProcess, service.status) + with mock.patch("psutil._psplatform.cext.winservice_query_config", + side_effect=exc): + self.assertRaises(psutil.NoSuchProcess, service.username) + + # test AccessDenied + exc = WindowsError( + psutil._psplatform.cext.ERROR_ACCESS_DENIED, "") + with mock.patch("psutil._psplatform.cext.winservice_query_status", + side_effect=exc): + self.assertRaises(psutil.AccessDenied, service.status) + with mock.patch("psutil._psplatform.cext.winservice_query_config", + side_effect=exc): + self.assertRaises(psutil.AccessDenied, service.username) + + # test __str__ and __repr__ + self.assertIn(service.name(), str(service)) + self.assertIn(service.display_name(), str(service)) + self.assertIn(service.name(), repr(service)) + self.assertIn(service.display_name(), repr(service)) + + +if __name__ == '__main__': + run_test_module_by_name(__file__) diff --git a/pipenv/vendor/ptyprocess/__init__.py b/pipenv/vendor/ptyprocess/__init__.py new file mode 100644 index 00000000..c831e417 --- /dev/null +++ b/pipenv/vendor/ptyprocess/__init__.py @@ -0,0 +1,4 @@ +"""Run a subprocess in a pseudo terminal""" +from .ptyprocess import PtyProcess, PtyProcessUnicode, PtyProcessError + +__version__ = '0.5.1' diff --git a/pipenv/vendor/ptyprocess/_fork_pty.py b/pipenv/vendor/ptyprocess/_fork_pty.py new file mode 100644 index 00000000..d00eb65e --- /dev/null +++ b/pipenv/vendor/ptyprocess/_fork_pty.py @@ -0,0 +1,77 @@ +"""Substitute for the forkpty system call, to support Solaris. +""" +import os +import errno + +from pty import (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CHILD) + +def fork_pty(): + '''This implements a substitute for the forkpty system call. This + should be more portable than the pty.fork() function. Specifically, + this should work on Solaris. + + Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to + resolve the issue with Python's pty.fork() not supporting Solaris, + particularly ssh. Based on patch to posixmodule.c authored by Noah + Spurrier:: + + http://mail.python.org/pipermail/python-dev/2003-May/035281.html + + ''' + + parent_fd, child_fd = os.openpty() + if parent_fd < 0 or child_fd < 0: + raise OSError("os.openpty() failed") + + pid = os.fork() + if pid == CHILD: + # Child. + os.close(parent_fd) + pty_make_controlling_tty(child_fd) + + os.dup2(child_fd, STDIN_FILENO) + os.dup2(child_fd, STDOUT_FILENO) + os.dup2(child_fd, STDERR_FILENO) + + else: + # Parent. + os.close(child_fd) + + return pid, parent_fd + +def pty_make_controlling_tty(tty_fd): + '''This makes the pseudo-terminal the controlling tty. This should be + more portable than the pty.fork() function. Specifically, this should + work on Solaris. ''' + + child_name = os.ttyname(tty_fd) + + # Disconnect from controlling tty, if any. Raises OSError of ENXIO + # if there was no controlling tty to begin with, such as when + # executed by a cron(1) job. + try: + fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + os.close(fd) + except OSError as err: + if err.errno != errno.ENXIO: + raise + + os.setsid() + + # Verify we are disconnected from controlling tty by attempting to open + # it again. We expect that OSError of ENXIO should always be raised. + try: + fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + os.close(fd) + raise ExceptionPexpect("OSError of errno.ENXIO should be raised.") + except OSError as err: + if err.errno != errno.ENXIO: + raise + + # Verify we can open child pty. + fd = os.open(child_name, os.O_RDWR) + os.close(fd) + + # Verify we now have a controlling tty. + fd = os.open("/dev/tty", os.O_WRONLY) + os.close(fd) \ No newline at end of file diff --git a/pipenv/vendor/ptyprocess/ptyprocess.py b/pipenv/vendor/ptyprocess/ptyprocess.py new file mode 100644 index 00000000..ca2b1626 --- /dev/null +++ b/pipenv/vendor/ptyprocess/ptyprocess.py @@ -0,0 +1,821 @@ +import codecs +import errno +import fcntl +import io +import os +import pty +import resource +import signal +import struct +import sys +import termios +import time + +try: + import builtins # Python 3 +except ImportError: + import __builtin__ as builtins # Python 2 + +# Constants +from pty import (STDIN_FILENO, CHILD) + +from .util import which + +_platform = sys.platform.lower() + +# Solaris uses internal __fork_pty(). All others use pty.fork(). +_is_solaris = ( + _platform.startswith('solaris') or + _platform.startswith('sunos')) + +if _is_solaris: + use_native_pty_fork = False + from . import _fork_pty +else: + use_native_pty_fork = True + +PY3 = sys.version_info[0] >= 3 + +if PY3: + def _byte(i): + return bytes([i]) +else: + def _byte(i): + return chr(i) + + class FileNotFoundError(OSError): pass + class TimeoutError(OSError): pass + +_EOF, _INTR = None, None + +def _make_eof_intr(): + """Set constants _EOF and _INTR. + + This avoids doing potentially costly operations on module load. + """ + global _EOF, _INTR + if (_EOF is not None) and (_INTR is not None): + return + + # inherit EOF and INTR definitions from controlling process. + try: + from termios import VEOF, VINTR + try: + fd = sys.__stdin__.fileno() + except ValueError: + # ValueError: I/O operation on closed file + fd = sys.__stdout__.fileno() + intr = ord(termios.tcgetattr(fd)[6][VINTR]) + eof = ord(termios.tcgetattr(fd)[6][VEOF]) + except (ImportError, OSError, IOError, ValueError, termios.error): + # unless the controlling process is also not a terminal, + # such as cron(1), or when stdin and stdout are both closed. + # Fall-back to using CEOF and CINTR. There + try: + from termios import CEOF, CINTR + (intr, eof) = (CINTR, CEOF) + except ImportError: + # ^C, ^D + (intr, eof) = (3, 4) + + _INTR = _byte(intr) + _EOF = _byte(eof) + +class PtyProcessError(Exception): + """Generic error class for this package.""" + +# setecho and setwinsize are pulled out here because on some platforms, we need +# to do this from the child before we exec() + +def _setecho(fd, state): + errmsg = 'setecho() may not be called on this platform' + + try: + attr = termios.tcgetattr(fd) + except termios.error as err: + if err.args[0] == errno.EINVAL: + raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) + raise + + if state: + attr[3] = attr[3] | termios.ECHO + else: + attr[3] = attr[3] & ~termios.ECHO + + try: + # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent and + # blocked on some platforms. TCSADRAIN would probably be ideal. + termios.tcsetattr(fd, termios.TCSANOW, attr) + except IOError as err: + if err.args[0] == errno.EINVAL: + raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) + raise + +def _setwinsize(fd, rows, cols): + # Some very old platforms have a bug that causes the value for + # termios.TIOCSWINSZ to be truncated. There was a hack here to work + # around this, but it caused problems with newer platforms so has been + # removed. For details see https://github.com/pexpect/pexpect/issues/39 + TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561) + # Note, assume ws_xpixel and ws_ypixel are zero. + s = struct.pack('HHHH', rows, cols, 0, 0) + fcntl.ioctl(fd, TIOCSWINSZ, s) + +class PtyProcess(object): + '''This class represents a process running in a pseudoterminal. + + The main constructor is the :meth:`spawn` classmethod. + ''' + string_type = bytes + if PY3: + linesep = os.linesep.encode('ascii') + crlf = '\r\n'.encode('ascii') + + @staticmethod + def write_to_stdout(b): + try: + return sys.stdout.buffer.write(b) + except AttributeError: + # If stdout has been replaced, it may not have .buffer + return sys.stdout.write(b.decode('ascii', 'replace')) + else: + linesep = os.linesep + crlf = '\r\n' + write_to_stdout = sys.stdout.write + + encoding = None + + argv = None + env = None + launch_dir = None + + def __init__(self, pid, fd): + _make_eof_intr() # Ensure _EOF and _INTR are calculated + self.pid = pid + self.fd = fd + self.fileobj = io.open(fd, 'r+b', buffering=0) + + self.terminated = False + self.closed = False + self.exitstatus = None + self.signalstatus = None + # status returned by os.waitpid + self.status = None + self.flag_eof = False + # Used by close() to give kernel time to update process status. + # Time in seconds. + self.delayafterclose = 0.1 + # Used by terminate() to give kernel time to update process status. + # Time in seconds. + self.delayafterterminate = 0.1 + + @classmethod + def spawn( + cls, argv, cwd=None, env=None, echo=True, preexec_fn=None, + dimensions=(24, 80)): + '''Start the given command in a child process in a pseudo terminal. + + This does all the fork/exec type of stuff for a pty, and returns an + instance of PtyProcess. + + If preexec_fn is supplied, it will be called with no arguments in the + child process before exec-ing the specified command. + It may, for instance, set signal handlers to SIG_DFL or SIG_IGN. + + Dimensions of the psuedoterminal used for the subprocess can be + specified as a tuple (rows, cols), or the default (24, 80) will be used. + ''' + # Note that it is difficult for this method to fail. + # You cannot detect if the child process cannot start. + # So the only way you can tell if the child process started + # or not is to try to read from the file descriptor. If you get + # EOF immediately then it means that the child is already dead. + # That may not necessarily be bad because you may have spawned a child + # that performs some task; creates no stdout output; and then dies. + + if not isinstance(argv, (list, tuple)): + raise TypeError("Expected a list or tuple for argv, got %r" % argv) + + # Shallow copy of argv so we can modify it + argv = argv[:] + command = argv[0] + + command_with_path = which(command) + if command_with_path is None: + raise FileNotFoundError('The command was not found or was not ' + + 'executable: %s.' % command) + command = command_with_path + argv[0] = command + + # [issue #119] To prevent the case where exec fails and the user is + # stuck interacting with a python child process instead of whatever + # was expected, we implement the solution from + # http://stackoverflow.com/a/3703179 to pass the exception to the + # parent process + + # [issue #119] 1. Before forking, open a pipe in the parent process. + exec_err_pipe_read, exec_err_pipe_write = os.pipe() + + if use_native_pty_fork: + pid, fd = pty.fork() + else: + # Use internal fork_pty, for Solaris + pid, fd = _fork_pty.fork_pty() + + # Some platforms must call setwinsize() and setecho() from the + # child process, and others from the master process. We do both, + # allowing IOError for either. + + if pid == CHILD: + # set window size + try: + _setwinsize(STDIN_FILENO, *dimensions) + except IOError as err: + if err.args[0] not in (errno.EINVAL, errno.ENOTTY): + raise + + # disable echo if spawn argument echo was unset + if not echo: + try: + _setecho(STDIN_FILENO, False) + except (IOError, termios.error) as err: + if err.args[0] not in (errno.EINVAL, errno.ENOTTY): + raise + + # [issue #119] 3. The child closes the reading end and sets the + # close-on-exec flag for the writing end. + os.close(exec_err_pipe_read) + fcntl.fcntl(exec_err_pipe_write, fcntl.F_SETFD, fcntl.FD_CLOEXEC) + + # Do not allow child to inherit open file descriptors from parent, + # with the exception of the exec_err_pipe_write of the pipe + max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0] + os.closerange(3, exec_err_pipe_write) + os.closerange(exec_err_pipe_write+1, max_fd) + + if cwd is not None: + os.chdir(cwd) + + if preexec_fn is not None: + try: + preexec_fn() + except Exception as e: + ename = type(e).__name__ + tosend = '{}:0:{}'.format(ename, str(e)) + if PY3: + tosend = tosend.encode('utf-8') + + os.write(exec_err_pipe_write, tosend) + os.close(exec_err_pipe_write) + os._exit(1) + + try: + if env is None: + os.execv(command, argv) + else: + os.execvpe(command, argv, env) + except OSError as err: + # [issue #119] 5. If exec fails, the child writes the error + # code back to the parent using the pipe, then exits. + tosend = 'OSError:{}:{}'.format(err.errno, str(err)) + if PY3: + tosend = tosend.encode('utf-8') + os.write(exec_err_pipe_write, tosend) + os.close(exec_err_pipe_write) + os._exit(os.EX_OSERR) + + # Parent + inst = cls(pid, fd) + + # Set some informational attributes + inst.argv = argv + if env is not None: + inst.env = env + if cwd is not None: + inst.launch_dir = cwd + + # [issue #119] 2. After forking, the parent closes the writing end + # of the pipe and reads from the reading end. + os.close(exec_err_pipe_write) + exec_err_data = os.read(exec_err_pipe_read, 4096) + os.close(exec_err_pipe_read) + + # [issue #119] 6. The parent reads eof (a zero-length read) if the + # child successfully performed exec, since close-on-exec made + # successful exec close the writing end of the pipe. Or, if exec + # failed, the parent reads the error code and can proceed + # accordingly. Either way, the parent blocks until the child calls + # exec. + if len(exec_err_data) != 0: + try: + errclass, errno_s, errmsg = exec_err_data.split(b':', 2) + exctype = getattr(builtins, errclass.decode('ascii'), Exception) + + exception = exctype(errmsg.decode('utf-8', 'replace')) + if exctype is OSError: + exception.errno = int(errno_s) + except: + raise Exception('Subprocess failed, got bad error data: %r' + % exec_err_data) + else: + raise exception + + try: + inst.setwinsize(*dimensions) + except IOError as err: + if err.args[0] not in (errno.EINVAL, errno.ENOTTY, errno.ENXIO): + raise + + return inst + + def __repr__(self): + clsname = type(self).__name__ + if self.argv is not None: + args = [repr(self.argv)] + if self.env is not None: + args.append("env=%r" % self.env) + if self.launch_dir is not None: + args.append("cwd=%r" % self.launch_dir) + + return "{}.spawn({})".format(clsname, ", ".join(args)) + + else: + return "{}(pid={}, fd={})".format(clsname, self.pid, self.fd) + + @staticmethod + def _coerce_send_string(s): + if not isinstance(s, bytes): + return s.encode('utf-8') + return s + + @staticmethod + def _coerce_read_string(s): + return s + + def __del__(self): + '''This makes sure that no system resources are left open. Python only + garbage collects Python objects. OS file descriptors are not Python + objects, so they must be handled explicitly. If the child file + descriptor was opened outside of this class (passed to the constructor) + then this does not close it. ''' + + if not self.closed: + # It is possible for __del__ methods to execute during the + # teardown of the Python VM itself. Thus self.close() may + # trigger an exception because os.close may be None. + try: + self.close() + # which exception, shouldn't we catch explicitly .. ? + except: + pass + + + def fileno(self): + '''This returns the file descriptor of the pty for the child. + ''' + return self.fd + + def close(self, force=True): + '''This closes the connection with the child application. Note that + calling close() more than once is valid. This emulates standard Python + behavior with files. Set force to True if you want to make sure that + the child is terminated (SIGKILL is sent if the child ignores SIGHUP + and SIGINT). ''' + if not self.closed: + self.flush() + self.fileobj.close() # Closes the file descriptor + # Give kernel time to update process status. + time.sleep(self.delayafterclose) + if self.isalive(): + if not self.terminate(force): + raise PtyProcessError('Could not terminate the child.') + self.fd = -1 + self.closed = True + #self.pid = None + + def flush(self): + '''This does nothing. It is here to support the interface for a + File-like object. ''' + + pass + + def isatty(self): + '''This returns True if the file descriptor is open and connected to a + tty(-like) device, else False. + + On SVR4-style platforms implementing streams, such as SunOS and HP-UX, + the child pty may not appear as a terminal device. This means + methods such as setecho(), setwinsize(), getwinsize() may raise an + IOError. ''' + + return os.isatty(self.fd) + + def waitnoecho(self, timeout=None): + '''This waits until the terminal ECHO flag is set False. This returns + True if the echo mode is off. This returns False if the ECHO flag was + not set False before the timeout. This can be used to detect when the + child is waiting for a password. Usually a child application will turn + off echo mode when it is waiting for the user to enter a password. For + example, instead of expecting the "password:" prompt you can wait for + the child to set ECHO off:: + + p = pexpect.spawn('ssh user@example.com') + p.waitnoecho() + p.sendline(mypassword) + + If timeout==None then this method to block until ECHO flag is False. + ''' + + if timeout is not None: + end_time = time.time() + timeout + while True: + if not self.getecho(): + return True + if timeout < 0 and timeout is not None: + return False + if timeout is not None: + timeout = end_time - time.time() + time.sleep(0.1) + + def getecho(self): + '''This returns the terminal echo mode. This returns True if echo is + on or False if echo is off. Child applications that are expecting you + to enter a password often set ECHO False. See waitnoecho(). + + Not supported on platforms where ``isatty()`` returns False. ''' + + try: + attr = termios.tcgetattr(self.fd) + except termios.error as err: + errmsg = 'getecho() may not be called on this platform' + if err.args[0] == errno.EINVAL: + raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) + raise + + self.echo = bool(attr[3] & termios.ECHO) + return self.echo + + def setecho(self, state): + '''This sets the terminal echo mode on or off. Note that anything the + child sent before the echo will be lost, so you should be sure that + your input buffer is empty before you call setecho(). For example, the + following will work as expected:: + + p = pexpect.spawn('cat') # Echo is on by default. + p.sendline('1234') # We expect see this twice from the child... + p.expect(['1234']) # ... once from the tty echo... + p.expect(['1234']) # ... and again from cat itself. + p.setecho(False) # Turn off tty echo + p.sendline('abcd') # We will set this only once (echoed by cat). + p.sendline('wxyz') # We will set this only once (echoed by cat) + p.expect(['abcd']) + p.expect(['wxyz']) + + The following WILL NOT WORK because the lines sent before the setecho + will be lost:: + + p = pexpect.spawn('cat') + p.sendline('1234') + p.setecho(False) # Turn off tty echo + p.sendline('abcd') # We will set this only once (echoed by cat). + p.sendline('wxyz') # We will set this only once (echoed by cat) + p.expect(['1234']) + p.expect(['1234']) + p.expect(['abcd']) + p.expect(['wxyz']) + + + Not supported on platforms where ``isatty()`` returns False. + ''' + _setecho(self.fd, state) + + self.echo = state + + def read(self, size=1024): + """Read and return at most ``size`` bytes from the pty. + + Can block if there is nothing to read. Raises :exc:`EOFError` if the + terminal was closed. + + Unlike Pexpect's ``read_nonblocking`` method, this doesn't try to deal + with the vagaries of EOF on platforms that do strange things, like IRIX + or older Solaris systems. It handles the errno=EIO pattern used on + Linux, and the empty-string return used on BSD platforms and (seemingly) + on recent Solaris. + """ + try: + s = self.fileobj.read(size) + except (OSError, IOError) as err: + if err.args[0] == errno.EIO: + # Linux-style EOF + self.flag_eof = True + raise EOFError('End Of File (EOF). Exception style platform.') + raise + if s == b'': + # BSD-style EOF (also appears to work on recent Solaris (OpenIndiana)) + self.flag_eof = True + raise EOFError('End Of File (EOF). Empty string style platform.') + + return s + + def readline(self): + """Read one line from the pseudoterminal, and return it as unicode. + + Can block if there is nothing to read. Raises :exc:`EOFError` if the + terminal was closed. + """ + try: + s = self.fileobj.readline() + except (OSError, IOError) as err: + if err.args[0] == errno.EIO: + # Linux-style EOF + self.flag_eof = True + raise EOFError('End Of File (EOF). Exception style platform.') + raise + if s == b'': + # BSD-style EOF (also appears to work on recent Solaris (OpenIndiana)) + self.flag_eof = True + raise EOFError('End Of File (EOF). Empty string style platform.') + + return s + + def write(self, s): + """Write bytes to the pseudoterminal. + + Returns the number of bytes written. + """ + return self.fileobj.write(s) + + def sendcontrol(self, char): + '''Helper method that wraps send() with mnemonic access for sending control + character to the child (such as Ctrl-C or Ctrl-D). For example, to send + Ctrl-G (ASCII 7, bell, '\a'):: + + child.sendcontrol('g') + + See also, sendintr() and sendeof(). + ''' + char = char.lower() + a = ord(char) + if 97 <= a <= 122: + a = a - ord('a') + 1 + byte = _byte(a) + return self.fileobj.write(byte), byte + d = {'@': 0, '`': 0, + '[': 27, '{': 27, + '\\': 28, '|': 28, + ']': 29, '}': 29, + '^': 30, '~': 30, + '_': 31, + '?': 127} + if char not in d: + return 0, b'' + + byte = _byte(d[char]) + return self.fileobj.write(byte), byte + + def sendeof(self): + '''This sends an EOF to the child. This sends a character which causes + the pending parent output buffer to be sent to the waiting child + program without waiting for end-of-line. If it is the first character + of the line, the read() in the user program returns 0, which signifies + end-of-file. This means to work as expected a sendeof() has to be + called at the beginning of a line. This method does not send a newline. + It is the responsibility of the caller to ensure the eof is sent at the + beginning of a line. ''' + + return self.fileobj.write(_EOF), _EOF + + def sendintr(self): + '''This sends a SIGINT to the child. It does not require + the SIGINT to be the first character on a line. ''' + + return self.fileobj.write(_INTR), _INTR + + def eof(self): + '''This returns True if the EOF exception was ever raised. + ''' + + return self.flag_eof + + def terminate(self, force=False): + '''This forces a child process to terminate. It starts nicely with + SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This + returns True if the child was terminated. This returns False if the + child could not be terminated. ''' + + if not self.isalive(): + return True + try: + self.kill(signal.SIGHUP) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + self.kill(signal.SIGCONT) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + self.kill(signal.SIGINT) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + if force: + self.kill(signal.SIGKILL) + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + else: + return False + return False + except OSError: + # I think there are kernel timing issues that sometimes cause + # this to happen. I think isalive() reports True, but the + # process is dead to the kernel. + # Make one last attempt to see if the kernel is up to date. + time.sleep(self.delayafterterminate) + if not self.isalive(): + return True + else: + return False + + def wait(self): + '''This waits until the child exits. This is a blocking call. This will + not read any data from the child, so this will block forever if the + child has unread output and has terminated. In other words, the child + may have printed output then called exit(), but, the child is + technically still alive until its output is read by the parent. ''' + + if self.isalive(): + pid, status = os.waitpid(self.pid, 0) + else: + return self.exitstatus + self.exitstatus = os.WEXITSTATUS(status) + if os.WIFEXITED(status): + self.status = status + self.exitstatus = os.WEXITSTATUS(status) + self.signalstatus = None + self.terminated = True + elif os.WIFSIGNALED(status): + self.status = status + self.exitstatus = None + self.signalstatus = os.WTERMSIG(status) + self.terminated = True + elif os.WIFSTOPPED(status): # pragma: no cover + # You can't call wait() on a child process in the stopped state. + raise PtyProcessError('Called wait() on a stopped child ' + + 'process. This is not supported. Is some other ' + + 'process attempting job control with our child pid?') + return self.exitstatus + + def isalive(self): + '''This tests if the child process is running or not. This is + non-blocking. If the child was terminated then this will read the + exitstatus or signalstatus of the child. This returns True if the child + process appears to be running or False if not. It can take literally + SECONDS for Solaris to return the right status. ''' + + if self.terminated: + return False + + if self.flag_eof: + # This is for Linux, which requires the blocking form + # of waitpid to get the status of a defunct process. + # This is super-lame. The flag_eof would have been set + # in read_nonblocking(), so this should be safe. + waitpid_options = 0 + else: + waitpid_options = os.WNOHANG + + try: + pid, status = os.waitpid(self.pid, waitpid_options) + except OSError as e: + # No child processes + if e.errno == errno.ECHILD: + raise PtyProcessError('isalive() encountered condition ' + + 'where "terminated" is 0, but there was no child ' + + 'process. Did someone else call waitpid() ' + + 'on our process?') + else: + raise + + # I have to do this twice for Solaris. + # I can't even believe that I figured this out... + # If waitpid() returns 0 it means that no child process + # wishes to report, and the value of status is undefined. + if pid == 0: + try: + ### os.WNOHANG) # Solaris! + pid, status = os.waitpid(self.pid, waitpid_options) + except OSError as e: # pragma: no cover + # This should never happen... + if e.errno == errno.ECHILD: + raise PtyProcessError('isalive() encountered condition ' + + 'that should never happen. There was no child ' + + 'process. Did someone else call waitpid() ' + + 'on our process?') + else: + raise + + # If pid is still 0 after two calls to waitpid() then the process + # really is alive. This seems to work on all platforms, except for + # Irix which seems to require a blocking call on waitpid or select, + # so I let read_nonblocking take care of this situation + # (unfortunately, this requires waiting through the timeout). + if pid == 0: + return True + + if pid == 0: + return True + + if os.WIFEXITED(status): + self.status = status + self.exitstatus = os.WEXITSTATUS(status) + self.signalstatus = None + self.terminated = True + elif os.WIFSIGNALED(status): + self.status = status + self.exitstatus = None + self.signalstatus = os.WTERMSIG(status) + self.terminated = True + elif os.WIFSTOPPED(status): + raise PtyProcessError('isalive() encountered condition ' + + 'where child process is stopped. This is not ' + + 'supported. Is some other process attempting ' + + 'job control with our child pid?') + return False + + def kill(self, sig): + """Send the given signal to the child application. + + In keeping with UNIX tradition it has a misleading name. It does not + necessarily kill the child unless you send the right signal. See the + :mod:`signal` module for constants representing signal numbers. + """ + + # Same as os.kill, but the pid is given for you. + if self.isalive(): + os.kill(self.pid, sig) + + def getwinsize(self): + """Return the window size of the pseudoterminal as a tuple (rows, cols). + """ + TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912) + s = struct.pack('HHHH', 0, 0, 0, 0) + x = fcntl.ioctl(self.fd, TIOCGWINSZ, s) + return struct.unpack('HHHH', x)[0:2] + + def setwinsize(self, rows, cols): + """Set the terminal window size of the child tty. + + This will cause a SIGWINCH signal to be sent to the child. This does not + change the physical window size. It changes the size reported to + TTY-aware applications like vi or curses -- applications that respond to + the SIGWINCH signal. + """ + return _setwinsize(self.fd, rows, cols) + + +class PtyProcessUnicode(PtyProcess): + """Unicode wrapper around a process running in a pseudoterminal. + + This class exposes a similar interface to :class:`PtyProcess`, but its read + methods return unicode, and its :meth:`write` accepts unicode. + """ + if PY3: + string_type = str + else: + string_type = unicode # analysis:ignore + + def __init__(self, pid, fd, encoding='utf-8', codec_errors='strict'): + super(PtyProcessUnicode, self).__init__(pid, fd) + self.encoding = encoding + self.codec_errors = codec_errors + self.decoder = codecs.getincrementaldecoder(encoding)(errors=codec_errors) + + def read(self, size=1024): + """Read at most ``size`` bytes from the pty, return them as unicode. + + Can block if there is nothing to read. Raises :exc:`EOFError` if the + terminal was closed. + + The size argument still refers to bytes, not unicode code points. + """ + b = super(PtyProcessUnicode, self).read(size) + return self.decoder.decode(b, final=False) + + def readline(self): + """Read one line from the pseudoterminal, and return it as unicode. + + Can block if there is nothing to read. Raises :exc:`EOFError` if the + terminal was closed. + """ + b = super(PtyProcessUnicode, self).readline() + return self.decoder.decode(b, final=False) + + def write(self, s): + """Write the unicode string ``s`` to the pseudoterminal. + + Returns the number of bytes written. + """ + b = s.encode(self.encoding) + return super(PtyProcessUnicode, self).write(b) diff --git a/pipenv/vendor/ptyprocess/util.py b/pipenv/vendor/ptyprocess/util.py new file mode 100644 index 00000000..d7fb7b27 --- /dev/null +++ b/pipenv/vendor/ptyprocess/util.py @@ -0,0 +1,67 @@ +try: + from shutil import which # Python >= 3.3 +except ImportError: + import os, sys + + # This is copied from Python 3.4.1 + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + + """ + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + + # If we're given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to the + # current directory, e.g. ./script + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + # The current directory takes precedence on Windows. + if not os.curdir in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given "python.exe". + # If it does match, only test that one, otherwise we have to try + # others. + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + # On other platforms you don't have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if not normdir in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None \ No newline at end of file diff --git a/pipenv/vendor/requests/__init__.py b/pipenv/vendor/requests/__init__.py new file mode 100644 index 00000000..1665d4b9 --- /dev/null +++ b/pipenv/vendor/requests/__init__.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# __ +# /__) _ _ _ _ _/ _ +# / ( (- (/ (/ (- _) / _) +# / + +""" +Requests HTTP library +~~~~~~~~~~~~~~~~~~~~~ + +Requests is an HTTP library, written in Python, for human beings. Basic GET +usage: + + >>> import requests + >>> r = requests.get('https://www.python.org') + >>> r.status_code + 200 + >>> 'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('http://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key2": "value2", + "key1": "value1" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at . + +:copyright: (c) 2016 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +__title__ = 'requests' +__version__ = '2.13.0' +__build__ = 0x021300 +__author__ = 'Kenneth Reitz' +__license__ = 'Apache 2.0' +__copyright__ = 'Copyright 2016 Kenneth Reitz' + +# Attempt to enable urllib3's SNI support, if possible +try: + from .packages.urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() +except ImportError: + pass + +import warnings + +# urllib3's DependencyWarnings should be silenced. +from .packages.urllib3.exceptions import DependencyWarning +warnings.simplefilter('ignore', DependencyWarning) + +from . import utils +from .models import Request, Response, PreparedRequest +from .api import request, get, head, post, patch, put, delete, options +from .sessions import session, Session +from .status_codes import codes +from .exceptions import ( + RequestException, Timeout, URLRequired, + TooManyRedirects, HTTPError, ConnectionError, + FileModeWarning, ConnectTimeout, ReadTimeout +) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/pipenv/vendor/requests/_internal_utils.py b/pipenv/vendor/requests/_internal_utils.py new file mode 100644 index 00000000..759d9a56 --- /dev/null +++ b/pipenv/vendor/requests/_internal_utils.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +""" +requests._internal_utils +~~~~~~~~~~~~~~ + +Provides utility functions that are consumed internally by Requests +which depend on extremely few external helpers (such as compat) +""" + +from .compat import is_py2, builtin_str, str + + +def to_native_string(string, encoding='ascii'): + """Given a string object, regardless of type, returns a representation of + that string in the native string type, encoding and decoding where + necessary. This assumes ASCII unless told otherwise. + """ + if isinstance(string, builtin_str): + out = string + else: + if is_py2: + out = string.encode(encoding) + else: + out = string.decode(encoding) + + return out + + +def unicode_is_ascii(u_string): + """Determine if unicode string only contains ASCII characters. + + :param str u_string: unicode string to check. Must be unicode + and not Python 2 `str`. + :rtype: bool + """ + assert isinstance(u_string, str) + try: + u_string.encode('ascii') + return True + except UnicodeEncodeError: + return False diff --git a/pipenv/vendor/requests/adapters.py b/pipenv/vendor/requests/adapters.py new file mode 100644 index 00000000..2475879c --- /dev/null +++ b/pipenv/vendor/requests/adapters.py @@ -0,0 +1,503 @@ +# -*- coding: utf-8 -*- + +""" +requests.adapters +~~~~~~~~~~~~~~~~~ + +This module contains the transport adapters that Requests uses to define +and maintain connections. +""" + +import os.path +import socket + +from .models import Response +from .packages.urllib3.poolmanager import PoolManager, proxy_from_url +from .packages.urllib3.response import HTTPResponse +from .packages.urllib3.util import Timeout as TimeoutSauce +from .packages.urllib3.util.retry import Retry +from .compat import urlparse, basestring +from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers, + prepend_scheme_if_needed, get_auth_from_url, urldefragauth, + select_proxy, to_native_string) +from .structures import CaseInsensitiveDict +from .packages.urllib3.exceptions import ClosedPoolError +from .packages.urllib3.exceptions import ConnectTimeoutError +from .packages.urllib3.exceptions import HTTPError as _HTTPError +from .packages.urllib3.exceptions import MaxRetryError +from .packages.urllib3.exceptions import NewConnectionError +from .packages.urllib3.exceptions import ProxyError as _ProxyError +from .packages.urllib3.exceptions import ProtocolError +from .packages.urllib3.exceptions import ReadTimeoutError +from .packages.urllib3.exceptions import SSLError as _SSLError +from .packages.urllib3.exceptions import ResponseError +from .cookies import extract_cookies_to_jar +from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError, + ProxyError, RetryError, InvalidSchema) +from .auth import _basic_auth_str + +try: + from .packages.urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + def SOCKSProxyManager(*args, **kwargs): + raise InvalidSchema("Missing dependencies for SOCKS support.") + +DEFAULT_POOLBLOCK = False +DEFAULT_POOLSIZE = 10 +DEFAULT_RETRIES = 0 +DEFAULT_POOL_TIMEOUT = None + + +class BaseAdapter(object): + """The Base Transport Adapter""" + + def __init__(self): + super(BaseAdapter, self).__init__() + + def send(self, request, stream=False, timeout=None, verify=True, + cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param verify: (optional) Whether to verify SSL certificates. + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + """ + raise NotImplementedError + + def close(self): + """Cleans up adapter specific items.""" + raise NotImplementedError + + +class HTTPAdapter(BaseAdapter): + """The built-in HTTP Adapter for urllib3. + + Provides a general-case interface for Requests sessions to contact HTTP and + HTTPS urls by implementing the Transport Adapter interface. This class will + usually be created by the :class:`Session ` class under the + covers. + + :param pool_connections: The number of urllib3 connection pools to cache. + :param pool_maxsize: The maximum number of connections to save in the pool. + :param max_retries: The maximum number of retries each connection + should attempt. Note, this applies only to failed DNS lookups, socket + connections and connection timeouts, never to requests where data has + made it to the server. By default, Requests does not retry failed + connections. If you need granular control over the conditions under + which we retry a request, import urllib3's ``Retry`` class and pass + that instead. + :param pool_block: Whether the connection pool should block for connections. + + Usage:: + + >>> import requests + >>> s = requests.Session() + >>> a = requests.adapters.HTTPAdapter(max_retries=3) + >>> s.mount('http://', a) + """ + __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', + '_pool_block'] + + def __init__(self, pool_connections=DEFAULT_POOLSIZE, + pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, + pool_block=DEFAULT_POOLBLOCK): + if max_retries == DEFAULT_RETRIES: + self.max_retries = Retry(0, read=False) + else: + self.max_retries = Retry.from_int(max_retries) + self.config = {} + self.proxy_manager = {} + + super(HTTPAdapter, self).__init__() + + self._pool_connections = pool_connections + self._pool_maxsize = pool_maxsize + self._pool_block = pool_block + + self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) + + def __getstate__(self): + return dict((attr, getattr(self, attr, None)) for attr in + self.__attrs__) + + def __setstate__(self, state): + # Can't handle by adding 'proxy_manager' to self.__attrs__ because + # self.poolmanager uses a lambda function, which isn't pickleable. + self.proxy_manager = {} + self.config = {} + + for attr, value in state.items(): + setattr(self, attr, value) + + self.init_poolmanager(self._pool_connections, self._pool_maxsize, + block=self._pool_block) + + def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs): + """Initializes a urllib3 PoolManager. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param connections: The number of urllib3 connection pools to cache. + :param maxsize: The maximum number of connections to save in the pool. + :param block: Block when no free connections are available. + :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. + """ + # save these values for pickling + self._pool_connections = connections + self._pool_maxsize = maxsize + self._pool_block = block + + self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize, + block=block, strict=True, **pool_kwargs) + + def proxy_manager_for(self, proxy, **proxy_kwargs): + """Return urllib3 ProxyManager for the given proxy. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param proxy: The proxy to return a urllib3 ProxyManager for. + :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. + :returns: ProxyManager + :rtype: requests.packages.urllib3.ProxyManager + """ + if proxy in self.proxy_manager: + manager = self.proxy_manager[proxy] + elif proxy.lower().startswith('socks'): + username, password = get_auth_from_url(proxy) + manager = self.proxy_manager[proxy] = SOCKSProxyManager( + proxy, + username=username, + password=password, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs + ) + else: + proxy_headers = self.proxy_headers(proxy) + manager = self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs) + + return manager + + def cert_verify(self, conn, url, verify, cert): + """Verify a SSL certificate. This method should not be called from user + code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param conn: The urllib3 connection object associated with the cert. + :param url: The requested URL. + :param verify: Whether we should actually verify the certificate. + :param cert: The SSL certificate to verify. + """ + if url.lower().startswith('https') and verify: + + cert_loc = None + + # Allow self-specified cert location. + if verify is not True: + cert_loc = verify + + if not cert_loc: + cert_loc = DEFAULT_CA_BUNDLE_PATH + + if not cert_loc: + raise Exception("Could not find a suitable SSL CA certificate bundle.") + + conn.cert_reqs = 'CERT_REQUIRED' + + if not os.path.isdir(cert_loc): + conn.ca_certs = cert_loc + else: + conn.ca_cert_dir = cert_loc + else: + conn.cert_reqs = 'CERT_NONE' + conn.ca_certs = None + conn.ca_cert_dir = None + + if cert: + if not isinstance(cert, basestring): + conn.cert_file = cert[0] + conn.key_file = cert[1] + else: + conn.cert_file = cert + + def build_response(self, req, resp): + """Builds a :class:`Response ` object from a urllib3 + response. This should not be called from user code, and is only exposed + for use when subclassing the + :class:`HTTPAdapter ` + + :param req: The :class:`PreparedRequest ` used to generate the response. + :param resp: The urllib3 response object. + :rtype: requests.Response + """ + response = Response() + + # Fallback to None if there's no status_code, for whatever reason. + response.status_code = getattr(resp, 'status', None) + + # Make headers case-insensitive. + response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) + + # Set encoding. + response.encoding = get_encoding_from_headers(response.headers) + response.raw = resp + response.reason = response.raw.reason + + if isinstance(req.url, bytes): + response.url = req.url.decode('utf-8') + else: + response.url = req.url + + # Add new cookies from the server. + extract_cookies_to_jar(response.cookies, req, resp) + + # Give the Response some context. + response.request = req + response.connection = self + + return response + + def get_connection(self, url, proxies=None): + """Returns a urllib3 connection for the given URL. This should not be + called from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param url: The URL to connect to. + :param proxies: (optional) A Requests-style dictionary of proxies used on this request. + :rtype: requests.packages.urllib3.ConnectionPool + """ + proxy = select_proxy(url, proxies) + + if proxy: + proxy = prepend_scheme_if_needed(proxy, 'http') + proxy_manager = self.proxy_manager_for(proxy) + conn = proxy_manager.connection_from_url(url) + else: + # Only scheme should be lower case + parsed = urlparse(url) + url = parsed.geturl() + conn = self.poolmanager.connection_from_url(url) + + return conn + + def close(self): + """Disposes of any internal state. + + Currently, this closes the PoolManager and any active ProxyManager, + which closes any pooled connections. + """ + self.poolmanager.clear() + for proxy in self.proxy_manager.values(): + proxy.clear() + + def request_url(self, request, proxies): + """Obtain the url to use when making the final request. + + If the message is being sent through a HTTP proxy, the full URL has to + be used. Otherwise, we should only use the path portion of the URL. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` being sent. + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. + :rtype: str + """ + proxy = select_proxy(request.url, proxies) + scheme = urlparse(request.url).scheme + + is_proxied_http_request = (proxy and scheme != 'https') + using_socks_proxy = False + if proxy: + proxy_scheme = urlparse(proxy).scheme.lower() + using_socks_proxy = proxy_scheme.startswith('socks') + + url = request.path_url + if is_proxied_http_request and not using_socks_proxy: + url = urldefragauth(request.url) + + return url + + def add_headers(self, request, **kwargs): + """Add any headers needed by the connection. As of v2.0 this does + nothing by default, but is left for overriding by users that subclass + the :class:`HTTPAdapter `. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` to add headers to. + :param kwargs: The keyword arguments from the call to send(). + """ + pass + + def proxy_headers(self, proxy): + """Returns a dictionary of the headers to add to any request sent + through a proxy. This works with urllib3 magic to ensure that they are + correctly sent to the proxy, rather than in a tunnelled request if + CONNECT is being used. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param proxies: The url of the proxy being used for this request. + :rtype: dict + """ + headers = {} + username, password = get_auth_from_url(proxy) + + if username: + headers['Proxy-Authorization'] = _basic_auth_str(username, + password) + + return headers + + def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param verify: (optional) Whether to verify SSL certificates. + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + :rtype: requests.Response + """ + + conn = self.get_connection(request.url, proxies) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers(request) + + chunked = not (request.body is None or 'Content-Length' in request.headers) + + if isinstance(timeout, tuple): + try: + connect, read = timeout + timeout = TimeoutSauce(connect=connect, read=read) + except ValueError as e: + # this may raise a string formatting error. + err = ("Invalid timeout {0}. Pass a (connect, read) " + "timeout tuple, or a single float to set " + "both timeouts to the same value".format(timeout)) + raise ValueError(err) + else: + timeout = TimeoutSauce(connect=timeout, read=timeout) + + try: + if not chunked: + resp = conn.urlopen( + method=request.method, + url=url, + body=request.body, + headers=request.headers, + redirect=False, + assert_same_host=False, + preload_content=False, + decode_content=False, + retries=self.max_retries, + timeout=timeout + ) + + # Send the request. + else: + if hasattr(conn, 'proxy_pool'): + conn = conn.proxy_pool + + low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) + + try: + low_conn.putrequest(request.method, + url, + skip_accept_encoding=True) + + for header, value in request.headers.items(): + low_conn.putheader(header, value) + + low_conn.endheaders() + + for i in request.body: + low_conn.send(hex(len(i))[2:].encode('utf-8')) + low_conn.send(b'\r\n') + low_conn.send(i) + low_conn.send(b'\r\n') + low_conn.send(b'0\r\n\r\n') + + # Receive the response from the server + try: + # For Python 2.7+ versions, use buffering of HTTP + # responses + r = low_conn.getresponse(buffering=True) + except TypeError: + # For compatibility with Python 2.6 versions and back + r = low_conn.getresponse() + + resp = HTTPResponse.from_httplib( + r, + pool=conn, + connection=low_conn, + preload_content=False, + decode_content=False + ) + except: + # If we hit any problems here, clean up the connection. + # Then, reraise so that we can handle the actual exception. + low_conn.close() + raise + + except (ProtocolError, socket.error) as err: + raise ConnectionError(err, request=request) + + except MaxRetryError as e: + if isinstance(e.reason, ConnectTimeoutError): + # TODO: Remove this in 3.0.0: see #2811 + if not isinstance(e.reason, NewConnectionError): + raise ConnectTimeout(e, request=request) + + if isinstance(e.reason, ResponseError): + raise RetryError(e, request=request) + + if isinstance(e.reason, _ProxyError): + raise ProxyError(e, request=request) + + raise ConnectionError(e, request=request) + + except ClosedPoolError as e: + raise ConnectionError(e, request=request) + + except _ProxyError as e: + raise ProxyError(e) + + except (_SSLError, _HTTPError) as e: + if isinstance(e, _SSLError): + raise SSLError(e, request=request) + elif isinstance(e, ReadTimeoutError): + raise ReadTimeout(e, request=request) + else: + raise + + return self.build_response(request, resp) diff --git a/pipenv/vendor/requests/api.py b/pipenv/vendor/requests/api.py new file mode 100644 index 00000000..16fd1e94 --- /dev/null +++ b/pipenv/vendor/requests/api.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +""" +requests.api +~~~~~~~~~~~~ + +This module implements the Requests API. + +:copyright: (c) 2012 by Kenneth Reitz. +:license: Apache2, see LICENSE for more details. +""" + +from . import sessions + + +def request(method, url, **kwargs): + """Constructs and sends a :class:`Request `. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. + :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. + ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` + or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string + defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers + to add for the file. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How long to wait for the server to send data + before giving up, as a float, or a :ref:`(connect timeout, read + timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param verify: (optional) whether the SSL cert will be verified. A CA_BUNDLE path can also be provided. Defaults to ``True``. + :param stream: (optional) if ``False``, the response content will be immediately downloaded. + :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. + :return: :class:`Response ` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'http://httpbin.org/get') + + """ + + # By using the 'with' statement we are sure the session is closed, thus we + # avoid leaving sockets open which can trigger a ResourceWarning in some + # cases, and look like a memory leak in others. + with sessions.Session() as session: + return session.request(method=method, url=url, **kwargs) + + +def get(url, params=None, **kwargs): + """Sends a GET request. + + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return request('get', url, params=params, **kwargs) + + +def options(url, **kwargs): + """Sends a OPTIONS request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return request('options', url, **kwargs) + + +def head(url, **kwargs): + """Sends a HEAD request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return request('head', url, **kwargs) + + +def post(url, data=None, json=None, **kwargs): + """Sends a POST request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('post', url, data=data, json=json, **kwargs) + + +def put(url, data=None, **kwargs): + """Sends a PUT request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('put', url, data=data, **kwargs) + + +def patch(url, data=None, **kwargs): + """Sends a PATCH request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('patch', url, data=data, **kwargs) + + +def delete(url, **kwargs): + """Sends a DELETE request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('delete', url, **kwargs) diff --git a/pipenv/vendor/requests/auth.py b/pipenv/vendor/requests/auth.py new file mode 100644 index 00000000..510846d6 --- /dev/null +++ b/pipenv/vendor/requests/auth.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- + +""" +requests.auth +~~~~~~~~~~~~~ + +This module contains the authentication handlers for Requests. +""" + +import os +import re +import time +import hashlib +import threading +import warnings + +from base64 import b64encode + +from .compat import urlparse, str, basestring +from .cookies import extract_cookies_to_jar +from ._internal_utils import to_native_string +from .utils import parse_dict_header +from .status_codes import codes + +CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' +CONTENT_TYPE_MULTI_PART = 'multipart/form-data' + + +def _basic_auth_str(username, password): + """Returns a Basic Auth string.""" + + # "I want us to put a big-ol' comment on top of it that + # says that this behaviour is dumb but we need to preserve + # it because people are relying on it." + # - Lukasa + # + # These are here solely to maintain backwards compatibility + # for things like ints. This will be removed in 3.0.0. + if not isinstance(username, basestring): + warnings.warn( + "Non-string usernames will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({0!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(username), + category=DeprecationWarning, + ) + username = str(username) + + if not isinstance(password, basestring): + warnings.warn( + "Non-string passwords will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({0!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(password), + category=DeprecationWarning, + ) + password = str(password) + # -- End Removal -- + + if isinstance(username, str): + username = username.encode('latin1') + + if isinstance(password, str): + password = password.encode('latin1') + + authstr = 'Basic ' + to_native_string( + b64encode(b':'.join((username, password))).strip() + ) + + return authstr + + +class AuthBase(object): + """Base class that all auth implementations derive from""" + + def __call__(self, r): + raise NotImplementedError('Auth hooks must be callable.') + + +class HTTPBasicAuth(AuthBase): + """Attaches HTTP Basic Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other + + def __call__(self, r): + r.headers['Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPProxyAuth(HTTPBasicAuth): + """Attaches HTTP Proxy Authentication to a given Request object.""" + + def __call__(self, r): + r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPDigestAuth(AuthBase): + """Attaches HTTP Digest Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + # Keep state in per-thread local storage + self._thread_local = threading.local() + + def init_per_thread_state(self): + # Ensure state is initialized just once per-thread + if not hasattr(self._thread_local, 'init'): + self._thread_local.init = True + self._thread_local.last_nonce = '' + self._thread_local.nonce_count = 0 + self._thread_local.chal = {} + self._thread_local.pos = None + self._thread_local.num_401_calls = None + + def build_digest_header(self, method, url): + """ + :rtype: str + """ + + realm = self._thread_local.chal['realm'] + nonce = self._thread_local.chal['nonce'] + qop = self._thread_local.chal.get('qop') + algorithm = self._thread_local.chal.get('algorithm') + opaque = self._thread_local.chal.get('opaque') + hash_utf8 = None + + if algorithm is None: + _algorithm = 'MD5' + else: + _algorithm = algorithm.upper() + # lambdas assume digest modules are imported at the top level + if _algorithm == 'MD5' or _algorithm == 'MD5-SESS': + def md5_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.md5(x).hexdigest() + hash_utf8 = md5_utf8 + elif _algorithm == 'SHA': + def sha_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha1(x).hexdigest() + hash_utf8 = sha_utf8 + + KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) + + if hash_utf8 is None: + return None + + # XXX not implemented yet + entdig = None + p_parsed = urlparse(url) + #: path is request-uri defined in RFC 2616 which should not be empty + path = p_parsed.path or "/" + if p_parsed.query: + path += '?' + p_parsed.query + + A1 = '%s:%s:%s' % (self.username, realm, self.password) + A2 = '%s:%s' % (method, path) + + HA1 = hash_utf8(A1) + HA2 = hash_utf8(A2) + + if nonce == self._thread_local.last_nonce: + self._thread_local.nonce_count += 1 + else: + self._thread_local.nonce_count = 1 + ncvalue = '%08x' % self._thread_local.nonce_count + s = str(self._thread_local.nonce_count).encode('utf-8') + s += nonce.encode('utf-8') + s += time.ctime().encode('utf-8') + s += os.urandom(8) + + cnonce = (hashlib.sha1(s).hexdigest()[:16]) + if _algorithm == 'MD5-SESS': + HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce)) + + if not qop: + respdig = KD(HA1, "%s:%s" % (nonce, HA2)) + elif qop == 'auth' or 'auth' in qop.split(','): + noncebit = "%s:%s:%s:%s:%s" % ( + nonce, ncvalue, cnonce, 'auth', HA2 + ) + respdig = KD(HA1, noncebit) + else: + # XXX handle auth-int. + return None + + self._thread_local.last_nonce = nonce + + # XXX should the partial digests be encoded too? + base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ + 'response="%s"' % (self.username, realm, nonce, path, respdig) + if opaque: + base += ', opaque="%s"' % opaque + if algorithm: + base += ', algorithm="%s"' % algorithm + if entdig: + base += ', digest="%s"' % entdig + if qop: + base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce) + + return 'Digest %s' % (base) + + def handle_redirect(self, r, **kwargs): + """Reset num_401_calls counter on redirects.""" + if r.is_redirect: + self._thread_local.num_401_calls = 1 + + def handle_401(self, r, **kwargs): + """ + Takes the given response and tries digest-auth, if needed. + + :rtype: requests.Response + """ + + if self._thread_local.pos is not None: + # Rewind the file position indicator of the body to where + # it was to resend the request. + r.request.body.seek(self._thread_local.pos) + s_auth = r.headers.get('www-authenticate', '') + + if 'digest' in s_auth.lower() and self._thread_local.num_401_calls < 2: + + self._thread_local.num_401_calls += 1 + pat = re.compile(r'digest ', flags=re.IGNORECASE) + self._thread_local.chal = parse_dict_header(pat.sub('', s_auth, count=1)) + + # Consume content and release the original connection + # to allow our new request to reuse the same one. + r.content + r.close() + prep = r.request.copy() + extract_cookies_to_jar(prep._cookies, r.request, r.raw) + prep.prepare_cookies(prep._cookies) + + prep.headers['Authorization'] = self.build_digest_header( + prep.method, prep.url) + _r = r.connection.send(prep, **kwargs) + _r.history.append(r) + _r.request = prep + + return _r + + self._thread_local.num_401_calls = 1 + return r + + def __call__(self, r): + # Initialize per-thread state, if needed + self.init_per_thread_state() + # If we have a saved nonce, skip the 401 + if self._thread_local.last_nonce: + r.headers['Authorization'] = self.build_digest_header(r.method, r.url) + try: + self._thread_local.pos = r.body.tell() + except AttributeError: + # In the case of HTTPDigestAuth being reused and the body of + # the previous request was a file-like object, pos has the + # file position of the previous body. Ensure it's set to + # None. + self._thread_local.pos = None + r.register_hook('response', self.handle_401) + r.register_hook('response', self.handle_redirect) + self._thread_local.num_401_calls = 1 + + return r + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other diff --git a/pipenv/vendor/requests/cacert.pem b/pipenv/vendor/requests/cacert.pem new file mode 100644 index 00000000..108f9d63 --- /dev/null +++ b/pipenv/vendor/requests/cacert.pem @@ -0,0 +1,5689 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Label: "GlobalSign Root CA - R2" +# Serial: 4835703278459682885658125 +# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 +# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe +# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Label: "Verisign Class 3 Public Primary Certification Authority - G3" +# Serial: 206684696279472310254277870180966723415 +# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 +# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 +# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Low-Value Services Root" +# Serial: 1 +# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc +# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d +# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7 +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw +MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD +VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul +CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n +tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl +dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch +PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC ++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O +BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X +7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz +43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl +pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA +WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Label: "AddTrust External Root" +# Serial: 1 +# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f +# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 +# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Public Services Root" +# Serial: 1 +# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f +# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5 +# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx +MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB +ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV +BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV +6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX +GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP +dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH +1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF +62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW +BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv +b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 +IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ +iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh +4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm +XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Qualified Certificates Root" +# Serial: 1 +# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb +# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf +# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16 +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +xqE= +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: O=RSA Security Inc OU=RSA Security 2048 V3 +# Subject: O=RSA Security Inc OU=RSA Security 2048 V3 +# Label: "RSA Security 2048 v3" +# Serial: 13297492616345471454730593562152402946 +# MD5 Fingerprint: 77:0d:19:b1:21:fd:00:42:9c:3e:0c:a5:dd:0b:02:8e +# SHA1 Fingerprint: 25:01:90:19:cf:fb:d9:99:1c:b7:68:25:74:8d:94:5f:30:93:95:42 +# SHA256 Fingerprint: af:8b:67:62:a1:e5:28:22:81:61:a9:5d:5c:55:9e:e2:66:27:8f:75:d7:9e:83:01:89:a5:03:50:6a:bd:6b:4c +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 +MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp +dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX +BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy +MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp +eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg +/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl +wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh +AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 +PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu +AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR +MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc +HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ +Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO +rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch +6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 +7CAFYd4= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. +# Label: "GeoTrust Global CA" +# Serial: 144470 +# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 +# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 +# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Global CA 2" +# Serial: 1 +# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9 +# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d +# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85 +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs +IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A +PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 +Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL +TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL +5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 +S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe +2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap +EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td +EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv +/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN +A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 +abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF +I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz +4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Label: "GeoTrust Universal CA" +# Serial: 1 +# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 +# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 +# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Universal CA 2" +# Serial: 1 +# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 +# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 +# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Label: "Visa eCommerce Root" +# Serial: 25952180776285836048024890241505565794 +# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 +# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 +# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum CA O=Unizeto Sp. z o.o. +# Subject: CN=Certum CA O=Unizeto Sp. z o.o. +# Label: "Certum Root CA" +# Serial: 65568 +# MD5 Fingerprint: 2c:8f:9f:66:1d:18:90:b1:47:26:9d:8e:86:82:8c:a9 +# SHA1 Fingerprint: 62:52:dc:40:f7:11:43:a2:2f:de:9e:f7:34:8e:06:42:51:b1:81:18 +# SHA256 Fingerprint: d8:e0:fe:bc:1d:b2:e3:8d:00:94:0f:37:d2:7d:41:34:4d:99:3e:73:4b:99:d5:65:6d:97:78:d4:d8:14:36:24 +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E +jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo +ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI +ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu +Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg +AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 +HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA +uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa +TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg +xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q +CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs +6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=Secure Certificate Services O=Comodo CA Limited +# Subject: CN=Secure Certificate Services O=Comodo CA Limited +# Label: "Comodo Secure Services root" +# Serial: 1 +# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd +# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1 +# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8 +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp +ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow +fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV +BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM +cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S +HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 +CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk +3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz +6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw +Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww +DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 +5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI +gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ +aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl +izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- + +# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited +# Subject: CN=Trusted Certificate Services O=Comodo CA Limited +# Label: "Comodo Trusted Services root" +# Serial: 1 +# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27 +# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd +# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 +aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla +MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD +VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW +fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt +TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL +fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW +1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 +kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G +A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo +dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu +Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ +HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS +jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ +xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn +dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Label: "QuoVadis Root CA" +# Serial: 985026699 +# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 +# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 +# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=Sonera Class2 CA O=Sonera +# Subject: CN=Sonera Class2 CA O=Sonera +# Label: "Sonera Class 2 Root CA" +# Serial: 29 +# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb +# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 +# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- + +# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com +# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com +# Label: "UTN USERFirst Hardware Root CA" +# Serial: 91374294542884704022267039221184531197 +# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39 +# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7 +# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37 +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- + +# Issuer: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org +# Subject: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org +# Label: "Camerfirma Chambers of Commerce Root" +# Serial: 0 +# MD5 Fingerprint: b0:01:ee:14:d9:af:29:18:94:76:8e:f1:69:33:2a:84 +# SHA1 Fingerprint: 6e:3a:55:a4:19:0c:19:5c:93:84:3c:c0:db:72:2e:31:30:61:f0:b1 +# SHA256 Fingerprint: 0c:25:8a:12:a5:67:4a:ef:25:f2:8b:a7:dc:fa:ec:ee:a3:48:e5:41:e6:f5:cc:4e:e6:3b:71:b3:61:60:6a:c3 +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +# Issuer: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org +# Subject: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org +# Label: "Camerfirma Global Chambersign Root" +# Serial: 0 +# MD5 Fingerprint: c5:e6:7b:bf:06:d0:4f:43:ed:c4:7a:65:8a:fb:6b:19 +# SHA1 Fingerprint: 33:9b:6b:14:50:24:9b:55:7a:01:87:72:84:d9:e0:2f:c3:d2:d8:e9 +# SHA256 Fingerprint: ef:3c:b4:17:fc:8e:bf:6f:97:87:6c:9e:4e:ce:39:de:1e:a5:fe:64:91:41:d1:02:8b:7d:11:c0:b2:29:8c:ed +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing +# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing +# Label: "StartCom Certification Authority" +# Serial: 1 +# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16 +# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f +# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j +ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js +LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM +BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy +dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh +cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh +YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg +dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp +bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ +YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT +TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ +9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 +jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW +FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz +ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 +ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L +EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu +L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC +O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V +um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh +NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= +-----END CERTIFICATE----- + +# Issuer: O=Government Root Certification Authority +# Subject: O=Government Root Certification Authority +# Label: "Taiwan GRCA" +# Serial: 42023070807708724159991140556527066870 +# MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e +# SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9 +# SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3 +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----END CERTIFICATE----- + +# Issuer: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services +# Subject: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services +# Label: "Swisscom Root CA 1" +# Serial: 122348795730808398873664200247279986742 +# MD5 Fingerprint: f8:38:7c:77:88:df:2c:16:68:2e:c2:e2:52:4b:b8:f9 +# SHA1 Fingerprint: 5f:3a:fc:0a:8b:64:f6:86:67:34:74:df:7e:a9:a2:fe:f9:fa:7a:51 +# SHA256 Fingerprint: 21:db:20:12:36:60:bb:2e:d4:18:20:5d:a1:1e:e7:a8:5a:65:e2:bc:6e:55:b5:af:7e:78:99:c8:a2:66:d9:2e +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 +m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih +FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ +TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F +EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco +kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu +HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF +vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo +19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC +L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW +bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX +JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc +K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf +ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik +Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB +sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e +3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR +ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip +mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH +b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf +rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms +hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y +zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 +MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=Class 2 Primary CA O=Certplus +# Subject: CN=Class 2 Primary CA O=Certplus +# Label: "Certplus Class 2 Primary CA" +# Serial: 177770208045934040241468760488327595043 +# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b +# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb +# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Label: "DST Root CA X3" +# Serial: 91299735575339953335919266965803778155 +# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 +# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 +# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +# Issuer: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES +# Subject: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES +# Label: "DST ACES CA X6" +# Serial: 17771143917277623872238992636097467865 +# MD5 Fingerprint: 21:d8:4c:82:2b:99:09:33:a2:eb:14:24:8d:8e:5f:e8 +# SHA1 Fingerprint: 40:54:da:6f:1c:3f:40:74:ac:ed:0f:ec:cd:db:79:d1:53:fb:90:1d +# SHA256 Fingerprint: 76:7c:95:5a:76:41:2c:89:af:68:8e:90:a1:c7:0f:55:6c:fd:6b:60:25:db:ea:10:41:6d:7e:b6:83:1f:8c:40 +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx +ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w +MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD +VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx +FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu +ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 +gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH +fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a +ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT +ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk +c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto +dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt +aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI +hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk +QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ +h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR +rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 +9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Label: "GeoTrust Primary Certification Authority" +# Serial: 32798226551256963324313806436981982369 +# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf +# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 +# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA" +# Serial: 69529181992039203566298953787712940909 +# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 +# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 +# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" +# Serial: 33037644167568058970164719475676101450 +# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c +# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 +# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA +# Subject: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA +# Label: "WellsSecure Public Root Certificate Authority" +# Serial: 1 +# MD5 Fingerprint: 15:ac:a5:c2:92:2d:79:bc:e8:7f:cb:67:ed:02:cf:36 +# SHA1 Fingerprint: e7:b4:f6:9d:61:ec:90:69:db:7e:90:a7:40:1a:3c:f4:7d:4f:e8:ee +# SHA256 Fingerprint: a7:12:72:ae:aa:a3:cf:e8:72:7f:7f:b3:9f:0f:b3:d1:e5:42:6e:90:60:b0:6e:e6:f1:3e:9a:3c:58:33:cd:43 +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx +IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs +cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 +MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl +bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD +DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r +WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU +Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs +HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj +z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf +SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl +AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG +KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P +AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j +BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC +VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX +ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB +ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd +/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB +A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn +k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 +iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv +2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1 +# Label: "Security Communication EV RootCA1" +# Serial: 0 +# MD5 Fingerprint: 22:2d:a6:01:ea:7c:0a:f7:f0:6c:56:43:3f:77:76:d3 +# SHA1 Fingerprint: fe:b8:c4:32:dc:f9:76:9a:ce:ae:3d:d8:90:8f:fd:28:86:65:64:7d +# SHA256 Fingerprint: a2:2d:ba:68:1e:97:37:6e:2d:39:7d:72:8a:ae:3a:9b:62:96:b9:fd:ba:60:bc:2e:11:f6:47:f2:c6:75:fb:37 +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz +MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N +IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 +bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE +RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO +zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 +bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF +MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 +VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC +OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW +tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ +q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb +EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ +Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O +VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GA CA" +# Serial: 86718877871133159090080555911823548314 +# MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93 +# SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9 +# SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5 +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA +# Subject: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA +# Label: "Microsec e-Szigno Root CA" +# Serial: 272122594155480254301341951808045322001 +# MD5 Fingerprint: f0:96:b6:2f:c5:10:d5:67:8e:83:25:32:e8:5e:2e:e5 +# SHA1 Fingerprint: 23:88:c9:d3:71:cc:9e:96:3d:ff:7d:3c:a7:ce:fc:d6:25:ec:19:0d +# SHA256 Fingerprint: 32:7a:3d:76:1a:ba:de:a0:34:eb:99:84:06:27:5c:b1:a4:77:6e:fd:ae:2f:df:6d:01:68:ea:1c:4f:55:67:d0 +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAw +cjELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNy +b3NlYyBMdGQuMRQwEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9z +ZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4 +NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMN +TWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMTGU1p +Y3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2u +uO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+ +LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabA +vjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770 +Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx +62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcB +AQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3Aw +LQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAP +BgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIB +AQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1L1NaU1ov +MIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5 +ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABT +AHoAbwBsAGcA4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABh +ACAAcwB6AGUAcgBpAG4AdAAgAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABo +AHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBa +AFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6Ly93d3cuZS1zemln +bm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NOPU1p +Y3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxP +PU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv +Y2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuB +EGluZm9AZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWdu +w7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWlj +cm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNV +HSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJI +VTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDAS +BgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBS +b290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS +8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds +ZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl +7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfR +hUZLphK3dehKyVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/ +MPMMNz7UwiiAc7EBt51alhQBS6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Label: "Deutsche Telekom Root CA 2" +# Serial: 38 +# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08 +# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf +# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3 +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc +# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc +# Label: "Cybertrust Global Root" +# Serial: 4835703278459682877484360 +# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 +# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 +# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet SaÄŸlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik AraÅŸtırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji AraÅŸtırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi +# Subject: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet SaÄŸlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik AraÅŸtırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji AraÅŸtırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi +# Label: "T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3" +# Serial: 17 +# MD5 Fingerprint: ed:41:f5:8c:50:c5:2b:9c:73:e6:ee:6c:eb:c2:a8:26 +# SHA1 Fingerprint: 1b:4b:39:61:26:27:6b:64:91:a2:68:6d:d7:02:43:21:2d:1f:1d:96 +# SHA256 Fingerprint: e4:c7:34:30:d7:a5:b5:09:25:df:43:37:0a:0d:21:6e:9a:79:b9:d6:db:83:73:a0:c6:9e:b1:cc:31:c7:c5:2a +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS +MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp +bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw +VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy +YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy +dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe +Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx +GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls +aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU +QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh +xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 +aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr +IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h +gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK +O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO +fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw +lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID +AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP +NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t +wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM +7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh +gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n +oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs +yZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327 +# Label: "Buypass Class 2 CA 1" +# Serial: 1 +# MD5 Fingerprint: b8:08:9a:f0:03:cc:1b:0d:c8:6c:0b:76:a1:75:64:23 +# SHA1 Fingerprint: a0:a1:ab:90:c9:fc:84:7b:3b:12:61:e8:97:7d:5f:d3:22:61:d3:cc +# SHA256 Fingerprint: 0f:4e:9c:dd:26:4b:02:55:50:d1:70:80:63:40:21:4f:e9:44:34:c9:b0:2f:69:7e:c7:10:fc:5f:ea:fb:5e:38 +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg +Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL +MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD +VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 +ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX +l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB +HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B +5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 +WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP +gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ +DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu +BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs +h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk +LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=CNNIC ROOT O=CNNIC +# Subject: CN=CNNIC ROOT O=CNNIC +# Label: "CNNIC ROOT" +# Serial: 1228079105 +# MD5 Fingerprint: 21:bc:82:ab:49:c4:13:3b:4b:b2:2b:5c:6b:90:9c:19 +# SHA1 Fingerprint: 8b:af:4c:9b:1d:f0:2a:92:f7:da:12:8e:b9:1b:ac:f4:98:60:4b:6f +# SHA256 Fingerprint: e2:83:93:77:3d:a8:45:a6:79:f2:08:0c:c7:fb:44:a3:b7:a1:c3:79:2c:b7:eb:77:29:fd:cb:6a:8d:99:ae:a7 +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD +TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 +MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF +Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh +IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 +dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO +V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC +GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN +v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB +AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB +Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO +76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK +OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH +ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi +yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL +buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj +2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= +-----END CERTIFICATE----- + +# Issuer: O=Japanese Government OU=ApplicationCA +# Subject: O=Japanese Government OU=ApplicationCA +# Label: "ApplicationCA - Japanese Government" +# Serial: 49 +# MD5 Fingerprint: 7e:23:4e:5b:a7:a5:b4:25:e9:00:07:74:11:62:ae:d6 +# SHA1 Fingerprint: 7f:8a:b0:cf:d0:51:87:6a:66:f3:36:0f:47:c8:8d:8c:d3:35:fc:74 +# SHA256 Fingerprint: 2d:47:43:7d:e1:79:51:21:5a:12:f3:c5:8e:51:c7:29:a5:80:26:ef:1f:cc:0a:5f:b3:d9:dc:01:2f:60:0d:19 +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc +MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp +b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT +AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs +aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H +j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K +f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 +IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw +FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht +QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm +/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ +k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ +MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC +seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ +hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ +eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U +DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj +B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G3" +# Serial: 28809105769928564313984085209975885599 +# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 +# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd +# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G2" +# Serial: 71758320672825410020661621085256472406 +# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f +# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 +# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G3" +# Serial: 127614157056681299805556476275995414779 +# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 +# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 +# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G2" +# Serial: 80682863203381065782177908751794619243 +# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a +# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 +# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Universal Root Certification Authority" +# Serial: 85209574734084581917763752644031726877 +# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 +# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 +# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" +# Serial: 63143484348153506665311985501458640051 +# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 +# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a +# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) FÅ‘tanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) FÅ‘tanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) +# Label: "NetLock Arany (Class Gold) FÅ‘tanúsítvány" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G2" +# Serial: 10000012 +# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a +# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16 +# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=ACEDICOM Root O=EDICOM OU=PKI +# Subject: CN=ACEDICOM Root O=EDICOM OU=PKI +# Label: "ACEDICOM Root" +# Serial: 7029493972724711941 +# MD5 Fingerprint: 42:81:a0:e2:1c:e3:55:10:de:55:89:42:65:96:22:e6 +# SHA1 Fingerprint: e0:b4:32:2e:b2:f6:a5:68:b6:54:53:84:48:18:4a:50:36:87:43:84 +# SHA256 Fingerprint: 03:95:0f:b4:9a:53:1f:3e:19:91:94:23:98:df:a9:e0:ea:32:d7:ba:1c:dd:9b:c8:5d:b5:7e:d9:40:0b:43:4a +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE +AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x +CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW +MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF +RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7 +09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7 +XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P +Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK +t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb +X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28 +MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU +fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI +2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH +K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae +ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP +BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ +MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw +RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm +fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3 +gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe +I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i +5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi +ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn +MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ +o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6 +zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN +GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt +r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK +Z05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Label: "Chambers of Commerce Root - 2008" +# Serial: 11806822484801597146 +# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 +# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c +# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- + +# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Label: "Global Chambersign Root - 2008" +# Serial: 14541511773111788494 +# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 +# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c +# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903 +# Subject: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903 +# Label: "Certinomis - Autorité Racine" +# Serial: 1 +# MD5 Fingerprint: 7f:30:78:8c:03:e3:ca:c9:0a:e2:c9:ea:1e:aa:55:1a +# SHA1 Fingerprint: 2e:14:da:ec:28:f0:fa:1e:8e:38:9a:4e:ab:eb:26:c0:0a:d3:83:c3 +# SHA256 Fingerprint: fc:bf:e2:88:62:06:f7:2b:27:59:3c:8b:07:02:97:e1:2d:76:9e:d1:0e:d7:93:07:05:a8:09:8e:ff:c1:4d:17 +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk +BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 +Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl +cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 +aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY +F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N +8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe +rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K +/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu +7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC +28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 +lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E +nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB +0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 +5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj +WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN +jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s +ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM +OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q +619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn +2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj +o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v +nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG +5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq +pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb +dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 +BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +# Issuer: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA +# Subject: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA +# Label: "Root CA Generalitat Valenciana" +# Serial: 994436456 +# MD5 Fingerprint: 2c:8c:17:5e:b1:54:ab:93:17:b5:36:5a:db:d1:c6:f2 +# SHA1 Fingerprint: a0:73:e5:c5:bd:43:61:0d:86:4c:21:13:0a:85:58:57:cc:9c:ea:46 +# SHA256 Fingerprint: 8c:4e:df:d0:43:48:f3:22:96:9e:7e:29:a4:cd:4d:ca:00:46:55:06:1c:16:e1:b0:76:42:2e:f3:42:ad:63:0e +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJF +UzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJ +R1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcN +MDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3WjBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScw +JQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+ +WmmmO3I2F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKj +SgbwJ/BXufjpTjJ3Cj9BZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGl +u6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQD0EbtFpKd71ng+CT516nDOeB0/RSrFOy +A8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXteJajCq+TA81yc477OMUxk +Hl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMBAAGjggM7 +MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBr +aS5ndmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIIC +IwYKKwYBBAG/VQIBADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8A +cgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIA +YQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIAYQBsAGkAdABhAHQAIABWAGEA +bABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQByAGEAYwBpAPMA +bgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMA +aQBvAG4AYQBtAGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQA +ZQAgAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA +YwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBuAHQAcgBhACAAZQBuACAAbABhACAA +ZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcA +LgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0dHA6 +Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+y +eAT8MIGVBgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQsw +CQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0G +A1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVu +Y2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRhTvW1yEICKrNcda3Fbcrn +lD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdzCkj+IHLt +b8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg +9J63NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XF +ducTZnV+ZfsBn5OHiJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmC +IoaZM3Fa6hlXPZHNqcCjbgcTpsnt+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2011" +# Serial: 0 +# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 +# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d +# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: O=Trustis Limited OU=Trustis FPS Root CA +# Subject: O=Trustis Limited OU=Trustis FPS Root CA +# Label: "Trustis FPS Root CA" +# Serial: 36053640375399034304724988975563710553 +# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d +# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 +# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing +# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing +# Label: "StartCom Certification Authority" +# Serial: 45 +# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16 +# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0 +# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11 +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC +ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w +ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk +aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 +YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg +c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 +d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG +CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF +wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS +Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst +0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc +pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl +CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF +P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK +1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm +KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ +8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm +fyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd. +# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd. +# Label: "StartCom Certification Authority G2" +# Serial: 59 +# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64 +# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17 +# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95 +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 +OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG +A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ +JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD +vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo +D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ +Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW +RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK +HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN +nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM +0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i +UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 +Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg +TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL +BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX +UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl +6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK +9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ +HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI +wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY +XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l +IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo +hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr +so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Label: "EE Certification Centre Root CA" +# Serial: 112324828676200291871926431888494945866 +# MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f +# SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7 +# SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76 +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----END CERTIFICATE----- + +# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. (c) Aralık 2007 +# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. (c) Aralık 2007 +# Label: "TURKTRUST Certificate Services Provider Root 2007" +# Serial: 1 +# MD5 Fingerprint: 2b:70:20:56:86:82:a0:18:c8:07:53:12:28:70:21:72 +# SHA1 Fingerprint: f1:7f:6f:b6:31:dc:99:e3:a3:c8:7f:fe:1c:f1:81:10:88:d9:60:33 +# SHA256 Fingerprint: 97:8c:d9:66:f2:fa:a0:7b:a7:aa:95:00:d9:c0:2e:9d:77:f2:cd:ad:a6:ad:6b:a7:4a:f4:b9:1c:66:59:3c:50 +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx +OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry +b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC +VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE +sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F +ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY +KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG ++7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG +HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P +IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M +733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk +Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW +AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 +mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa +XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ +qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Raiz del Estado Venezolano O=Sistema Nacional de Certificacion Electronica OU=Superintendencia de Servicios de Certificacion Electronica +# Subject: CN=PSCProcert O=Sistema Nacional de Certificacion Electronica OU=Proveedor de Certificados PROCERT +# Label: "PSCProcert" +# Serial: 11 +# MD5 Fingerprint: e6:24:e9:12:01:ae:0c:de:8e:85:c4:ce:a3:12:dd:ec +# SHA1 Fingerprint: 70:c1:8d:74:b4:28:81:0a:e4:fd:a5:75:d7:01:9f:99:b0:3d:50:74 +# SHA256 Fingerprint: 3c:fc:3c:14:d1:f6:84:ff:17:e3:8c:43:ca:44:0c:00:b9:67:ec:93:3e:8b:fe:06:4c:a1:d7:2c:90:f2:ad:b0 +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1 +dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s +YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz +dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 +aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh +IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ +KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEw +MFoXDTIwMTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHBy +b2NlcnQubmV0LnZlMQ8wDQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGEx +KjAoBgNVBAsTIVByb3ZlZWRvciBkZSBDZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQG +A1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9u +aWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo9 +7BVCwfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74 +BCXfgI8Qhd19L3uA3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38G +ieU89RLAu9MLmV+QfI4tL3czkkohRqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9 +JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmOEO8GqQKJ/+MMbpfg353bIdD0 +PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG20qCZyFSTXai2 +0b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/ +6mnbVSKVUyqUtd+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1m +v6JpIzi4mWCZDlZTOpx+FIywBm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7 +K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvpr2uKGcfLFFb14dq12fy/czja+eev +bqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/AgEBMDcGA1UdEgQw +MC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0w +MB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFD +gBStuyIdxuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0 +b3JpZGFkIGRlIENlcnRpZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xh +bm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0 +cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRp +ZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEg +ZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkq +hkiG9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQD +AgEGME0GA1UdEQRGMESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0w +MDAwMDKgGwYFYIZeAgKgEgwQUklGLUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEag +RKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9sY3IvQ0VSVElGSUNBRE8t +UkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNyYWl6LnN1c2Nl +cnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsG +AQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcN +AQELBQADggIBACtZ6yKZu4SqT96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS +1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmNg7+mvTV+LFwxNG9s2/NkAZiqlCxB +3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4quxtxj7mkoP3Yldmv +Wb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1n8Gh +HVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHm +pHmJWhSnFFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXz +sOfIt+FTvZLm8wyWuevo5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bE +qCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq3TNWOByyrYDT13K9mmyZY+gAu0F2Bbdb +mRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5poLWccret9W6aAjtmcz9 +opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3YeMLEYC/H +YvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +# Issuer: CN=China Internet Network Information Center EV Certificates Root O=China Internet Network Information Center +# Subject: CN=China Internet Network Information Center EV Certificates Root O=China Internet Network Information Center +# Label: "China Internet Network Information Center EV Certificates Root" +# Serial: 1218379777 +# MD5 Fingerprint: 55:5d:63:00:97:bd:6a:97:f5:67:ab:4b:fb:6e:63:15 +# SHA1 Fingerprint: 4f:99:aa:93:fb:2b:d1:37:26:a1:99:4a:ce:7f:f0:05:f2:93:5d:1e +# SHA256 Fingerprint: 1c:01:c6:f4:db:b2:fe:fc:22:55:8b:2b:ca:32:56:3f:49:84:4a:cf:c3:2b:7b:e4:b0:ff:59:9f:9e:8c:7a:f7 +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC +Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g +Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 +aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa +Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg +SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo +aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp +ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z +7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// +DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx +zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 +hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs +4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u +gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY +NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 +j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG +52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB +echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI +zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy +wy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +# Issuer: CN=Swisscom Root CA 2 O=Swisscom OU=Digital Certificate Services +# Subject: CN=Swisscom Root CA 2 O=Swisscom OU=Digital Certificate Services +# Label: "Swisscom Root CA 2" +# Serial: 40698052477090394928831521023204026294 +# MD5 Fingerprint: 5b:04:69:ec:a5:83:94:63:18:a7:86:d0:e4:f2:6e:19 +# SHA1 Fingerprint: 77:47:4f:c6:30:e4:0f:4c:47:64:3f:84:ba:b8:c6:95:4a:8a:41:ec +# SHA256 Fingerprint: f0:9b:12:2c:71:14:f4:a0:9b:d4:ea:4f:4a:99:d5:58:b4:6e:4c:25:cd:81:14:0d:29:c0:56:13:91:4c:38:41 +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr +jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r +0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f +2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP +ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF +y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA +tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL +6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 +uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL +acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh +k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q +VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh +b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R +fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv +/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI +REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx +srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv +aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT +woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n +Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W +t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N +8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 +9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 +wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +# Issuer: CN=Swisscom Root EV CA 2 O=Swisscom OU=Digital Certificate Services +# Subject: CN=Swisscom Root EV CA 2 O=Swisscom OU=Digital Certificate Services +# Label: "Swisscom Root EV CA 2" +# Serial: 322973295377129385374608406479535262296 +# MD5 Fingerprint: 7b:30:34:9f:dd:0a:4b:6b:35:ca:31:51:28:5d:ae:ec +# SHA1 Fingerprint: e7:a1:90:29:d3:d5:52:dc:0d:0f:c6:92:d3:ea:88:0d:15:2e:1a:6b +# SHA256 Fingerprint: d9:5f:ea:3c:a4:ee:dc:e7:4c:d7:6e:75:fc:6d:1f:f6:2c:44:1f:0f:a8:bc:77:f0:34:b1:9e:5d:b2:58:01:5d +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw +ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp +dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 +IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD +VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy +dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg +MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx +UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD +1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH +oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR +HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ +5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv +idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL +OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC +NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f +46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB +UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth +7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB +bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x +XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T +PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 +Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 +WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL +Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm +7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S +nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN +vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB +WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI +fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb +I+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R1 O=Disig a.s. +# Subject: CN=CA Disig Root R1 O=Disig a.s. +# Label: "CA Disig Root R1" +# Serial: 14052245610670616104 +# MD5 Fingerprint: be:ec:11:93:9a:f5:69:21:bc:d7:c1:c0:67:89:cc:2a +# SHA1 Fingerprint: 8e:1c:74:f8:a6:20:b9:e5:8a:f4:61:fa:ec:2b:47:56:51:1a:52:c6 +# SHA256 Fingerprint: f9:6f:23:f4:c3:e7:9c:07:7a:46:98:8d:5a:f5:90:06:76:a0:f0:39:cb:64:5d:d1:75:49:b2:16:c8:24:40:ce +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy +MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk +D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o +OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A +fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe +IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n +oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK +/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj +rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD +3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE +7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC +yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd +qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI +hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA +SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo +HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB +emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC +AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb +7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x +DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk +F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF +a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT +Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-TuÄŸra EBG BiliÅŸim Teknolojileri ve Hizmetleri A.Åž. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-TuÄŸra EBG BiliÅŸim Teknolojileri ve Hizmetleri A.Åž. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=Certification Authority of WoSign O=WoSign CA Limited +# Subject: CN=Certification Authority of WoSign O=WoSign CA Limited +# Label: "WoSign" +# Serial: 125491772294754854453622855443212256657 +# MD5 Fingerprint: a1:f2:f9:b5:d2:c8:7a:74:b8:f3:05:f1:d7:e1:84:8d +# SHA1 Fingerprint: b9:42:94:bf:91:ea:8f:b6:4b:e6:10:97:c7:fb:00:13:59:b6:76:cb +# SHA256 Fingerprint: 4b:22:d5:a6:ae:c9:9f:3c:db:79:aa:5e:c0:68:38:47:9c:d5:ec:ba:71:64:f7:f2:2d:c1:d6:5f:63:d8:57:08 +-----BEGIN CERTIFICATE----- +MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBV +MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV +BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgw +MTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX +b1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvcqN +rLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1U +fcIiePyOCbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcScc +f+Hb0v1naMQFXQoOXXDX2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2 +ZjC1vt7tj/id07sBMOby8w7gLJKA84X5KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4M +x1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR+ScPewavVIMYe+HdVHpR +aG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ezEC8wQjch +zDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDar +uHqklWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221K +mYo0SLwX3OSACCK28jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvA +Sh0JWzko/amrzgD5LkhLJuYwTKVYyrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWv +HYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0CAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R8bNLtwYgFP6H +EtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 +LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJ +MuYhOZO9sxXqT2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2e +JXLOC62qx1ViC777Y7NhRCOjy+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VN +g64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC2nz4SNAzqfkHx5Xh9T71XXG68pWp +dIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes5cVAWubXbHssw1ab +R80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/EaEQ +PkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGce +xGATVdVhmVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+ +J7x6v+Db9NpSvd4MVHAxkUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMl +OtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGikpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWT +ee5Ehr7XHuQe+w== +-----END CERTIFICATE----- + +# Issuer: CN=CA 沃通根è¯ä¹¦ O=WoSign CA Limited +# Subject: CN=CA 沃通根è¯ä¹¦ O=WoSign CA Limited +# Label: "WoSign China" +# Serial: 106921963437422998931660691310149453965 +# MD5 Fingerprint: 78:83:5b:52:16:76:c4:24:3b:83:78:e8:ac:da:9a:93 +# SHA1 Fingerprint: 16:32:47:8d:89:f9:21:3a:92:00:85:63:f5:a4:a7:d3:12:40:8a:d6 +# SHA256 Fingerprint: d6:f0:34:bd:94:aa:23:3f:02:97:ec:a4:24:5b:28:39:73:e4:47:aa:59:0f:31:0c:77:f4:8f:df:83:11:22:54 +-----BEGIN CERTIFICATE----- +MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBG +MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNV +BAMMEkNBIOayg+mAmuagueivgeS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgw +MTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRl +ZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k8H/r +D195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld1 +9AXbbQs5uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExf +v5RxadmWPgxDT74wwJ85dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnk +UkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+L +NVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFyb7Ao65vh4YOhn0pdr8yb ++gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc76DbT52V +qyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6K +yX2m+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0G +AbQOXDBGVWCvOGU6yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaK +J/kR8slC/k7e3x9cxKSGhxYzoacXGKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwEC +AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUAA4ICAQBqinA4 +WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 +yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj +/feTZU7n85iYr83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6 +jBAyvd0zaziGfjk9DgNyp115j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2 +ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0AkLppRQjbbpCBhqcqBT/mhDn4t/lX +X0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97qA4bLJyuQHCH2u2n +FoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Yjj4D +u9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10l +O1Hm13ZBONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Le +ie2uPAmvylezkolwQOQvT8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR1 +2KvxAmLBsX5VYc8T1yaw15zLKYs4SgsOkI26oQ== +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 14367148294922964480859022125800977897474 +# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e +# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb +# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G3" +# Serial: 10003001 +# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37 +# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc +# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H5 O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. +# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H5 O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. +# Label: "TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H5" +# Serial: 156233699172481 +# MD5 Fingerprint: da:70:8e:f0:22:df:93:26:f6:5f:9f:d3:15:06:52:4e +# SHA1 Fingerprint: c4:18:f6:4d:46:d1:df:00:3d:27:30:13:72:43:a9:12:11:c6:75:fb +# SHA256 Fingerprint: 49:35:1b:90:34:44:c1:85:cc:dc:5c:69:3d:24:d8:55:5c:b2:08:d6:a8:14:13:07:69:9f:4a:f0:63:19:9d:78 +-----BEGIN CERTIFICATE----- +MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE +BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn +aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg +QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0 +MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD +VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 +dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom +/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR +Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3 +4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z +5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0 +hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID +AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX +SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l +VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq +URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf +peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF +Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW ++qtB4Uu2NQvAmxU= +-----END CERTIFICATE----- + +# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H6 O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. +# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H6 O=TÜRKTRUST Bilgi İletiÅŸim ve BiliÅŸim GüvenliÄŸi Hizmetleri A.Åž. +# Label: "TÜRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H6" +# Serial: 138134509972618 +# MD5 Fingerprint: f8:c5:ee:2a:6b:be:95:8d:08:f7:25:4a:ea:71:3e:46 +# SHA1 Fingerprint: 8a:5c:8c:ee:a5:03:e6:05:56:ba:d8:1b:d4:f6:c9:b0:ed:e5:2f:e0 +# SHA256 Fingerprint: 8d:e7:86:55:e1:be:7f:78:47:80:0b:93:f6:94:d2:1d:36:8c:c0:6e:03:3e:7f:ab:04:bb:5e:b9:9d:a6:b7:00 +-----BEGIN CERTIFICATE----- +MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQG +EwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdp +IMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBB +LsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBI +aXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5MDQxMFoXDTIzMTIx +NjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBLBgNV +BAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2 +ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVs +ZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdsGjW6L0UlqMACprx9MfMkU1x +eHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a2uqsxgbPJQ1BgfbBOCK9 ++bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EEDwnS3/faA +z1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0p +u5FbHH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6p +lVxiSvgNZ1GpryHV+DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMB +AAGjQjBAMB0GA1UdDgQWBBTdVRcT9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb1gNl0Oq +FlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3RfdCaqaXKGDsC +QC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy +o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKID +gI6tflEATseWhvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm +9ocJV612ph1jmv3XZch4gyt1O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsG +tAuYSyher4hYyw== +-----END CERTIFICATE----- + +# Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Label: "Certinomis - Root CA" +# Serial: 1 +# MD5 Fingerprint: 14:0a:fd:8d:a8:28:b5:38:69:db:56:7e:61:22:03:3f +# SHA1 Fingerprint: 9d:70:bb:01:a5:a4:a0:18:11:2e:f7:1c:01:b9:32:c5:34:e7:88:a8 +# SHA256 Fingerprint: 2a:99:f5:bc:11:74:b7:3c:bb:1d:62:08:84:e0:1c:34:e5:1c:cb:39:78:da:12:5f:0e:33:26:88:83:bf:41:58 +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=Certification Authority of WoSign G2 O=WoSign CA Limited +# Subject: CN=Certification Authority of WoSign G2 O=WoSign CA Limited +# Label: "Certification Authority of WoSign G2" +# Serial: 142423943073812161787490648904721057092 +# MD5 Fingerprint: c8:1c:7d:19:aa:cb:71:93:f2:50:f8:52:a8:1e:ba:60 +# SHA1 Fingerprint: fb:ed:dc:90:65:b7:27:20:37:bc:55:0c:9c:56:de:bb:f2:78:94:e1 +# SHA256 Fingerprint: d4:87:a5:6f:83:b0:74:82:e8:5e:96:33:94:c1:ec:c2:c9:e5:1d:09:03:ee:94:6b:02:c3:01:58:1e:d9:9e:16 +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBY +MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNV +BAMTJENlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDEx +MDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgxCzAJBgNVBAYTAkNOMRowGAYDVQQK +ExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPX +JYY1kBaiXW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgO +gHzKtB0TiGsOqCR3A9DuW/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg +5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg95k4ot+vElbGs/V6r+kHLXZ1L3PR8du9n +fwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BKv0mUYQs4kI9dJGwlezt5 +2eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJ +KoZIhvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8 +fHulwqZm46qwtyeYP0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G +3CE4Q3RM+zD4F3LBMvzIkRfEzFg3TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yy +SrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu+sif/a+RZQp4OBXllxcU3fng +LDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+7Q9LGOHSJDy7 +XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg= +-----END CERTIFICATE----- + +# Issuer: CN=CA WoSign ECC Root O=WoSign CA Limited +# Subject: CN=CA WoSign ECC Root O=WoSign CA Limited +# Label: "CA WoSign ECC Root" +# Serial: 138625735294506723296996289575837012112 +# MD5 Fingerprint: 80:c6:53:ee:61:82:28:72:f0:ff:21:b9:17:ca:b2:20 +# SHA1 Fingerprint: d2:7a:d2:be:ed:94:c0:a1:3c:c7:25:21:ea:5d:71:be:81:19:f3:2b +# SHA256 Fingerprint: 8b:45:da:1c:06:f7:91:eb:0c:ab:f2:6b:e5:88:f5:fb:23:16:5c:2e:61:4b:f8:85:56:2d:0d:ce:50:b2:9b:02 +-----BEGIN CERTIFICATE----- +MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQsw +CQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMT +EkNBIFdvU2lnbiBFQ0MgUm9vdDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4 +NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEb +MBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACID +YgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiUt5v8 +KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES +1ns2o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUqv3VWqP2h4syhf3RMluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB +1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0Daupn75OcsqF1NnstTJFGG+rrQIwfcf3 +aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYua/GRspBl9JrmkO5K +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=Certplus Root CA G1 O=Certplus +# Subject: CN=Certplus Root CA G1 O=Certplus +# Label: "Certplus Root CA G1" +# Serial: 1491911565779898356709731176965615564637713 +# MD5 Fingerprint: 7f:09:9c:f7:d9:b9:5c:69:69:56:d5:37:3e:14:0d:42 +# SHA1 Fingerprint: 22:fd:d0:b7:fd:a2:4e:0d:ac:49:2c:a0:ac:a6:7b:6a:1f:e3:f7:66 +# SHA256 Fingerprint: 15:2a:40:2b:fc:df:2c:d5:48:05:4d:22:75:b3:9c:7f:ca:3e:c0:97:80:78:b0:f0:ea:76:e5:61:a6:c7:43:3e +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a +iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt +6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP +0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f +6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE +EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN +1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc +h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT +mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV +4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO +WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd +Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq +hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh +66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 +/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS +S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j +2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R +Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr +RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy +6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV +V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 +g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl +++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= +-----END CERTIFICATE----- + +# Issuer: CN=Certplus Root CA G2 O=Certplus +# Subject: CN=Certplus Root CA G2 O=Certplus +# Label: "Certplus Root CA G2" +# Serial: 1492087096131536844209563509228951875861589 +# MD5 Fingerprint: a7:ee:c4:78:2d:1b:ee:2d:b9:29:ce:d6:a7:96:32:31 +# SHA1 Fingerprint: 4f:65:8e:1f:e9:06:d8:28:02:e9:54:47:41:c9:54:25:5d:69:cc:1a +# SHA256 Fingerprint: 6c:c0:50:41:e6:44:5e:74:69:6c:4c:fb:c9:f8:0f:54:3b:7e:ab:bb:44:b4:ce:6f:78:7c:6a:99:71:c4:2f:17 +-----BEGIN CERTIFICATE----- +MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat +93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x +Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj +FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG +SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch +p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal +U5ORGpOucGpnutee5WEaXw== +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G1 O=OpenTrust +# Subject: CN=OpenTrust Root CA G1 O=OpenTrust +# Label: "OpenTrust Root CA G1" +# Serial: 1492036577811947013770400127034825178844775 +# MD5 Fingerprint: 76:00:cc:81:29:cd:55:5e:88:6a:7a:2e:f7:4d:39:da +# SHA1 Fingerprint: 79:91:e8:34:f7:e2:ee:dd:08:95:01:52:e9:55:2d:14:e9:58:d5:7e +# SHA256 Fingerprint: 56:c7:71:28:d9:8c:18:d9:1b:4c:fd:ff:bc:25:ee:91:03:d4:75:8e:a2:ab:ad:82:6a:90:f3:45:7d:46:0e:b4 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b +wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX +/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0 +77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP +uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx +p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx +Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2 +TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W +G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw +vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY +EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1 +2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw +DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E +PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf +gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS +FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0 +V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P +XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I +i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t +TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91 +09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky +Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ +AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj +1oxx +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G2 O=OpenTrust +# Subject: CN=OpenTrust Root CA G2 O=OpenTrust +# Label: "OpenTrust Root CA G2" +# Serial: 1492012448042702096986875987676935573415441 +# MD5 Fingerprint: 57:24:b6:59:24:6b:ae:c8:fe:1c:0c:20:f2:c0:4e:eb +# SHA1 Fingerprint: 79:5f:88:60:c5:ab:7c:3d:92:e6:cb:f4:8d:e1:45:cd:11:ef:60:0b +# SHA256 Fingerprint: 27:99:58:29:fe:6a:75:15:c1:bf:e8:48:f9:c4:76:1d:b1:6c:22:59:29:25:7b:f4:0d:08:94:f2:9e:a8:ba:f2 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh +/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e +CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 +1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE +FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS +gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X +G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy +YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH +vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 +t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ +gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 +5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w +DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz +Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 +nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT +RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT +wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 +t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa +TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 +o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU +3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA +iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f +WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM +S1IK +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G3 O=OpenTrust +# Subject: CN=OpenTrust Root CA G3 O=OpenTrust +# Label: "OpenTrust Root CA G3" +# Serial: 1492104908271485653071219941864171170455615 +# MD5 Fingerprint: 21:37:b4:17:16:92:7b:67:46:70:a9:96:d7:a8:13:24 +# SHA1 Fingerprint: 6e:26:64:f3:56:bf:34:55:bf:d1:93:3f:7c:01:de:d8:13:da:8a:a6 +# SHA256 Fingerprint: b7:c3:62:31:70:6e:81:07:8c:36:7c:b8:96:19:8f:1e:32:08:dd:92:69:49:dd:8f:57:09:a4:10:f7:5b:62:92 +-----BEGIN CERTIFICATE----- +MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx +CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U +cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow +QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl +blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm +3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d +oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 +DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK +BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q +j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx +4nxp5V2a+EEfOzmTk51V6s2N8fvB +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Secure Server CA" +# Serial: 927650371 +# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee +# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39 +# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50 +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u +ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u +ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 +MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j +b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg +U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ +I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 +wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC +AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb +oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 +BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p +dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk +MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp +b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 +MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi +E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa +MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI +hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN +95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd +2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority +# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority +# Label: "ValiCert Class 2 VA" +# Serial: 1 +# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87 +# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6 +# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok +# Subject: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok +# Label: "NetLock Express (Class C) Root" +# Serial: 104 +# MD5 Fingerprint: 4f:eb:f1:f0:70:c2:80:63:5d:58:9f:da:12:3c:a9:c4 +# SHA1 Fingerprint: e3:92:51:2f:0a:cf:f5:05:df:f6:de:06:7f:75:37:e1:65:ea:57:4b +# SHA256 Fingerprint: 0b:5e:ed:4e:84:64:03:cf:55:e0:65:84:84:40:ed:2a:82:75:8b:f5:b9:aa:1f:25:3d:46:13:cf:a0:80:ff:3f +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD +EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X +DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw +DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u +c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr +TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA +OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC +2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW +RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P +AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW +ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 +YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz +b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO +ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB +IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs +b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s +YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg +a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g +SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 +aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg +YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg +Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY +ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g +pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 +Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok +# Subject: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok +# Label: "NetLock Business (Class B) Root" +# Serial: 105 +# MD5 Fingerprint: 39:16:aa:b9:6a:41:e1:14:69:df:9e:6c:3b:72:dc:b6 +# SHA1 Fingerprint: 87:9f:4b:ee:05:df:98:58:3b:e3:60:d6:33:e7:0d:3f:fe:98:71:af +# SHA256 Fingerprint: 39:df:7b:68:2b:7b:93:8f:84:71:54:81:cc:de:8d:60:d8:f2:2e:c5:98:87:7d:0a:aa:c1:2b:59:18:2b:03:12 +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD +EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 +OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G +A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh +Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l +dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG +SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK +gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX +iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc +Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E +BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G +SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu +b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh +bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv +Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln +aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 +IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph +biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo +ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP +UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj +YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA +bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 +sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa +n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS +NitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority +# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority +# Label: "RSA Root Certificate 1" +# Serial: 1 +# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72 +# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb +# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy +NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD +cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs +2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY +JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE +Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ +n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A +PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu +-----END CERTIFICATE----- + +# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority +# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority +# Label: "ValiCert Class 1 VA" +# Serial: 1 +# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb +# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e +# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04 +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy +NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y +LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ +TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y +TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 +LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW +I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw +nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI +-----END CERTIFICATE----- + +# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc. +# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc. +# Label: "Equifax Secure eBusiness CA 1" +# Serial: 4 +# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d +# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41 +# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73 +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT +ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw +MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j +LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo +RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu +WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw +Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK +eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM +zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ +WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN +/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc. +# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc. +# Label: "Equifax Secure Global eBusiness CA" +# Serial: 1 +# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc +# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45 +# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07 +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT +ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw +MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj +dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l +c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC +UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc +58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ +o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr +aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA +A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA +Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv +8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division +# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division +# Label: "Thawte Premium Server CA" +# Serial: 1 +# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a +# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a +# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72 +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy +dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t +MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB +MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG +A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp +b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl +cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv +bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE +VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ +ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR +uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI +hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM +pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division +# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division +# Label: "Thawte Server CA" +# Serial: 1 +# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d +# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c +# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9 +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm +MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx +MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 +dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl +cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 +DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 +yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX +L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj +EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG +7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e +QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ +qdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority +# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority +# Label: "Verisign Class 3 Public Primary Certification Authority" +# Serial: 149843929435818692848040365716851702463 +# MD5 Fingerprint: 10:fc:63:5d:f6:26:3e:0d:f3:25:be:5f:79:cd:67:67 +# SHA1 Fingerprint: 74:2c:31:92:e6:07:e4:24:eb:45:49:54:2b:e1:bb:c5:3e:61:74:e2 +# SHA256 Fingerprint: e7:68:56:34:ef:ac:f6:9a:ce:93:9a:6b:25:5b:7b:4f:ab:ef:42:93:5b:50:a2:65:ac:b5:cb:60:27:e4:4e:70 +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do +lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc +AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +-----END CERTIFICATE----- + +# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority +# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority +# Label: "Verisign Class 3 Public Primary Certification Authority" +# Serial: 80507572722862485515306429940691309246 +# MD5 Fingerprint: ef:5a:f1:33:ef:f1:cd:bb:51:02:ee:12:14:4b:96:c4 +# SHA1 Fingerprint: a1:db:63:93:91:6f:17:e4:18:55:09:40:04:15:c7:02:40:b0:ae:6b +# SHA256 Fingerprint: a4:b6:b3:99:6f:c2:f3:06:b3:fd:86:81:bd:63:41:3d:8c:50:09:cc:4f:a3:29:c2:cc:f0:e2:fa:1b:14:03:05 +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i +2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ +2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ +-----END CERTIFICATE----- + +# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network +# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network +# Label: "Verisign Class 3 Public Primary Certification Authority - G2" +# Serial: 167285380242319648451154478808036881606 +# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9 +# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f +# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- + +# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc. +# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc. +# Label: "GTE CyberTrust Global Root" +# Serial: 421 +# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db +# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74 +# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36 +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv +b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH +iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS +r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 +04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r +GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 +3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P +lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +# Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority +# Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority +# Label: "Equifax Secure Certificate Authority" +# Serial: 903804111 +# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4 +# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a +# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78 +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- diff --git a/pipenv/vendor/requests/certs.py b/pipenv/vendor/requests/certs.py new file mode 100644 index 00000000..f922b99d --- /dev/null +++ b/pipenv/vendor/requests/certs.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +requests.certs +~~~~~~~~~~~~~~ + +This module returns the preferred default CA certificate bundle. + +If you are packaging Requests, e.g., for a Linux distribution or a managed +environment, you can change the definition of where() to return a separately +packaged CA bundle. +""" +import os.path + +try: + from certifi import where +except ImportError: + def where(): + """Return the preferred certificate bundle.""" + # vendored bundle inside Requests + return os.path.join(os.path.dirname(__file__), 'cacert.pem') + +if __name__ == '__main__': + print(where()) diff --git a/pipenv/vendor/requests/compat.py b/pipenv/vendor/requests/compat.py new file mode 100644 index 00000000..f88e600d --- /dev/null +++ b/pipenv/vendor/requests/compat.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module handles import compatibility issues between Python 2 and +Python 3. +""" + +from .packages import chardet + +import sys + +# ------- +# Pythons +# ------- + +# Syntax sugar. +_ver = sys.version_info + +#: Python 2.x? +is_py2 = (_ver[0] == 2) + +#: Python 3.x? +is_py3 = (_ver[0] == 3) + +try: + import simplejson as json +except (ImportError, SyntaxError): + # simplejson does not support Python 3.2, it throws a SyntaxError + # because of u'...' Unicode literals. + import json + +# --------- +# Specifics +# --------- + +if is_py2: + from urllib import quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, proxy_bypass + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag + from urllib2 import parse_http_list + import cookielib + from Cookie import Morsel + from StringIO import StringIO + from .packages.urllib3.packages.ordered_dict import OrderedDict + + builtin_str = str + bytes = str + str = unicode + basestring = basestring + numeric_types = (int, long, float) + integer_types = (int, long) + +elif is_py3: + from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag + from urllib.request import parse_http_list, getproxies, proxy_bypass + from http import cookiejar as cookielib + from http.cookies import Morsel + from io import StringIO + from collections import OrderedDict + + builtin_str = str + str = str + bytes = bytes + basestring = (str, bytes) + numeric_types = (int, float) + integer_types = (int,) diff --git a/pipenv/vendor/requests/cookies.py b/pipenv/vendor/requests/cookies.py new file mode 100644 index 00000000..856fd45e --- /dev/null +++ b/pipenv/vendor/requests/cookies.py @@ -0,0 +1,542 @@ +# -*- coding: utf-8 -*- + +""" +requests.cookies +~~~~~~~~~~~~~~~~ + +Compatibility code to be able to use `cookielib.CookieJar` with requests. + +requests.utils imports from here, so be careful with imports. +""" + +import copy +import time +import calendar +import collections + +from ._internal_utils import to_native_string +from .compat import cookielib, urlparse, urlunparse, Morsel + +try: + import threading + # grr, pyflakes: this fixes "redefinition of unused 'threading'" + threading +except ImportError: + import dummy_threading as threading + + +class MockRequest(object): + """Wraps a `requests.Request` to mimic a `urllib2.Request`. + + The code in `cookielib.CookieJar` expects this interface in order to correctly + manage cookie policies, i.e., determine whether a cookie can be set, given the + domains of the request and the cookie. + + The original request object is read-only. The client is responsible for collecting + the new headers via `get_new_headers()` and interpreting them appropriately. You + probably want `get_cookie_header`, defined below. + """ + + def __init__(self, request): + self._r = request + self._new_headers = {} + self.type = urlparse(self._r.url).scheme + + def get_type(self): + return self.type + + def get_host(self): + return urlparse(self._r.url).netloc + + def get_origin_req_host(self): + return self.get_host() + + def get_full_url(self): + # Only return the response's URL if the user hadn't set the Host + # header + if not self._r.headers.get('Host'): + return self._r.url + # If they did set it, retrieve it and reconstruct the expected domain + host = to_native_string(self._r.headers['Host'], encoding='utf-8') + parsed = urlparse(self._r.url) + # Reconstruct the URL as we expect it + return urlunparse([ + parsed.scheme, host, parsed.path, parsed.params, parsed.query, + parsed.fragment + ]) + + def is_unverifiable(self): + return True + + def has_header(self, name): + return name in self._r.headers or name in self._new_headers + + def get_header(self, name, default=None): + return self._r.headers.get(name, self._new_headers.get(name, default)) + + def add_header(self, key, val): + """cookielib has no legitimate use for this method; add it back if you find one.""" + raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") + + def add_unredirected_header(self, name, value): + self._new_headers[name] = value + + def get_new_headers(self): + return self._new_headers + + @property + def unverifiable(self): + return self.is_unverifiable() + + @property + def origin_req_host(self): + return self.get_origin_req_host() + + @property + def host(self): + return self.get_host() + + +class MockResponse(object): + """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. + + ...what? Basically, expose the parsed HTTP headers from the server response + the way `cookielib` expects to see them. + """ + + def __init__(self, headers): + """Make a MockResponse for `cookielib` to read. + + :param headers: a httplib.HTTPMessage or analogous carrying the headers + """ + self._headers = headers + + def info(self): + return self._headers + + def getheaders(self, name): + self._headers.getheaders(name) + + +def extract_cookies_to_jar(jar, request, response): + """Extract the cookies from the response into a CookieJar. + + :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) + :param request: our own requests.Request object + :param response: urllib3.HTTPResponse object + """ + if not (hasattr(response, '_original_response') and + response._original_response): + return + # the _original_response field is the wrapped httplib.HTTPResponse object, + req = MockRequest(request) + # pull out the HTTPMessage with the headers and put it in the mock: + res = MockResponse(response._original_response.msg) + jar.extract_cookies(res, req) + + +def get_cookie_header(jar, request): + """ + Produce an appropriate Cookie header string to be sent with `request`, or None. + + :rtype: str + """ + r = MockRequest(request) + jar.add_cookie_header(r) + return r.get_new_headers().get('Cookie') + + +def remove_cookie_by_name(cookiejar, name, domain=None, path=None): + """Unsets a cookie by name, by default over all domains and paths. + + Wraps CookieJar.clear(), is O(n). + """ + clearables = [] + for cookie in cookiejar: + if cookie.name != name: + continue + if domain is not None and domain != cookie.domain: + continue + if path is not None and path != cookie.path: + continue + clearables.append((cookie.domain, cookie.path, cookie.name)) + + for domain, path, name in clearables: + cookiejar.clear(domain, path, name) + + +class CookieConflictError(RuntimeError): + """There are two cookies that meet the criteria specified in the cookie jar. + Use .get and .set and include domain and path args in order to be more specific. + """ + + +class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): + """Compatibility class; is a cookielib.CookieJar, but exposes a dict + interface. + + This is the CookieJar we create by default for requests and sessions that + don't specify one, since some clients may expect response.cookies and + session.cookies to support dict operations. + + Requests does not use the dict interface internally; it's just for + compatibility with external client code. All requests code should work + out of the box with externally provided instances of ``CookieJar``, e.g. + ``LWPCookieJar`` and ``FileCookieJar``. + + Unlike a regular CookieJar, this class is pickleable. + + .. warning:: dictionary operations that are normally O(1) may be O(n). + """ + + def get(self, name, default=None, domain=None, path=None): + """Dict-like get() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + + .. warning:: operation is O(n), not O(1). + """ + try: + return self._find_no_duplicates(name, domain, path) + except KeyError: + return default + + def set(self, name, value, **kwargs): + """Dict-like set() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + """ + # support client code that unsets cookies by assignment of a None value: + if value is None: + remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) + return + + if isinstance(value, Morsel): + c = morsel_to_cookie(value) + else: + c = create_cookie(name, value, **kwargs) + self.set_cookie(c) + return c + + def iterkeys(self): + """Dict-like iterkeys() that returns an iterator of names of cookies + from the jar. + + .. seealso:: itervalues() and iteritems(). + """ + for cookie in iter(self): + yield cookie.name + + def keys(self): + """Dict-like keys() that returns a list of names of cookies from the + jar. + + .. seealso:: values() and items(). + """ + return list(self.iterkeys()) + + def itervalues(self): + """Dict-like itervalues() that returns an iterator of values of cookies + from the jar. + + .. seealso:: iterkeys() and iteritems(). + """ + for cookie in iter(self): + yield cookie.value + + def values(self): + """Dict-like values() that returns a list of values of cookies from the + jar. + + .. seealso:: keys() and items(). + """ + return list(self.itervalues()) + + def iteritems(self): + """Dict-like iteritems() that returns an iterator of name-value tuples + from the jar. + + .. seealso:: iterkeys() and itervalues(). + """ + for cookie in iter(self): + yield cookie.name, cookie.value + + def items(self): + """Dict-like items() that returns a list of name-value tuples from the + jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a + vanilla python dict of key value pairs. + + .. seealso:: keys() and values(). + """ + return list(self.iteritems()) + + def list_domains(self): + """Utility method to list all the domains in the jar.""" + domains = [] + for cookie in iter(self): + if cookie.domain not in domains: + domains.append(cookie.domain) + return domains + + def list_paths(self): + """Utility method to list all the paths in the jar.""" + paths = [] + for cookie in iter(self): + if cookie.path not in paths: + paths.append(cookie.path) + return paths + + def multiple_domains(self): + """Returns True if there are multiple domains in the jar. + Returns False otherwise. + + :rtype: bool + """ + domains = [] + for cookie in iter(self): + if cookie.domain is not None and cookie.domain in domains: + return True + domains.append(cookie.domain) + return False # there is only one domain in jar + + def get_dict(self, domain=None, path=None): + """Takes as an argument an optional domain and path and returns a plain + old Python dict of name-value pairs of cookies that meet the + requirements. + + :rtype: dict + """ + dictionary = {} + for cookie in iter(self): + if (domain is None or cookie.domain == domain) and (path is None + or cookie.path == path): + dictionary[cookie.name] = cookie.value + return dictionary + + def __contains__(self, name): + try: + return super(RequestsCookieJar, self).__contains__(name) + except CookieConflictError: + return True + + def __getitem__(self, name): + """Dict-like __getitem__() for compatibility with client code. Throws + exception if there are more than one cookie with name. In that case, + use the more explicit get() method instead. + + .. warning:: operation is O(n), not O(1). + """ + return self._find_no_duplicates(name) + + def __setitem__(self, name, value): + """Dict-like __setitem__ for compatibility with client code. Throws + exception if there is already a cookie of that name in the jar. In that + case, use the more explicit set() method instead. + """ + self.set(name, value) + + def __delitem__(self, name): + """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s + ``remove_cookie_by_name()``. + """ + remove_cookie_by_name(self, name) + + def set_cookie(self, cookie, *args, **kwargs): + if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): + cookie.value = cookie.value.replace('\\"', '') + return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) + + def update(self, other): + """Updates this jar with cookies from another CookieJar or dict-like""" + if isinstance(other, cookielib.CookieJar): + for cookie in other: + self.set_cookie(copy.copy(cookie)) + else: + super(RequestsCookieJar, self).update(other) + + def _find(self, name, domain=None, path=None): + """Requests uses this method internally to get cookie values. + + If there are conflicting cookies, _find arbitrarily chooses one. + See _find_no_duplicates if you want an exception thrown if there are + conflicting cookies. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :return: cookie.value + """ + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + return cookie.value + + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def _find_no_duplicates(self, name, domain=None, path=None): + """Both ``__get_item__`` and ``get`` call this function: it's never + used elsewhere in Requests. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :raises KeyError: if cookie is not found + :raises CookieConflictError: if there are multiple cookies + that match name and optionally domain and path + :return: cookie.value + """ + toReturn = None + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + if toReturn is not None: # if there are multiple cookies that meet passed in criteria + raise CookieConflictError('There are multiple cookies with name, %r' % (name)) + toReturn = cookie.value # we will eventually return this as long as no cookie conflict + + if toReturn: + return toReturn + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def __getstate__(self): + """Unlike a normal CookieJar, this class is pickleable.""" + state = self.__dict__.copy() + # remove the unpickleable RLock object + state.pop('_cookies_lock') + return state + + def __setstate__(self, state): + """Unlike a normal CookieJar, this class is pickleable.""" + self.__dict__.update(state) + if '_cookies_lock' not in self.__dict__: + self._cookies_lock = threading.RLock() + + def copy(self): + """Return a copy of this RequestsCookieJar.""" + new_cj = RequestsCookieJar() + new_cj.update(self) + return new_cj + + +def _copy_cookie_jar(jar): + if jar is None: + return None + + if hasattr(jar, 'copy'): + # We're dealing with an instance of RequestsCookieJar + return jar.copy() + # We're dealing with a generic CookieJar instance + new_jar = copy.copy(jar) + new_jar.clear() + for cookie in jar: + new_jar.set_cookie(copy.copy(cookie)) + return new_jar + + +def create_cookie(name, value, **kwargs): + """Make a cookie from underspecified parameters. + + By default, the pair of `name` and `value` will be set for the domain '' + and sent on every request (this is sometimes called a "supercookie"). + """ + result = dict( + version=0, + name=name, + value=value, + port=None, + domain='', + path='/', + secure=False, + expires=None, + discard=True, + comment=None, + comment_url=None, + rest={'HttpOnly': None}, + rfc2109=False,) + + badargs = set(kwargs) - set(result) + if badargs: + err = 'create_cookie() got unexpected keyword arguments: %s' + raise TypeError(err % list(badargs)) + + result.update(kwargs) + result['port_specified'] = bool(result['port']) + result['domain_specified'] = bool(result['domain']) + result['domain_initial_dot'] = result['domain'].startswith('.') + result['path_specified'] = bool(result['path']) + + return cookielib.Cookie(**result) + + +def morsel_to_cookie(morsel): + """Convert a Morsel object into a Cookie containing the one k/v pair.""" + + expires = None + if morsel['max-age']: + try: + expires = int(time.time() + int(morsel['max-age'])) + except ValueError: + raise TypeError('max-age: %s must be integer' % morsel['max-age']) + elif morsel['expires']: + time_template = '%a, %d-%b-%Y %H:%M:%S GMT' + expires = calendar.timegm( + time.strptime(morsel['expires'], time_template) + ) + return create_cookie( + comment=morsel['comment'], + comment_url=bool(morsel['comment']), + discard=False, + domain=morsel['domain'], + expires=expires, + name=morsel.key, + path=morsel['path'], + port=None, + rest={'HttpOnly': morsel['httponly']}, + rfc2109=False, + secure=bool(morsel['secure']), + value=morsel.value, + version=morsel['version'] or 0, + ) + + +def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): + """Returns a CookieJar from a key/value dictionary. + + :param cookie_dict: Dict of key/values to insert into CookieJar. + :param cookiejar: (optional) A cookiejar to add the cookies to. + :param overwrite: (optional) If False, will not replace cookies + already in the jar with new ones. + """ + if cookiejar is None: + cookiejar = RequestsCookieJar() + + if cookie_dict is not None: + names_from_jar = [cookie.name for cookie in cookiejar] + for name in cookie_dict: + if overwrite or (name not in names_from_jar): + cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) + + return cookiejar + + +def merge_cookies(cookiejar, cookies): + """Add cookies to cookiejar and returns a merged CookieJar. + + :param cookiejar: CookieJar object to add the cookies to. + :param cookies: Dictionary or CookieJar object to be added. + """ + if not isinstance(cookiejar, cookielib.CookieJar): + raise ValueError('You can only merge into CookieJar') + + if isinstance(cookies, dict): + cookiejar = cookiejar_from_dict( + cookies, cookiejar=cookiejar, overwrite=False) + elif isinstance(cookies, cookielib.CookieJar): + try: + cookiejar.update(cookies) + except AttributeError: + for cookie_in_jar in cookies: + cookiejar.set_cookie(cookie_in_jar) + + return cookiejar diff --git a/pipenv/vendor/requests/exceptions.py b/pipenv/vendor/requests/exceptions.py new file mode 100644 index 00000000..0658e7ec --- /dev/null +++ b/pipenv/vendor/requests/exceptions.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from .packages.urllib3.exceptions import HTTPError as BaseHTTPError + + +class RequestException(IOError): + """There was an ambiguous exception that occurred while handling your + request. + """ + + def __init__(self, *args, **kwargs): + """Initialize RequestException with `request` and `response` objects.""" + response = kwargs.pop('response', None) + self.response = response + self.request = kwargs.pop('request', None) + if (response is not None and not self.request and + hasattr(response, 'request')): + self.request = self.response.request + super(RequestException, self).__init__(*args, **kwargs) + + +class HTTPError(RequestException): + """An HTTP error occurred.""" + + +class ConnectionError(RequestException): + """A Connection error occurred.""" + + +class ProxyError(ConnectionError): + """A proxy error occurred.""" + + +class SSLError(ConnectionError): + """An SSL error occurred.""" + + +class Timeout(RequestException): + """The request timed out. + + Catching this error will catch both + :exc:`~requests.exceptions.ConnectTimeout` and + :exc:`~requests.exceptions.ReadTimeout` errors. + """ + + +class ConnectTimeout(ConnectionError, Timeout): + """The request timed out while trying to connect to the remote server. + + Requests that produced this error are safe to retry. + """ + + +class ReadTimeout(Timeout): + """The server did not send any data in the allotted amount of time.""" + + +class URLRequired(RequestException): + """A valid URL is required to make a request.""" + + +class TooManyRedirects(RequestException): + """Too many redirects.""" + + +class MissingSchema(RequestException, ValueError): + """The URL schema (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """See defaults.py for valid schemas.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow invalid.""" + + +class ChunkedEncodingError(RequestException): + """The server declared chunked encoding but sent an invalid chunk.""" + + +class ContentDecodingError(RequestException, BaseHTTPError): + """Failed to decode response content""" + + +class StreamConsumedError(RequestException, TypeError): + """The content for this response was already consumed""" + + +class RetryError(RequestException): + """Custom retries logic failed""" + +class UnrewindableBodyError(RequestException): + """Requests encountered an error when trying to rewind a body""" + +# Warnings + + +class RequestsWarning(Warning): + """Base warning for Requests.""" + pass + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + pass diff --git a/pipenv/vendor/requests/hooks.py b/pipenv/vendor/requests/hooks.py new file mode 100644 index 00000000..32b32de7 --- /dev/null +++ b/pipenv/vendor/requests/hooks.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +""" +requests.hooks +~~~~~~~~~~~~~~ + +This module provides the capabilities for the Requests hooks system. + +Available hooks: + +``response``: + The response generated from a Request. +""" +HOOKS = ['response'] + + +def default_hooks(): + return dict((event, []) for event in HOOKS) + +# TODO: response is the only one + + +def dispatch_hook(key, hooks, hook_data, **kwargs): + """Dispatches a hook dictionary on a given piece of data.""" + hooks = hooks or dict() + hooks = hooks.get(key) + if hooks: + if hasattr(hooks, '__call__'): + hooks = [hooks] + for hook in hooks: + _hook_data = hook(hook_data, **kwargs) + if _hook_data is not None: + hook_data = _hook_data + return hook_data diff --git a/pipenv/vendor/requests/models.py b/pipenv/vendor/requests/models.py new file mode 100644 index 00000000..d1a9c868 --- /dev/null +++ b/pipenv/vendor/requests/models.py @@ -0,0 +1,922 @@ +# -*- coding: utf-8 -*- + +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import collections +import datetime +import sys + +# Import encoding now, to avoid implicit import later. +# Implicit import within threads may cause LookupError when standard library is in a ZIP, +# such as in Embedded Python. See https://github.com/kennethreitz/requests/issues/3578. +import encodings.idna + +from io import BytesIO, UnsupportedOperation +from .hooks import default_hooks +from .structures import CaseInsensitiveDict + +from .auth import HTTPBasicAuth +from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar +from .packages.urllib3.fields import RequestField +from .packages.urllib3.filepost import encode_multipart_formdata +from .packages.urllib3.util import parse_url +from .packages.urllib3.exceptions import ( + DecodeError, ReadTimeoutError, ProtocolError, LocationParseError) +from .exceptions import ( + HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError, + ContentDecodingError, ConnectionError, StreamConsumedError) +from ._internal_utils import to_native_string, unicode_is_ascii +from .utils import ( + guess_filename, get_auth_from_url, requote_uri, + stream_decode_response_unicode, to_key_val_list, parse_header_links, + iter_slices, guess_json_utf, super_len, check_header_validity) +from .compat import ( + cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO, + is_py2, chardet, builtin_str, basestring) +from .compat import json as complexjson +from .status_codes import codes + +#: The set of HTTP status codes that indicate an automatically +#: processable redirect. +REDIRECT_STATI = ( + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 + codes.temporary_redirect, # 307 + codes.permanent_redirect, # 308 +) + +DEFAULT_REDIRECT_LIMIT = 30 +CONTENT_CHUNK_SIZE = 10 * 1024 +ITER_CHUNK_SIZE = 512 + + +class RequestEncodingMixin(object): + @property + def path_url(self): + """Build the path URL to use.""" + + url = [] + + p = urlsplit(self.url) + + path = p.path + if not path: + path = '/' + + url.append(path) + + query = p.query + if query: + url.append('?') + url.append(query) + + return ''.join(url) + + @staticmethod + def _encode_params(data): + """Encode parameters in a piece of data. + + Will successfully encode parameters when passed as a dict or a list of + 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary + if parameters are supplied as a dict. + """ + + if isinstance(data, (str, bytes)): + return data + elif hasattr(data, 'read'): + return data + elif hasattr(data, '__iter__'): + result = [] + for k, vs in to_key_val_list(data): + if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): + vs = [vs] + for v in vs: + if v is not None: + result.append( + (k.encode('utf-8') if isinstance(k, str) else k, + v.encode('utf-8') if isinstance(v, str) else v)) + return urlencode(result, doseq=True) + else: + return data + + @staticmethod + def _encode_files(files, data): + """Build the body for a multipart/form-data request. + + Will successfully encode files when passed as a dict or a list of + tuples. Order is retained if data is a list of tuples but arbitrary + if parameters are supplied as a dict. + The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) + or 4-tuples (filename, fileobj, contentype, custom_headers). + """ + if (not files): + raise ValueError("Files must be provided.") + elif isinstance(data, basestring): + raise ValueError("Data must not be a string.") + + new_fields = [] + fields = to_key_val_list(data or {}) + files = to_key_val_list(files or {}) + + for field, val in fields: + if isinstance(val, basestring) or not hasattr(val, '__iter__'): + val = [val] + for v in val: + if v is not None: + # Don't call str() on bytestrings: in Py3 it all goes wrong. + if not isinstance(v, bytes): + v = str(v) + + new_fields.append( + (field.decode('utf-8') if isinstance(field, bytes) else field, + v.encode('utf-8') if isinstance(v, str) else v)) + + for (k, v) in files: + # support for explicit filename + ft = None + fh = None + if isinstance(v, (tuple, list)): + if len(v) == 2: + fn, fp = v + elif len(v) == 3: + fn, fp, ft = v + else: + fn, fp, ft, fh = v + else: + fn = guess_filename(v) or k + fp = v + + if isinstance(fp, (str, bytes, bytearray)): + fdata = fp + else: + fdata = fp.read() + + rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) + rf.make_multipart(content_type=ft) + new_fields.append(rf) + + body, content_type = encode_multipart_formdata(new_fields) + + return body, content_type + + +class RequestHooksMixin(object): + def register_hook(self, event, hook): + """Properly register a hook.""" + + if event not in self.hooks: + raise ValueError('Unsupported event specified, with event name "%s"' % (event)) + + if isinstance(hook, collections.Callable): + self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if isinstance(h, collections.Callable)) + + def deregister_hook(self, event, hook): + """Deregister a previously registered hook. + Returns True if the hook existed, False if not. + """ + + try: + self.hooks[event].remove(hook) + return True + except ValueError: + return False + + +class Request(RequestHooksMixin): + """A user-created :class:`Request ` object. + + Used to prepare a :class:`PreparedRequest `, which is sent to the server. + + :param method: HTTP method to use. + :param url: URL to send. + :param headers: dictionary of headers to send. + :param files: dictionary of {filename: fileobject} files to multipart upload. + :param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place. + :param json: json for the body to attach to the request (if files or data is not specified). + :param params: dictionary of URL parameters to append to the URL. + :param auth: Auth handler or (user, pass) tuple. + :param cookies: dictionary or CookieJar of cookies to attach to this request. + :param hooks: dictionary of callback hooks, for internal usage. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'http://httpbin.org/get') + >>> req.prepare() + + """ + + def __init__(self, method=None, url=None, headers=None, files=None, + data=None, params=None, auth=None, cookies=None, hooks=None, json=None): + + # Default empty dicts for dict params. + data = [] if data is None else data + files = [] if files is None else files + headers = {} if headers is None else headers + params = {} if params is None else params + hooks = {} if hooks is None else hooks + + self.hooks = default_hooks() + for (k, v) in list(hooks.items()): + self.register_hook(event=k, hook=v) + + self.method = method + self.url = url + self.headers = headers + self.files = files + self.data = data + self.json = json + self.params = params + self.auth = auth + self.cookies = cookies + + def __repr__(self): + return '' % (self.method) + + def prepare(self): + """Constructs a :class:`PreparedRequest ` for transmission and returns it.""" + p = PreparedRequest() + p.prepare( + method=self.method, + url=self.url, + headers=self.headers, + files=self.files, + data=self.data, + json=self.json, + params=self.params, + auth=self.auth, + cookies=self.cookies, + hooks=self.hooks, + ) + return p + + +class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): + """The fully mutable :class:`PreparedRequest ` object, + containing the exact bytes that will be sent to the server. + + Generated from either a :class:`Request ` object or manually. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'http://httpbin.org/get') + >>> r = req.prepare() + + + >>> s = requests.Session() + >>> s.send(r) + + """ + + def __init__(self): + #: HTTP verb to send to the server. + self.method = None + #: HTTP URL to send the request to. + self.url = None + #: dictionary of HTTP headers. + self.headers = None + # The `CookieJar` used to create the Cookie header will be stored here + # after prepare_cookies is called + self._cookies = None + #: request body to send to the server. + self.body = None + #: dictionary of callback hooks, for internal usage. + self.hooks = default_hooks() + #: integer denoting starting position of a readable file-like body. + self._body_position = None + + def prepare(self, method=None, url=None, headers=None, files=None, + data=None, params=None, auth=None, cookies=None, hooks=None, json=None): + """Prepares the entire request with the given parameters.""" + + self.prepare_method(method) + self.prepare_url(url, params) + self.prepare_headers(headers) + self.prepare_cookies(cookies) + self.prepare_body(data, files, json) + self.prepare_auth(auth, url) + + # Note that prepare_auth must be last to enable authentication schemes + # such as OAuth to work on a fully prepared request. + + # This MUST go after prepare_auth. Authenticators could add a hook + self.prepare_hooks(hooks) + + def __repr__(self): + return '' % (self.method) + + def copy(self): + p = PreparedRequest() + p.method = self.method + p.url = self.url + p.headers = self.headers.copy() if self.headers is not None else None + p._cookies = _copy_cookie_jar(self._cookies) + p.body = self.body + p.hooks = self.hooks + p._body_position = self._body_position + return p + + def prepare_method(self, method): + """Prepares the given HTTP method.""" + self.method = method + if self.method is not None: + self.method = to_native_string(self.method.upper()) + + @staticmethod + def _get_idna_encoded_host(host): + try: + from .packages import idna + except ImportError: + # tolerate the possibility of downstream repackagers unvendoring `requests` + # For more information, read: packages/__init__.py + import idna + sys.modules['requests.packages.idna'] = idna + + try: + host = idna.encode(host, uts46=True).decode('utf-8') + except idna.IDNAError: + raise UnicodeError + return host + + def prepare_url(self, url, params): + """Prepares the given HTTP URL.""" + #: Accept objects that have string representations. + #: We're unable to blindly call unicode/str functions + #: as this will include the bytestring indicator (b'') + #: on python 3.x. + #: https://github.com/kennethreitz/requests/pull/2238 + if isinstance(url, bytes): + url = url.decode('utf8') + else: + url = unicode(url) if is_py2 else str(url) + + # Remove leading whitespaces from url + url = url.lstrip() + + # Don't do any URL preparation for non-HTTP schemes like `mailto`, + # `data` etc to work around exceptions from `url_parse`, which + # handles RFC 3986 only. + if ':' in url and not url.lower().startswith('http'): + self.url = url + return + + # Support for unicode domain names and paths. + try: + scheme, auth, host, port, path, query, fragment = parse_url(url) + except LocationParseError as e: + raise InvalidURL(*e.args) + + if not scheme: + error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?") + error = error.format(to_native_string(url, 'utf8')) + + raise MissingSchema(error) + + if not host: + raise InvalidURL("Invalid URL %r: No host supplied" % url) + + # In general, we want to try IDNA encoding the hostname if the string contains + # non-ASCII characters. This allows users to automatically get the correct IDNA + # behaviour. For strings containing only ASCII characters, we need to also verify + # it doesn't start with a wildcard (*), before allowing the unencoded hostname. + if not unicode_is_ascii(host): + try: + host = self._get_idna_encoded_host(host) + except UnicodeError: + raise InvalidURL('URL has an invalid label.') + elif host.startswith(u'*'): + raise InvalidURL('URL has an invalid label.') + + # Carefully reconstruct the network location + netloc = auth or '' + if netloc: + netloc += '@' + netloc += host + if port: + netloc += ':' + str(port) + + # Bare domains aren't valid URLs. + if not path: + path = '/' + + if is_py2: + if isinstance(scheme, str): + scheme = scheme.encode('utf-8') + if isinstance(netloc, str): + netloc = netloc.encode('utf-8') + if isinstance(path, str): + path = path.encode('utf-8') + if isinstance(query, str): + query = query.encode('utf-8') + if isinstance(fragment, str): + fragment = fragment.encode('utf-8') + + if isinstance(params, (str, bytes)): + params = to_native_string(params) + + enc_params = self._encode_params(params) + if enc_params: + if query: + query = '%s&%s' % (query, enc_params) + else: + query = enc_params + + url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment])) + self.url = url + + def prepare_headers(self, headers): + """Prepares the given HTTP headers.""" + + self.headers = CaseInsensitiveDict() + if headers: + for header in headers.items(): + # Raise exception on invalid header value. + check_header_validity(header) + name, value = header + self.headers[to_native_string(name)] = value + + def prepare_body(self, data, files, json=None): + """Prepares the given HTTP body data.""" + + # Check if file, fo, generator, iterator. + # If not, run through normal process. + + # Nottin' on you. + body = None + content_type = None + + if not data and json is not None: + # urllib3 requires a bytes-like body. Python 2's json.dumps + # provides this natively, but Python 3 gives a Unicode string. + content_type = 'application/json' + body = complexjson.dumps(json) + if not isinstance(body, bytes): + body = body.encode('utf-8') + + is_stream = all([ + hasattr(data, '__iter__'), + not isinstance(data, (basestring, list, tuple, collections.Mapping)) + ]) + + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + if is_stream: + body = data + + if getattr(body, 'tell', None) is not None: + # Record the current file position before reading. + # This will allow us to rewind a file in the event + # of a redirect. + try: + self._body_position = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body + self._body_position = object() + + if files: + raise NotImplementedError('Streamed bodies and files are mutually exclusive.') + + if length: + self.headers['Content-Length'] = builtin_str(length) + else: + self.headers['Transfer-Encoding'] = 'chunked' + else: + # Multi-part file uploads. + if files: + (body, content_type) = self._encode_files(files, data) + else: + if data: + body = self._encode_params(data) + if isinstance(data, basestring) or hasattr(data, 'read'): + content_type = None + else: + content_type = 'application/x-www-form-urlencoded' + + self.prepare_content_length(body) + + # Add content-type if it wasn't explicitly provided. + if content_type and ('content-type' not in self.headers): + self.headers['Content-Type'] = content_type + + self.body = body + + def prepare_content_length(self, body): + """Prepare Content-Length header based on request method and body""" + if body is not None: + length = super_len(body) + if length: + # If length exists, set it. Otherwise, we fallback + # to Transfer-Encoding: chunked. + self.headers['Content-Length'] = builtin_str(length) + elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None: + # Set Content-Length to 0 for methods that can have a body + # but don't provide one. (i.e. not GET or HEAD) + self.headers['Content-Length'] = '0' + + def prepare_auth(self, auth, url=''): + """Prepares the given HTTP auth data.""" + + # If no Auth is explicitly provided, extract it from the URL first. + if auth is None: + url_auth = get_auth_from_url(self.url) + auth = url_auth if any(url_auth) else None + + if auth: + if isinstance(auth, tuple) and len(auth) == 2: + # special-case basic HTTP auth + auth = HTTPBasicAuth(*auth) + + # Allow auth to make its changes. + r = auth(self) + + # Update self to reflect the auth changes. + self.__dict__.update(r.__dict__) + + # Recompute Content-Length + self.prepare_content_length(self.body) + + def prepare_cookies(self, cookies): + """Prepares the given HTTP cookie data. + + This function eventually generates a ``Cookie`` header from the + given cookies using cookielib. Due to cookielib's design, the header + will not be regenerated if it already exists, meaning this function + can only be called once for the life of the + :class:`PreparedRequest ` object. Any subsequent calls + to ``prepare_cookies`` will have no actual effect, unless the "Cookie" + header is removed beforehand. + """ + if isinstance(cookies, cookielib.CookieJar): + self._cookies = cookies + else: + self._cookies = cookiejar_from_dict(cookies) + + cookie_header = get_cookie_header(self._cookies, self) + if cookie_header is not None: + self.headers['Cookie'] = cookie_header + + def prepare_hooks(self, hooks): + """Prepares the given hooks.""" + # hooks can be passed as None to the prepare method and to this + # method. To prevent iterating over None, simply use an empty list + # if hooks is False-y + hooks = hooks or [] + for event in hooks: + self.register_hook(event, hooks[event]) + + +class Response(object): + """The :class:`Response ` object, which contains a + server's response to an HTTP request. + """ + + __attrs__ = [ + '_content', 'status_code', 'headers', 'url', 'history', + 'encoding', 'reason', 'cookies', 'elapsed', 'request' + ] + + def __init__(self): + super(Response, self).__init__() + + self._content = False + self._content_consumed = False + + #: Integer Code of responded HTTP Status, e.g. 404 or 200. + self.status_code = None + + #: Case-insensitive Dictionary of Response Headers. + #: For example, ``headers['content-encoding']`` will return the + #: value of a ``'Content-Encoding'`` response header. + self.headers = CaseInsensitiveDict() + + #: File-like object representation of response (for advanced usage). + #: Use of ``raw`` requires that ``stream=True`` be set on the request. + # This requirement does not apply for use internally to Requests. + self.raw = None + + #: Final URL location of Response. + self.url = None + + #: Encoding to decode with when accessing r.text. + self.encoding = None + + #: A list of :class:`Response ` objects from + #: the history of the Request. Any redirect responses will end + #: up here. The list is sorted from the oldest to the most recent request. + self.history = [] + + #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". + self.reason = None + + #: A CookieJar of Cookies the server sent back. + self.cookies = cookiejar_from_dict({}) + + #: The amount of time elapsed between sending the request + #: and the arrival of the response (as a timedelta). + #: This property specifically measures the time taken between sending + #: the first byte of the request and finishing parsing the headers. It + #: is therefore unaffected by consuming the response content or the + #: value of the ``stream`` keyword argument. + self.elapsed = datetime.timedelta(0) + + #: The :class:`PreparedRequest ` object to which this + #: is a response. + self.request = None + + def __getstate__(self): + # Consume everything; accessing the content attribute makes + # sure the content has been fully read. + if not self._content_consumed: + self.content + + return dict( + (attr, getattr(self, attr, None)) + for attr in self.__attrs__ + ) + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + # pickled objects do not have .raw + setattr(self, '_content_consumed', True) + setattr(self, 'raw', None) + + def __repr__(self): + return '' % (self.status_code) + + def __bool__(self): + """Returns true if :attr:`status_code` is 'OK'.""" + return self.ok + + def __nonzero__(self): + """Returns true if :attr:`status_code` is 'OK'.""" + return self.ok + + def __iter__(self): + """Allows you to use a response as an iterator.""" + return self.iter_content(128) + + @property + def ok(self): + try: + self.raise_for_status() + except HTTPError: + return False + return True + + @property + def is_redirect(self): + """True if this Response is a well-formed HTTP redirect that could have + been processed automatically (by :meth:`Session.resolve_redirects`). + """ + return ('location' in self.headers and self.status_code in REDIRECT_STATI) + + @property + def is_permanent_redirect(self): + """True if this Response one of the permanent versions of redirect""" + return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect)) + + @property + def apparent_encoding(self): + """The apparent encoding, provided by the chardet library""" + return chardet.detect(self.content)['encoding'] + + def iter_content(self, chunk_size=1, decode_unicode=False): + """Iterates over the response data. When stream=True is set on the + request, this avoids reading the content at once into memory for + large responses. The chunk size is the number of bytes it should + read into memory. This is not necessarily the length of each item + returned as decoding can take place. + + chunk_size must be of type int or None. A value of None will + function differently depending on the value of `stream`. + stream=True will read data as it arrives in whatever size the + chunks are received. If stream=False, data is returned as + a single chunk. + + If decode_unicode is True, content will be decoded using the best + available encoding based on the response. + """ + + def generate(): + # Special case for urllib3. + if hasattr(self.raw, 'stream'): + try: + for chunk in self.raw.stream(chunk_size, decode_content=True): + yield chunk + except ProtocolError as e: + raise ChunkedEncodingError(e) + except DecodeError as e: + raise ContentDecodingError(e) + except ReadTimeoutError as e: + raise ConnectionError(e) + else: + # Standard file-like object. + while True: + chunk = self.raw.read(chunk_size) + if not chunk: + break + yield chunk + + self._content_consumed = True + + if self._content_consumed and isinstance(self._content, bool): + raise StreamConsumedError() + elif chunk_size is not None and not isinstance(chunk_size, int): + raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size)) + # simulate reading small chunks of the content + reused_chunks = iter_slices(self._content, chunk_size) + + stream_chunks = generate() + + chunks = reused_chunks if self._content_consumed else stream_chunks + + if decode_unicode: + chunks = stream_decode_response_unicode(chunks, self) + + return chunks + + def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter=None): + """Iterates over the response data, one line at a time. When + stream=True is set on the request, this avoids reading the + content at once into memory for large responses. + + .. note:: This method is not reentrant safe. + """ + + pending = None + + for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): + + if pending is not None: + chunk = pending + chunk + + if delimiter: + lines = chunk.split(delimiter) + else: + lines = chunk.splitlines() + + if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: + pending = lines.pop() + else: + pending = None + + for line in lines: + yield line + + if pending is not None: + yield pending + + @property + def content(self): + """Content of the response, in bytes.""" + + if self._content is False: + # Read the contents. + if self._content_consumed: + raise RuntimeError( + 'The content for this response was already consumed') + + if self.status_code == 0 or self.raw is None: + self._content = None + else: + self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes() + + self._content_consumed = True + # don't need to release the connection; that's been handled by urllib3 + # since we exhausted the data. + return self._content + + @property + def text(self): + """Content of the response, in unicode. + + If Response.encoding is None, encoding will be guessed using + ``chardet``. + + The encoding of the response content is determined based solely on HTTP + headers, following RFC 2616 to the letter. If you can take advantage of + non-HTTP knowledge to make a better guess at the encoding, you should + set ``r.encoding`` appropriately before accessing this property. + """ + + # Try charset from content-type + content = None + encoding = self.encoding + + if not self.content: + return str('') + + # Fallback to auto-detected encoding. + if self.encoding is None: + encoding = self.apparent_encoding + + # Decode unicode from given encoding. + try: + content = str(self.content, encoding, errors='replace') + except (LookupError, TypeError): + # A LookupError is raised if the encoding was not found which could + # indicate a misspelling or similar mistake. + # + # A TypeError can be raised if encoding is None + # + # So we try blindly encoding. + content = str(self.content, errors='replace') + + return content + + def json(self, **kwargs): + """Returns the json-encoded content of a response, if any. + + :param \*\*kwargs: Optional arguments that ``json.loads`` takes. + :raises ValueError: If the response body does not contain valid json. + """ + + if not self.encoding and self.content and len(self.content) > 3: + # No encoding set. JSON RFC 4627 section 3 states we should expect + # UTF-8, -16 or -32. Detect which one to use; If the detection or + # decoding fails, fall back to `self.text` (using chardet to make + # a best guess). + encoding = guess_json_utf(self.content) + if encoding is not None: + try: + return complexjson.loads( + self.content.decode(encoding), **kwargs + ) + except UnicodeDecodeError: + # Wrong UTF codec detected; usually because it's not UTF-8 + # but some other 8-bit codec. This is an RFC violation, + # and the server didn't bother to tell us what codec *was* + # used. + pass + return complexjson.loads(self.text, **kwargs) + + @property + def links(self): + """Returns the parsed header links of the response, if any.""" + + header = self.headers.get('link') + + # l = MultiDict() + l = {} + + if header: + links = parse_header_links(header) + + for link in links: + key = link.get('rel') or link.get('url') + l[key] = link + + return l + + def raise_for_status(self): + """Raises stored :class:`HTTPError`, if one occurred.""" + + http_error_msg = '' + if isinstance(self.reason, bytes): + # We attempt to decode utf-8 first because some servers + # choose to localize their reason strings. If the string + # isn't utf-8, we fall back to iso-8859-1 for all other + # encodings. (See PR #3538) + try: + reason = self.reason.decode('utf-8') + except UnicodeDecodeError: + reason = self.reason.decode('iso-8859-1') + else: + reason = self.reason + + if 400 <= self.status_code < 500: + http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url) + + elif 500 <= self.status_code < 600: + http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url) + + if http_error_msg: + raise HTTPError(http_error_msg, response=self) + + def close(self): + """Releases the connection back to the pool. Once this method has been + called the underlying ``raw`` object must not be accessed again. + + *Note: Should not normally need to be called explicitly.* + """ + if not self._content_consumed: + self.raw.close() + + release_conn = getattr(self.raw, 'release_conn', None) + if release_conn is not None: + release_conn() diff --git a/pipenv/vendor/requests/packages/__init__.py b/pipenv/vendor/requests/packages/__init__.py new file mode 100644 index 00000000..971c2ad0 --- /dev/null +++ b/pipenv/vendor/requests/packages/__init__.py @@ -0,0 +1,36 @@ +''' +Debian and other distributions "unbundle" requests' vendored dependencies, and +rewrite all imports to use the global versions of ``urllib3`` and ``chardet``. +The problem with this is that not only requests itself imports those +dependencies, but third-party code outside of the distros' control too. + +In reaction to these problems, the distro maintainers replaced +``requests.packages`` with a magical "stub module" that imports the correct +modules. The implementations were varying in quality and all had severe +problems. For example, a symlink (or hardlink) that links the correct modules +into place introduces problems regarding object identity, since you now have +two modules in `sys.modules` with the same API, but different identities:: + + requests.packages.urllib3 is not urllib3 + +With version ``2.5.2``, requests started to maintain its own stub, so that +distro-specific breakage would be reduced to a minimum, even though the whole +issue is not requests' fault in the first place. See +https://github.com/kennethreitz/requests/pull/2375 for the corresponding pull +request. +''' + +from __future__ import absolute_import +import sys + +try: + from . import urllib3 +except ImportError: + import urllib3 + sys.modules['%s.urllib3' % __name__] = urllib3 + +try: + from . import chardet +except ImportError: + import chardet + sys.modules['%s.chardet' % __name__] = chardet diff --git a/pipenv/vendor/requests/packages/chardet/__init__.py b/pipenv/vendor/requests/packages/chardet/__init__.py new file mode 100644 index 00000000..82c2a48d --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/__init__.py @@ -0,0 +1,32 @@ +######################## BEGIN LICENSE BLOCK ######################## +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +__version__ = "2.3.0" +from sys import version_info + + +def detect(aBuf): + if ((version_info < (3, 0) and isinstance(aBuf, unicode)) or + (version_info >= (3, 0) and not isinstance(aBuf, bytes))): + raise ValueError('Expected a bytes object, not a unicode object') + + from . import universaldetector + u = universaldetector.UniversalDetector() + u.reset() + u.feed(aBuf) + u.close() + return u.result diff --git a/pipenv/vendor/requests/packages/chardet/big5freq.py b/pipenv/vendor/requests/packages/chardet/big5freq.py new file mode 100644 index 00000000..65bffc04 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/big5freq.py @@ -0,0 +1,925 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Big5 frequency table +# by Taiwan's Mandarin Promotion Council +# +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +Big5CharToFreqOrder = ( + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 #last 512 +#Everything below is of no interest for detection purpose +2522,1613,4812,5799,3345,3945,2523,5800,4162,5801,1637,4163,2471,4813,3946,5802, # 5392 +2500,3034,3800,5803,5804,2195,4814,5805,2163,5806,5807,5808,5809,5810,5811,5812, # 5408 +5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828, # 5424 +5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844, # 5440 +5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860, # 5456 +5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876, # 5472 +5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892, # 5488 +5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908, # 5504 +5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,5924, # 5520 +5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,5939,5940, # 5536 +5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,5954,5955,5956, # 5552 +5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5970,5971,5972, # 5568 +5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984,5985,5986,5987,5988, # 5584 +5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004, # 5600 +6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020, # 5616 +6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036, # 5632 +6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052, # 5648 +6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068, # 5664 +6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084, # 5680 +6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100, # 5696 +6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116, # 5712 +6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132, # 5728 +6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148, # 5744 +6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,6164, # 5760 +6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179,6180, # 5776 +6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196, # 5792 +6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212, # 5808 +6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,3670,6224,6225,6226,6227, # 5824 +6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241,6242,6243, # 5840 +6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259, # 5856 +6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275, # 5872 +6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,4815,6286,6287,6288,6289,6290, # 5888 +6291,6292,4816,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305, # 5904 +6306,6307,6308,6309,6310,6311,4817,4818,6312,6313,6314,6315,6316,6317,6318,4819, # 5920 +6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334, # 5936 +6335,6336,6337,4820,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349, # 5952 +6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365, # 5968 +6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381, # 5984 +6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397, # 6000 +6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,3441,6411,6412, # 6016 +6413,6414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,4440,6426,6427, # 6032 +6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443, # 6048 +6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,4821,6455,6456,6457,6458, # 6064 +6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474, # 6080 +6475,6476,6477,3947,3948,6478,6479,6480,6481,3272,4441,6482,6483,6484,6485,4442, # 6096 +6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,6496,4822,6497,6498,6499,6500, # 6112 +6501,6502,6503,6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516, # 6128 +6517,6518,6519,6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532, # 6144 +6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548, # 6160 +6549,6550,6551,6552,6553,6554,6555,6556,2784,6557,4823,6558,6559,6560,6561,6562, # 6176 +6563,6564,6565,6566,6567,6568,6569,3949,6570,6571,6572,4824,6573,6574,6575,6576, # 6192 +6577,6578,6579,6580,6581,6582,6583,4825,6584,6585,6586,3950,2785,6587,6588,6589, # 6208 +6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605, # 6224 +6606,6607,6608,6609,6610,6611,6612,4826,6613,6614,6615,4827,6616,6617,6618,6619, # 6240 +6620,6621,6622,6623,6624,6625,4164,6626,6627,6628,6629,6630,6631,6632,6633,6634, # 6256 +3547,6635,4828,6636,6637,6638,6639,6640,6641,6642,3951,2984,6643,6644,6645,6646, # 6272 +6647,6648,6649,4165,6650,4829,6651,6652,4830,6653,6654,6655,6656,6657,6658,6659, # 6288 +6660,6661,6662,4831,6663,6664,6665,6666,6667,6668,6669,6670,6671,4166,6672,4832, # 6304 +3952,6673,6674,6675,6676,4833,6677,6678,6679,4167,6680,6681,6682,3198,6683,6684, # 6320 +6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,4834,6698,6699, # 6336 +6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715, # 6352 +6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731, # 6368 +6732,6733,6734,4443,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,4444, # 6384 +6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761, # 6400 +6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777, # 6416 +6778,6779,6780,6781,4168,6782,6783,3442,6784,6785,6786,6787,6788,6789,6790,6791, # 6432 +4169,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806, # 6448 +6807,6808,6809,6810,6811,4835,6812,6813,6814,4445,6815,6816,4446,6817,6818,6819, # 6464 +6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835, # 6480 +3548,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,4836,6847,6848,6849, # 6496 +6850,6851,6852,6853,6854,3953,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864, # 6512 +6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,3199,6878,6879, # 6528 +6880,6881,6882,4447,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894, # 6544 +6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,4170,6905,6906,6907,6908,6909, # 6560 +6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925, # 6576 +6926,6927,4837,6928,6929,6930,6931,6932,6933,6934,6935,6936,3346,6937,6938,4838, # 6592 +6939,6940,6941,4448,6942,6943,6944,6945,6946,4449,6947,6948,6949,6950,6951,6952, # 6608 +6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968, # 6624 +6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984, # 6640 +6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,3671,6995,6996,6997,6998,4839, # 6656 +6999,7000,7001,7002,3549,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013, # 6672 +7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029, # 6688 +7030,4840,7031,7032,7033,7034,7035,7036,7037,7038,4841,7039,7040,7041,7042,7043, # 6704 +7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059, # 6720 +7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,2985,7071,7072,7073,7074, # 6736 +7075,7076,7077,7078,7079,7080,4842,7081,7082,7083,7084,7085,7086,7087,7088,7089, # 6752 +7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105, # 6768 +7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,4450,7119,7120, # 6784 +7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136, # 6800 +7137,7138,7139,7140,7141,7142,7143,4843,7144,7145,7146,7147,7148,7149,7150,7151, # 6816 +7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167, # 6832 +7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183, # 6848 +7184,7185,7186,7187,7188,4171,4172,7189,7190,7191,7192,7193,7194,7195,7196,7197, # 6864 +7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213, # 6880 +7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229, # 6896 +7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245, # 6912 +7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261, # 6928 +7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277, # 6944 +7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293, # 6960 +7294,7295,7296,4844,7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308, # 6976 +7309,7310,7311,7312,7313,7314,7315,7316,4451,7317,7318,7319,7320,7321,7322,7323, # 6992 +7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339, # 7008 +7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,4173,7354, # 7024 +7355,4845,7356,7357,7358,7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369, # 7040 +7370,7371,7372,7373,7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385, # 7056 +7386,7387,7388,4846,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400, # 7072 +7401,7402,7403,7404,7405,3672,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415, # 7088 +7416,7417,7418,7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431, # 7104 +7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447, # 7120 +7448,7449,7450,7451,7452,7453,4452,7454,3200,7455,7456,7457,7458,7459,7460,7461, # 7136 +7462,7463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,4847,7475,7476, # 7152 +7477,3133,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491, # 7168 +7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,3347,7503,7504,7505,7506, # 7184 +7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,4848, # 7200 +7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537, # 7216 +7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,3801,4849,7550,7551, # 7232 +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, # 7248 +7568,7569,3035,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582, # 7264 +7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598, # 7280 +7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614, # 7296 +7615,7616,4850,7617,7618,3802,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628, # 7312 +7629,7630,7631,7632,4851,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643, # 7328 +7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659, # 7344 +7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,4453,7671,7672,7673,7674, # 7360 +7675,7676,7677,7678,7679,7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690, # 7376 +7691,7692,7693,7694,7695,7696,7697,3443,7698,7699,7700,7701,7702,4454,7703,7704, # 7392 +7705,7706,7707,7708,7709,7710,7711,7712,7713,2472,7714,7715,7716,7717,7718,7719, # 7408 +7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7731,3954,7732,7733,7734, # 7424 +7735,7736,7737,7738,7739,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7750, # 7440 +3134,7751,7752,4852,7753,7754,7755,4853,7756,7757,7758,7759,7760,4174,7761,7762, # 7456 +7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,7777,7778, # 7472 +7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794, # 7488 +7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,4854,7806,7807,7808,7809, # 7504 +7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824,7825, # 7520 +4855,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7536 +7841,7842,7843,7844,7845,7846,7847,3955,7848,7849,7850,7851,7852,7853,7854,7855, # 7552 +7856,7857,7858,7859,7860,3444,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870, # 7568 +7871,7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886, # 7584 +7887,7888,7889,7890,7891,4175,7892,7893,7894,7895,7896,4856,4857,7897,7898,7899, # 7600 +7900,2598,7901,7902,7903,7904,7905,7906,7907,7908,4455,7909,7910,7911,7912,7913, # 7616 +7914,3201,7915,7916,7917,7918,7919,7920,7921,4858,7922,7923,7924,7925,7926,7927, # 7632 +7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943, # 7648 +7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7958,7959, # 7664 +7960,7961,7962,7963,7964,7965,7966,7967,7968,7969,7970,7971,7972,7973,7974,7975, # 7680 +7976,7977,7978,7979,7980,7981,4859,7982,7983,7984,7985,7986,7987,7988,7989,7990, # 7696 +7991,7992,7993,7994,7995,7996,4860,7997,7998,7999,8000,8001,8002,8003,8004,8005, # 7712 +8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,4176,8017,8018,8019,8020, # 7728 +8021,8022,8023,4861,8024,8025,8026,8027,8028,8029,8030,8031,8032,8033,8034,8035, # 7744 +8036,4862,4456,8037,8038,8039,8040,4863,8041,8042,8043,8044,8045,8046,8047,8048, # 7760 +8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063,8064, # 7776 +8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080, # 7792 +8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096, # 7808 +8097,8098,8099,4864,4177,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110, # 7824 +8111,8112,8113,8114,8115,8116,8117,8118,8119,8120,4178,8121,8122,8123,8124,8125, # 7840 +8126,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141, # 7856 +8142,8143,8144,8145,4865,4866,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155, # 7872 +8156,8157,8158,8159,8160,8161,8162,8163,8164,8165,4179,8166,8167,8168,8169,8170, # 7888 +8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,4457,8182,8183,8184,8185, # 7904 +8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201, # 7920 +8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217, # 7936 +8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,8233, # 7952 +8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,8248,8249, # 7968 +8250,8251,8252,8253,8254,8255,8256,3445,8257,8258,8259,8260,8261,8262,4458,8263, # 7984 +8264,8265,8266,8267,8268,8269,8270,8271,8272,4459,8273,8274,8275,8276,3550,8277, # 8000 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,4460,8290,8291,8292, # 8016 +8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,4867, # 8032 +8308,8309,8310,8311,8312,3551,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322, # 8048 +8323,8324,8325,8326,4868,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337, # 8064 +8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353, # 8080 +8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,4869,4461,8364,8365,8366,8367, # 8096 +8368,8369,8370,4870,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382, # 8112 +8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398, # 8128 +8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,4871,8411,8412,8413, # 8144 +8414,8415,8416,8417,8418,8419,8420,8421,8422,4462,8423,8424,8425,8426,8427,8428, # 8160 +8429,8430,8431,8432,8433,2986,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443, # 8176 +8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459, # 8192 +8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475, # 8208 +8476,8477,8478,4180,8479,8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490, # 8224 +8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506, # 8240 +8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522, # 8256 +8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538, # 8272 +8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554, # 8288 +8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,4872,8565,8566,8567,8568,8569, # 8304 +8570,8571,8572,8573,4873,8574,8575,8576,8577,8578,8579,8580,8581,8582,8583,8584, # 8320 +8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600, # 8336 +8601,8602,8603,8604,8605,3803,8606,8607,8608,8609,8610,8611,8612,8613,4874,3804, # 8352 +8614,8615,8616,8617,8618,8619,8620,8621,3956,8622,8623,8624,8625,8626,8627,8628, # 8368 +8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,2865,8639,8640,8641,8642,8643, # 8384 +8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,4463,8657,8658, # 8400 +8659,4875,4876,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672, # 8416 +8673,8674,8675,8676,8677,8678,8679,8680,8681,4464,8682,8683,8684,8685,8686,8687, # 8432 +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, # 8448 +8704,8705,8706,8707,8708,8709,2261,8710,8711,8712,8713,8714,8715,8716,8717,8718, # 8464 +8719,8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,4181, # 8480 +8734,8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749, # 8496 +8750,8751,8752,8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,4877,8764, # 8512 +8765,8766,8767,8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780, # 8528 +8781,8782,8783,8784,8785,8786,8787,8788,4878,8789,4879,8790,8791,8792,4880,8793, # 8544 +8794,8795,8796,8797,8798,8799,8800,8801,4881,8802,8803,8804,8805,8806,8807,8808, # 8560 +8809,8810,8811,8812,8813,8814,8815,3957,8816,8817,8818,8819,8820,8821,8822,8823, # 8576 +8824,8825,8826,8827,8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839, # 8592 +8840,8841,8842,8843,8844,8845,8846,8847,4882,8848,8849,8850,8851,8852,8853,8854, # 8608 +8855,8856,8857,8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870, # 8624 +8871,8872,8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,3202,8885, # 8640 +8886,8887,8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901, # 8656 +8902,8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917, # 8672 +8918,8919,8920,8921,8922,8923,8924,4465,8925,8926,8927,8928,8929,8930,8931,8932, # 8688 +4883,8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,2214,8944,8945,8946, # 8704 +8947,8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962, # 8720 +8963,8964,8965,4884,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977, # 8736 +8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,4885, # 8752 +8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008, # 8768 +9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,4182,9022,9023, # 8784 +9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039, # 8800 +9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055, # 8816 +9056,9057,9058,9059,9060,9061,9062,9063,4886,9064,9065,9066,9067,9068,9069,4887, # 8832 +9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085, # 8848 +9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101, # 8864 +9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117, # 8880 +9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,9133, # 8896 +9134,9135,9136,9137,9138,9139,9140,9141,3958,9142,9143,9144,9145,9146,9147,9148, # 8912 +9149,9150,9151,4888,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,9163, # 8928 +9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,4889,9176,9177,9178, # 8944 +9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,9193,9194, # 8960 +9195,9196,9197,9198,9199,9200,9201,9202,9203,4890,9204,9205,9206,9207,9208,9209, # 8976 +9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,4466,9223,9224, # 8992 +9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240, # 9008 +9241,9242,9243,9244,9245,4891,9246,9247,9248,9249,9250,9251,9252,9253,9254,9255, # 9024 +9256,9257,4892,9258,9259,9260,9261,4893,4894,9262,9263,9264,9265,9266,9267,9268, # 9040 +9269,9270,9271,9272,9273,4467,9274,9275,9276,9277,9278,9279,9280,9281,9282,9283, # 9056 +9284,9285,3673,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,9298, # 9072 +9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314, # 9088 +9315,9316,9317,9318,9319,9320,9321,9322,4895,9323,9324,9325,9326,9327,9328,9329, # 9104 +9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345, # 9120 +9346,9347,4468,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,9358,9359,9360, # 9136 +9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,9373,4896,9374,4469, # 9152 +9375,9376,9377,9378,9379,4897,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389, # 9168 +9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,9403,9404,9405, # 9184 +9406,4470,9407,2751,9408,9409,3674,3552,9410,9411,9412,9413,9414,9415,9416,9417, # 9200 +9418,9419,9420,9421,4898,9422,9423,9424,9425,9426,9427,9428,9429,3959,9430,9431, # 9216 +9432,9433,9434,9435,9436,4471,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446, # 9232 +9447,9448,9449,9450,3348,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461, # 9248 +9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,4899,9473,9474,9475,9476, # 9264 +9477,4900,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,3349,9489,9490, # 9280 +9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506, # 9296 +9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,4901,9521, # 9312 +9522,9523,9524,9525,9526,4902,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536, # 9328 +9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552, # 9344 +9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568, # 9360 +9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584, # 9376 +3805,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,9598,9599, # 9392 +9600,9601,9602,4903,9603,9604,9605,9606,9607,4904,9608,9609,9610,9611,9612,9613, # 9408 +9614,4905,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,9628, # 9424 +9629,9630,9631,9632,4906,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,9643, # 9440 +4907,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,9658, # 9456 +9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,4183,9673, # 9472 +9674,9675,9676,9677,4908,9678,9679,9680,9681,4909,9682,9683,9684,9685,9686,9687, # 9488 +9688,9689,9690,4910,9691,9692,9693,3675,9694,9695,9696,2945,9697,9698,9699,9700, # 9504 +9701,9702,9703,9704,9705,4911,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715, # 9520 +9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731, # 9536 +9732,9733,9734,9735,4912,9736,9737,9738,9739,9740,4913,9741,9742,9743,9744,9745, # 9552 +9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,4914,9759,9760, # 9568 +9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776, # 9584 +9777,9778,9779,9780,9781,9782,4915,9783,9784,9785,9786,9787,9788,9789,9790,9791, # 9600 +9792,9793,4916,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806, # 9616 +9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822, # 9632 +9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,9838, # 9648 +9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,9853,9854, # 9664 +9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,9868,4917,9869, # 9680 +9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,9883,9884,9885, # 9696 +9886,9887,9888,9889,9890,9891,9892,4472,9893,9894,9895,9896,9897,3806,9898,9899, # 9712 +9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,9913,9914,4918, # 9728 +9915,9916,9917,4919,9918,9919,9920,9921,4184,9922,9923,9924,9925,9926,9927,9928, # 9744 +9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,9943,9944, # 9760 +9945,9946,4920,9947,9948,9949,9950,9951,9952,9953,9954,9955,4185,9956,9957,9958, # 9776 +9959,9960,9961,9962,9963,9964,9965,4921,9966,9967,9968,4473,9969,9970,9971,9972, # 9792 +9973,9974,9975,9976,9977,4474,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987, # 9808 +9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,10002,10003, # 9824 +10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019, # 9840 +10020,10021,4922,10022,4923,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033, # 9856 +10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,4924, # 9872 +10049,10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,10062,10063,10064, # 9888 +10065,10066,10067,10068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080, # 9904 +10081,10082,10083,10084,10085,10086,10087,4475,10088,10089,10090,10091,10092,10093,10094,10095, # 9920 +10096,10097,4476,10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,10110, # 9936 +10111,2174,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,10122,10123,10124,10125, # 9952 +10126,10127,10128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,3807, # 9968 +4186,4925,10141,10142,10143,10144,10145,10146,10147,4477,4187,10148,10149,10150,10151,10152, # 9984 +10153,4188,10154,10155,10156,10157,10158,10159,10160,10161,4926,10162,10163,10164,10165,10166, #10000 +10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182, #10016 +10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,3203,10193,10194,10195,10196,10197, #10032 +10198,10199,10200,4478,10201,10202,10203,10204,4479,10205,10206,10207,10208,10209,10210,10211, #10048 +10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,10226,10227, #10064 +10228,10229,10230,10231,10232,10233,10234,4927,10235,10236,10237,10238,10239,10240,10241,10242, #10080 +10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,10254,10255,10256,10257,10258, #10096 +10259,10260,10261,10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,4480, #10112 +4928,4929,10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,10286,10287, #10128 +10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,10302,10303, #10144 +10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,10314,10315,10316,10317,10318,10319, #10160 +10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,10334,4930, #10176 +10335,10336,10337,10338,10339,10340,10341,10342,4931,10343,10344,10345,10346,10347,10348,10349, #10192 +10350,10351,10352,10353,10354,10355,3088,10356,2786,10357,10358,10359,10360,4189,10361,10362, #10208 +10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,10374,10375,4932,10376,10377, #10224 +10378,10379,10380,10381,10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,4933, #10240 +10393,10394,10395,4934,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,10406,10407, #10256 +10408,10409,10410,10411,10412,3446,10413,10414,10415,10416,10417,10418,10419,10420,10421,10422, #10272 +10423,4935,10424,10425,10426,10427,10428,10429,10430,4936,10431,10432,10433,10434,10435,10436, #10288 +10437,10438,10439,10440,10441,10442,10443,4937,10444,10445,10446,10447,4481,10448,10449,10450, #10304 +10451,10452,10453,10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,10466, #10320 +10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,10482, #10336 +10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,10498, #10352 +10499,10500,10501,10502,10503,10504,10505,4938,10506,10507,10508,10509,10510,2552,10511,10512, #10368 +10513,10514,10515,10516,3447,10517,10518,10519,10520,10521,10522,10523,10524,10525,10526,10527, #10384 +10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543, #10400 +4482,10544,4939,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557, #10416 +10558,10559,10560,10561,10562,10563,10564,10565,10566,10567,3676,4483,10568,10569,10570,10571, #10432 +10572,3448,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,10586, #10448 +10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,10602, #10464 +10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618, #10480 +10619,10620,10621,10622,10623,10624,10625,10626,10627,4484,10628,10629,10630,10631,10632,4940, #10496 +10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648, #10512 +10649,10650,10651,10652,10653,10654,10655,10656,4941,10657,10658,10659,2599,10660,10661,10662, #10528 +10663,10664,10665,10666,3089,10667,10668,10669,10670,10671,10672,10673,10674,10675,10676,10677, #10544 +10678,10679,10680,4942,10681,10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692, #10560 +10693,10694,10695,10696,10697,4485,10698,10699,10700,10701,10702,10703,10704,4943,10705,3677, #10576 +10706,10707,10708,10709,10710,10711,10712,4944,10713,10714,10715,10716,10717,10718,10719,10720, #10592 +10721,10722,10723,10724,10725,10726,10727,10728,4945,10729,10730,10731,10732,10733,10734,10735, #10608 +10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,10746,10747,10748,10749,10750,10751, #10624 +10752,10753,10754,10755,10756,10757,10758,10759,10760,10761,4946,10762,10763,10764,10765,10766, #10640 +10767,4947,4948,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780, #10656 +10781,10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796, #10672 +10797,10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812, #10688 +10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828, #10704 +10829,10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,10842,10843,10844, #10720 +10845,10846,10847,10848,10849,10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860, #10736 +10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876, #10752 +10877,10878,4486,10879,10880,10881,10882,10883,10884,10885,4949,10886,10887,10888,10889,10890, #10768 +10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,10906, #10784 +10907,10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,4487,10920,10921, #10800 +10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,4950,10933,10934,10935,10936, #10816 +10937,10938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,4488,10950,10951, #10832 +10952,10953,10954,10955,10956,10957,10958,10959,4190,10960,10961,10962,10963,10964,10965,10966, #10848 +10967,10968,10969,10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,10982, #10864 +10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,10998, #10880 +10999,11000,11001,11002,11003,11004,11005,11006,3960,11007,11008,11009,11010,11011,11012,11013, #10896 +11014,11015,11016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029, #10912 +11030,11031,11032,4951,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044, #10928 +11045,11046,11047,4489,11048,11049,11050,11051,4952,11052,11053,11054,11055,11056,11057,11058, #10944 +4953,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,4954,11072, #10960 +11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088, #10976 +11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104, #10992 +11105,11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,3808,11116,11117,11118,11119, #11008 +11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,4955, #11024 +11135,11136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150, #11040 +11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,4956,11162,11163,11164,11165, #11056 +11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,11178,11179,11180,4957, #11072 +11181,11182,11183,11184,11185,11186,4958,11187,11188,11189,11190,11191,11192,11193,11194,11195, #11088 +11196,11197,11198,11199,11200,3678,11201,11202,11203,11204,11205,11206,4191,11207,11208,11209, #11104 +11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225, #11120 +11226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,11238,11239,11240,11241, #11136 +11242,11243,11244,11245,11246,11247,11248,11249,11250,11251,4959,11252,11253,11254,11255,11256, #11152 +11257,11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272, #11168 +11273,11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,11288, #11184 +11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304, #11200 +11305,11306,11307,11308,11309,11310,11311,11312,11313,11314,3679,11315,11316,11317,11318,4490, #11216 +11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334, #11232 +11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,4960,11348,11349, #11248 +11350,11351,11352,11353,11354,11355,11356,11357,11358,11359,11360,11361,11362,11363,11364,11365, #11264 +11366,11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,3961,4961,11378,11379, #11280 +11380,11381,11382,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395, #11296 +11396,11397,4192,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410, #11312 +11411,4962,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425, #11328 +11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,11436,11437,11438,11439,11440,11441, #11344 +11442,11443,11444,11445,11446,11447,11448,11449,11450,11451,11452,11453,11454,11455,11456,11457, #11360 +11458,11459,11460,11461,11462,11463,11464,11465,11466,11467,11468,11469,4963,11470,11471,4491, #11376 +11472,11473,11474,11475,4964,11476,11477,11478,11479,11480,11481,11482,11483,11484,11485,11486, #11392 +11487,11488,11489,11490,11491,11492,4965,11493,11494,11495,11496,11497,11498,11499,11500,11501, #11408 +11502,11503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,11515,11516,11517, #11424 +11518,11519,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,3962,11530,11531,11532, #11440 +11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548, #11456 +11549,11550,11551,11552,11553,11554,11555,11556,11557,11558,11559,11560,11561,11562,11563,11564, #11472 +4193,4194,11565,11566,11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578, #11488 +11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,4966,4195,11592, #11504 +11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,3090,11605,11606,11607, #11520 +11608,11609,11610,4967,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622, #11536 +11623,11624,11625,11626,11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638, #11552 +11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,11654, #11568 +11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670, #11584 +11671,11672,11673,11674,4968,11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685, #11600 +11686,11687,11688,11689,11690,11691,11692,11693,3809,11694,11695,11696,11697,11698,11699,11700, #11616 +11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,11714,11715,11716, #11632 +11717,11718,3553,11719,11720,11721,11722,11723,11724,11725,11726,11727,11728,11729,11730,4969, #11648 +11731,11732,11733,11734,11735,11736,11737,11738,11739,11740,4492,11741,11742,11743,11744,11745, #11664 +11746,11747,11748,11749,11750,11751,11752,4970,11753,11754,11755,11756,11757,11758,11759,11760, #11680 +11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,11776, #11696 +11777,11778,11779,11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,4971,11791, #11712 +11792,11793,11794,11795,11796,11797,4972,11798,11799,11800,11801,11802,11803,11804,11805,11806, #11728 +11807,11808,11809,11810,4973,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821, #11744 +11822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,11834,3680,3810,11835, #11760 +11836,4974,11837,11838,11839,11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850, #11776 +11851,11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866, #11792 +11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,11882, #11808 +11883,11884,4493,11885,11886,11887,11888,11889,11890,11891,11892,11893,11894,11895,11896,11897, #11824 +11898,11899,11900,11901,11902,11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913, #11840 +11914,11915,4975,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928, #11856 +11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,11942,11943,11944, #11872 +11945,11946,11947,11948,11949,4976,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959, #11888 +11960,11961,11962,11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,11975, #11904 +11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,11987,4196,11988,11989,11990, #11920 +11991,11992,4977,11993,11994,11995,11996,11997,11998,11999,12000,12001,12002,12003,12004,12005, #11936 +12006,12007,12008,12009,12010,12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021, #11952 +12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037, #11968 +12038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,12050,12051,12052,12053, #11984 +12054,12055,12056,12057,12058,12059,12060,12061,4978,12062,12063,12064,12065,12066,12067,12068, #12000 +12069,12070,12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084, #12016 +12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,12098,12099,12100, #12032 +12101,12102,12103,12104,12105,12106,12107,12108,12109,12110,12111,12112,12113,12114,12115,12116, #12048 +12117,12118,12119,12120,12121,12122,12123,4979,12124,12125,12126,12127,12128,4197,12129,12130, #12064 +12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,12146, #12080 +12147,12148,12149,12150,12151,12152,12153,12154,4980,12155,12156,12157,12158,12159,12160,4494, #12096 +12161,12162,12163,12164,3811,12165,12166,12167,12168,12169,4495,12170,12171,4496,12172,12173, #12112 +12174,12175,12176,3812,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187,12188, #12128 +12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204, #12144 +12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,12218,12219,12220, #12160 +12221,4981,12222,12223,12224,12225,12226,12227,12228,12229,12230,12231,12232,12233,12234,12235, #12176 +4982,12236,12237,12238,12239,12240,12241,12242,12243,12244,12245,4983,12246,12247,12248,12249, #12192 +4984,12250,12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264, #12208 +4985,12265,4497,12266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,12278, #12224 +12279,12280,12281,12282,12283,12284,12285,12286,12287,4986,12288,12289,12290,12291,12292,12293, #12240 +12294,12295,12296,2473,12297,12298,12299,12300,12301,12302,12303,12304,12305,12306,12307,12308, #12256 +12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,3963,12320,12321,12322,12323, #12272 +12324,12325,12326,12327,12328,12329,12330,12331,12332,4987,12333,12334,12335,12336,12337,12338, #12288 +12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,12350,12351,12352,12353,12354, #12304 +12355,12356,12357,12358,12359,3964,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369, #12320 +12370,3965,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384, #12336 +12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400, #12352 +12401,12402,12403,12404,12405,12406,12407,12408,4988,12409,12410,12411,12412,12413,12414,12415, #12368 +12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431, #12384 +12432,12433,12434,12435,12436,12437,12438,3554,12439,12440,12441,12442,12443,12444,12445,12446, #12400 +12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462, #12416 +12463,12464,4989,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477, #12432 +12478,12479,12480,4990,12481,12482,12483,12484,12485,12486,12487,12488,12489,4498,12490,12491, #12448 +12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, #12464 +12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523, #12480 +12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,12539, #12496 +12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,12551,4991,12552,12553,12554, #12512 +12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570, #12528 +12571,12572,12573,12574,12575,12576,12577,12578,3036,12579,12580,12581,12582,12583,3966,12584, #12544 +12585,12586,12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600, #12560 +12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616, #12576 +12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632, #12592 +12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,4499,12647, #12608 +12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663, #12624 +12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679, #12640 +12680,12681,12682,12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,12695, #12656 +12696,12697,12698,4992,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,12710, #12672 +12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726, #12688 +12727,12728,12729,12730,12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742, #12704 +12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,12758, #12720 +12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,12770,12771,12772,12773,12774, #12736 +12775,12776,12777,12778,4993,2175,12779,12780,12781,12782,12783,12784,12785,12786,4500,12787, #12752 +12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,12803, #12768 +12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819, #12784 +12820,12821,12822,12823,12824,12825,12826,4198,3967,12827,12828,12829,12830,12831,12832,12833, #12800 +12834,12835,12836,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849, #12816 +12850,12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,4199,12862,12863,12864, #12832 +12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,12878,12879,12880, #12848 +12881,12882,12883,12884,12885,12886,12887,4501,12888,12889,12890,12891,12892,12893,12894,12895, #12864 +12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911, #12880 +12912,4994,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,12926, #12896 +12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,12938,12939,12940,12941,12942, #12912 +12943,12944,12945,12946,12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,1772,12957, #12928 +12958,12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973, #12944 +12974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988,12989, #12960 +12990,12991,12992,12993,12994,12995,12996,12997,4502,12998,4503,12999,13000,13001,13002,13003, #12976 +4504,13004,13005,13006,13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018, #12992 +13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,3449,13030,13031,13032,13033, #13008 +13034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,13046,13047,13048,13049, #13024 +13050,13051,13052,13053,13054,13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065, #13040 +13066,13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081, #13056 +13082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,13094,13095,13096,13097, #13072 +13098,13099,13100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113, #13088 +13114,13115,13116,13117,13118,3968,13119,4995,13120,13121,13122,13123,13124,13125,13126,13127, #13104 +4505,13128,13129,13130,13131,13132,13133,13134,4996,4506,13135,13136,13137,13138,13139,4997, #13120 +13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,13154,13155, #13136 +13156,13157,13158,13159,4998,13160,13161,13162,13163,13164,13165,13166,13167,13168,13169,13170, #13152 +13171,13172,13173,13174,13175,13176,4999,13177,13178,13179,13180,13181,13182,13183,13184,13185, #13168 +13186,13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201, #13184 +13202,13203,13204,13205,13206,5000,13207,13208,13209,13210,13211,13212,13213,13214,13215,13216, #13200 +13217,13218,13219,13220,13221,13222,13223,13224,13225,13226,13227,4200,5001,13228,13229,13230, #13216 +13231,13232,13233,13234,13235,13236,13237,13238,13239,13240,3969,13241,13242,13243,13244,3970, #13232 +13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260, #13248 +13261,13262,13263,13264,13265,13266,13267,13268,3450,13269,13270,13271,13272,13273,13274,13275, #13264 +13276,5002,13277,13278,13279,13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,13290, #13280 +13291,13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,3813,13303,13304,13305, #13296 +13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321, #13312 +13322,13323,13324,13325,13326,13327,13328,4507,13329,13330,13331,13332,13333,13334,13335,13336, #13328 +13337,13338,13339,13340,13341,5003,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351, #13344 +13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367, #13360 +5004,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382, #13376 +13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398, #13392 +13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414, #13408 +13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430, #13424 +13431,13432,4508,13433,13434,13435,4201,13436,13437,13438,13439,13440,13441,13442,13443,13444, #13440 +13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,5005,13458,13459, #13456 +13460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,4509,13471,13472,13473,13474, #13472 +13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490, #13488 +13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506, #13504 +13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522, #13520 +13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538, #13536 +13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554, #13552 +13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570, #13568 +13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,13586, #13584 +13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602, #13600 +13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618, #13616 +13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13634, #13632 +13635,13636,13637,13638,13639,13640,13641,13642,5006,13643,13644,13645,13646,13647,13648,13649, #13648 +13650,13651,5007,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13664, #13664 +13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680, #13680 +13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696, #13696 +13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712, #13712 +13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728, #13728 +13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744, #13744 +13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760, #13760 +13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,3273,13775, #13776 +13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791, #13792 +13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807, #13808 +13808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,13823, #13824 +13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839, #13840 +13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855, #13856 +13856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,13871, #13872 +13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,13886,13887, #13888 +13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903, #13904 +13904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,13919, #13920 +13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935, #13936 +13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951, #13952 +13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967, #13968 +13968,13969,13970,13971,13972) #13973 + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/big5prober.py b/pipenv/vendor/requests/packages/chardet/big5prober.py new file mode 100644 index 00000000..becce81e --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/big5prober.py @@ -0,0 +1,42 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import Big5DistributionAnalysis +from .mbcssm import Big5SMModel + + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(Big5SMModel) + self._mDistributionAnalyzer = Big5DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "Big5" diff --git a/pipenv/vendor/requests/packages/chardet/chardetect.py b/pipenv/vendor/requests/packages/chardet/chardetect.py new file mode 100755 index 00000000..ffe892f2 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/chardetect.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +""" +Script which takes one or more file paths and reports on their detected +encodings + +Example:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +If no paths are provided, it takes its input from stdin. + +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import argparse +import sys +from io import open + +from chardet import __version__ +from chardet.universaldetector import UniversalDetector + + +def description_of(lines, name='stdin'): + """ + Return a string describing the probable encoding of a file or + list of strings. + + :param lines: The lines to get the encoding of. + :type lines: Iterable of bytes + :param name: Name of file or collection of lines + :type name: str + """ + u = UniversalDetector() + for line in lines: + u.feed(line) + u.close() + result = u.result + if result['encoding']: + return '{0}: {1} with confidence {2}'.format(name, result['encoding'], + result['confidence']) + else: + return '{0}: no result'.format(name) + + +def main(argv=None): + ''' + Handles command line arguments and gets things started. + + :param argv: List of arguments, as if specified on the command-line. + If None, ``sys.argv[1:]`` is used instead. + :type argv: list of str + ''' + # Get command line arguments + parser = argparse.ArgumentParser( + description="Takes one or more file paths and reports their detected \ + encodings", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + conflict_handler='resolve') + parser.add_argument('input', + help='File whose encoding we would like to determine.', + type=argparse.FileType('rb'), nargs='*', + default=[sys.stdin]) + parser.add_argument('--version', action='version', + version='%(prog)s {0}'.format(__version__)) + args = parser.parse_args(argv) + + for f in args.input: + if f.isatty(): + print("You are running chardetect interactively. Press " + + "CTRL-D twice at the start of a blank line to signal the " + + "end of your input. If you want help, run chardetect " + + "--help\n", file=sys.stderr) + print(description_of(f, f.name)) + + +if __name__ == '__main__': + main() diff --git a/pipenv/vendor/requests/packages/chardet/chardistribution.py b/pipenv/vendor/requests/packages/chardet/chardistribution.py new file mode 100644 index 00000000..4e64a00b --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/chardistribution.py @@ -0,0 +1,231 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .euctwfreq import (EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO) +from .euckrfreq import (EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO) +from .gb2312freq import (GB2312CharToFreqOrder, GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO) +from .big5freq import (Big5CharToFreqOrder, BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO) +from .jisfreq import (JISCharToFreqOrder, JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO) +from .compat import wrap_ord + +ENOUGH_DATA_THRESHOLD = 1024 +SURE_YES = 0.99 +SURE_NO = 0.01 +MINIMUM_DATA_THRESHOLD = 3 + + +class CharDistributionAnalysis: + def __init__(self): + # Mapping table to get frequency order from char order (get from + # GetOrder()) + self._mCharToFreqOrder = None + self._mTableSize = None # Size of above table + # This is a constant value which varies from language to language, + # used in calculating confidence. See + # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html + # for further detail. + self._mTypicalDistributionRatio = None + self.reset() + + def reset(self): + """reset analyser, clear any state""" + # If this flag is set to True, detection is done and conclusion has + # been made + self._mDone = False + self._mTotalChars = 0 # Total characters encountered + # The number of characters whose frequency order is less than 512 + self._mFreqChars = 0 + + def feed(self, aBuf, aCharLen): + """feed a character with known length""" + if aCharLen == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(aBuf) + else: + order = -1 + if order >= 0: + self._mTotalChars += 1 + # order is valid + if order < self._mTableSize: + if 512 > self._mCharToFreqOrder[order]: + self._mFreqChars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, + # return negative answer + if self._mTotalChars <= 0 or self._mFreqChars <= MINIMUM_DATA_THRESHOLD: + return SURE_NO + + if self._mTotalChars != self._mFreqChars: + r = (self._mFreqChars / ((self._mTotalChars - self._mFreqChars) + * self._mTypicalDistributionRatio)) + if r < SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. + # For charset detection, certain amount of data is enough + return self._mTotalChars > ENOUGH_DATA_THRESHOLD + + def get_order(self, aBuf): + # We do not handle characters based on the original encoding string, + # but convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency + # table. + return -1 + + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCTWCharToFreqOrder + self._mTableSize = EUCTW_TABLE_SIZE + self._mTypicalDistributionRatio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = wrap_ord(aBuf[0]) + if first_char >= 0xC4: + return 94 * (first_char - 0xC4) + wrap_ord(aBuf[1]) - 0xA1 + else: + return -1 + + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCKRCharToFreqOrder + self._mTableSize = EUCKR_TABLE_SIZE + self._mTypicalDistributionRatio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = wrap_ord(aBuf[0]) + if first_char >= 0xB0: + return 94 * (first_char - 0xB0) + wrap_ord(aBuf[1]) - 0xA1 + else: + return -1 + + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = GB2312CharToFreqOrder + self._mTableSize = GB2312_TABLE_SIZE + self._mTypicalDistributionRatio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + if (first_char >= 0xB0) and (second_char >= 0xA1): + return 94 * (first_char - 0xB0) + second_char - 0xA1 + else: + return -1 + + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = Big5CharToFreqOrder + self._mTableSize = BIG5_TABLE_SIZE + self._mTypicalDistributionRatio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + if first_char >= 0xA4: + if second_char >= 0xA1: + return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 + else: + return 157 * (first_char - 0xA4) + second_char - 0x40 + else: + return -1 + + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + if (first_char >= 0x81) and (first_char <= 0x9F): + order = 188 * (first_char - 0x81) + elif (first_char >= 0xE0) and (first_char <= 0xEF): + order = 188 * (first_char - 0xE0 + 31) + else: + return -1 + order = order + second_char - 0x40 + if second_char > 0x7F: + order = -1 + return order + + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + char = wrap_ord(aBuf[0]) + if char >= 0xA0: + return 94 * (char - 0xA1) + wrap_ord(aBuf[1]) - 0xa1 + else: + return -1 diff --git a/pipenv/vendor/requests/packages/chardet/charsetgroupprober.py b/pipenv/vendor/requests/packages/chardet/charsetgroupprober.py new file mode 100644 index 00000000..85e7a1c6 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mActiveNum = 0 + self._mProbers = [] + self._mBestGuessProber = None + + def reset(self): + CharSetProber.reset(self) + self._mActiveNum = 0 + for prober in self._mProbers: + if prober: + prober.reset() + prober.active = True + self._mActiveNum += 1 + self._mBestGuessProber = None + + def get_charset_name(self): + if not self._mBestGuessProber: + self.get_confidence() + if not self._mBestGuessProber: + return None +# self._mBestGuessProber = self._mProbers[0] + return self._mBestGuessProber.get_charset_name() + + def feed(self, aBuf): + for prober in self._mProbers: + if not prober: + continue + if not prober.active: + continue + st = prober.feed(aBuf) + if not st: + continue + if st == constants.eFoundIt: + self._mBestGuessProber = prober + return self.get_state() + elif st == constants.eNotMe: + prober.active = False + self._mActiveNum -= 1 + if self._mActiveNum <= 0: + self._mState = constants.eNotMe + return self.get_state() + return self.get_state() + + def get_confidence(self): + st = self.get_state() + if st == constants.eFoundIt: + return 0.99 + elif st == constants.eNotMe: + return 0.01 + bestConf = 0.0 + self._mBestGuessProber = None + for prober in self._mProbers: + if not prober: + continue + if not prober.active: + if constants._debug: + sys.stderr.write(prober.get_charset_name() + + ' not active\n') + continue + cf = prober.get_confidence() + if constants._debug: + sys.stderr.write('%s confidence = %s\n' % + (prober.get_charset_name(), cf)) + if bestConf < cf: + bestConf = cf + self._mBestGuessProber = prober + if not self._mBestGuessProber: + return 0.0 + return bestConf +# else: +# self._mBestGuessProber = self._mProbers[0] +# return self._mBestGuessProber.get_confidence() diff --git a/pipenv/vendor/requests/packages/chardet/charsetprober.py b/pipenv/vendor/requests/packages/chardet/charsetprober.py new file mode 100644 index 00000000..97581712 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/charsetprober.py @@ -0,0 +1,62 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import re + + +class CharSetProber: + def __init__(self): + pass + + def reset(self): + self._mState = constants.eDetecting + + def get_charset_name(self): + return None + + def feed(self, aBuf): + pass + + def get_state(self): + return self._mState + + def get_confidence(self): + return 0.0 + + def filter_high_bit_only(self, aBuf): + aBuf = re.sub(b'([\x00-\x7F])+', b' ', aBuf) + return aBuf + + def filter_without_english_letters(self, aBuf): + aBuf = re.sub(b'([A-Za-z])+', b' ', aBuf) + return aBuf + + def filter_with_english_letters(self, aBuf): + # TODO + return aBuf diff --git a/pipenv/vendor/requests/packages/chardet/codingstatemachine.py b/pipenv/vendor/requests/packages/chardet/codingstatemachine.py new file mode 100644 index 00000000..8dd8c917 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/codingstatemachine.py @@ -0,0 +1,61 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart +from .compat import wrap_ord + + +class CodingStateMachine: + def __init__(self, sm): + self._mModel = sm + self._mCurrentBytePos = 0 + self._mCurrentCharLen = 0 + self.reset() + + def reset(self): + self._mCurrentState = eStart + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + # PY3K: aBuf is a byte stream, so c is an int, not a byte + byteCls = self._mModel['classTable'][wrap_ord(c)] + if self._mCurrentState == eStart: + self._mCurrentBytePos = 0 + self._mCurrentCharLen = self._mModel['charLenTable'][byteCls] + # from byte's class and stateTable, we get its next state + curr_state = (self._mCurrentState * self._mModel['classFactor'] + + byteCls) + self._mCurrentState = self._mModel['stateTable'][curr_state] + self._mCurrentBytePos += 1 + return self._mCurrentState + + def get_current_charlen(self): + return self._mCurrentCharLen + + def get_coding_state_machine(self): + return self._mModel['name'] diff --git a/pipenv/vendor/requests/packages/chardet/compat.py b/pipenv/vendor/requests/packages/chardet/compat.py new file mode 100644 index 00000000..d9e30add --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/compat.py @@ -0,0 +1,34 @@ +######################## BEGIN LICENSE BLOCK ######################## +# Contributor(s): +# Ian Cordasco - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys + + +if sys.version_info < (3, 0): + base_str = (str, unicode) +else: + base_str = (bytes, str) + + +def wrap_ord(a): + if sys.version_info < (3, 0) and isinstance(a, base_str): + return ord(a) + else: + return a diff --git a/pipenv/vendor/requests/packages/chardet/constants.py b/pipenv/vendor/requests/packages/chardet/constants.py new file mode 100644 index 00000000..e4d148b3 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/constants.py @@ -0,0 +1,39 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +_debug = 0 + +eDetecting = 0 +eFoundIt = 1 +eNotMe = 2 + +eStart = 0 +eError = 1 +eItsMe = 2 + +SHORTCUT_THRESHOLD = 0.95 diff --git a/pipenv/vendor/requests/packages/chardet/cp949prober.py b/pipenv/vendor/requests/packages/chardet/cp949prober.py new file mode 100644 index 00000000..ff4272f8 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/cp949prober.py @@ -0,0 +1,44 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import CP949SMModel + + +class CP949Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(CP949SMModel) + # NOTE: CP949 is a superset of EUC-KR, so the distribution should be + # not different. + self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "CP949" diff --git a/pipenv/vendor/requests/packages/chardet/escprober.py b/pipenv/vendor/requests/packages/chardet/escprober.py new file mode 100644 index 00000000..80a844ff --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/escprober.py @@ -0,0 +1,86 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +from .escsm import (HZSMModel, ISO2022CNSMModel, ISO2022JPSMModel, + ISO2022KRSMModel) +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .compat import wrap_ord + + +class EscCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = [ + CodingStateMachine(HZSMModel), + CodingStateMachine(ISO2022CNSMModel), + CodingStateMachine(ISO2022JPSMModel), + CodingStateMachine(ISO2022KRSMModel) + ] + self.reset() + + def reset(self): + CharSetProber.reset(self) + for codingSM in self._mCodingSM: + if not codingSM: + continue + codingSM.active = True + codingSM.reset() + self._mActiveSM = len(self._mCodingSM) + self._mDetectedCharset = None + + def get_charset_name(self): + return self._mDetectedCharset + + def get_confidence(self): + if self._mDetectedCharset: + return 0.99 + else: + return 0.00 + + def feed(self, aBuf): + for c in aBuf: + # PY3K: aBuf is a byte array, so c is an int, not a byte + for codingSM in self._mCodingSM: + if not codingSM: + continue + if not codingSM.active: + continue + codingState = codingSM.next_state(wrap_ord(c)) + if codingState == constants.eError: + codingSM.active = False + self._mActiveSM -= 1 + if self._mActiveSM <= 0: + self._mState = constants.eNotMe + return self.get_state() + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + self._mDetectedCharset = codingSM.get_coding_state_machine() # nopep8 + return self.get_state() + + return self.get_state() diff --git a/pipenv/vendor/requests/packages/chardet/escsm.py b/pipenv/vendor/requests/packages/chardet/escsm.py new file mode 100644 index 00000000..bd302b4c --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/escsm.py @@ -0,0 +1,242 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart, eError, eItsMe + +HZ_cls = ( +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_st = ( +eStart,eError, 3,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eStart,eStart, 4,eError,# 10-17 + 5,eError, 6,eError, 5, 5, 4,eError,# 18-1f + 4,eError, 4, 4, 4,eError, 4,eError,# 20-27 + 4,eItsMe,eStart,eStart,eStart,eStart,eStart,eStart,# 28-2f +) + +HZCharLenTable = (0, 0, 0, 0, 0, 0) + +HZSMModel = {'classTable': HZ_cls, + 'classFactor': 6, + 'stateTable': HZ_st, + 'charLenTable': HZCharLenTable, + 'name': "HZ-GB-2312"} + +ISO2022CN_cls = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_st = ( +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eError,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eError,eError,eError, 4,eError,# 18-1f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 20-27 + 5, 6,eError,eError,eError,eError,eError,eError,# 28-2f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 30-37 +eError,eError,eError,eError,eError,eItsMe,eError,eStart,# 38-3f +) + +ISO2022CNCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CNSMModel = {'classTable': ISO2022CN_cls, + 'classFactor': 9, + 'stateTable': ISO2022CN_st, + 'charLenTable': ISO2022CNCharLenTable, + 'name': "ISO-2022-CN"} + +ISO2022JP_cls = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_st = ( +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eStart,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,# 18-1f +eError, 5,eError,eError,eError, 4,eError,eError,# 20-27 +eError,eError,eError, 6,eItsMe,eError,eItsMe,eError,# 28-2f +eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,# 30-37 +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 38-3f +eError,eError,eError,eError,eItsMe,eError,eStart,eStart,# 40-47 +) + +ISO2022JPCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JPSMModel = {'classTable': ISO2022JP_cls, + 'classFactor': 10, + 'stateTable': ISO2022JP_st, + 'charLenTable': ISO2022JPCharLenTable, + 'name': "ISO-2022-JP"} + +ISO2022KR_cls = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_st = ( +eStart, 3,eError,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eError, 4,eError,eError,# 10-17 +eError,eError,eError,eError, 5,eError,eError,eError,# 18-1f +eError,eError,eError,eItsMe,eStart,eStart,eStart,eStart,# 20-27 +) + +ISO2022KRCharLenTable = (0, 0, 0, 0, 0, 0) + +ISO2022KRSMModel = {'classTable': ISO2022KR_cls, + 'classFactor': 6, + 'stateTable': ISO2022KR_st, + 'charLenTable': ISO2022KRCharLenTable, + 'name': "ISO-2022-KR"} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/eucjpprober.py b/pipenv/vendor/requests/packages/chardet/eucjpprober.py new file mode 100644 index 00000000..8e64fdcc --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/eucjpprober.py @@ -0,0 +1,90 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys +from . import constants +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJPSMModel + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCJPSMModel) + self._mDistributionAnalyzer = EUCJPDistributionAnalysis() + self._mContextAnalyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return "EUC-JP" + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + # PY3K: aBuf is a byte array, so aBuf[i] is an int, not a byte + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == constants.eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + + ' prober hit error at byte ' + str(i) + + '\n') + self._mState = constants.eNotMe + break + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == constants.eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar, charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i - 1:i + 1], charLen) + self._mDistributionAnalyzer.feed(aBuf[i - 1:i + 1], + charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if (self._mContextAnalyzer.got_enough_data() and + (self.get_confidence() > constants.SHORTCUT_THRESHOLD)): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/pipenv/vendor/requests/packages/chardet/euckrfreq.py b/pipenv/vendor/requests/packages/chardet/euckrfreq.py new file mode 100644 index 00000000..a179e4c2 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/euckrfreq.py @@ -0,0 +1,596 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKRCharToFreqOrder = ( \ + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +#Everything below is of no interest for detection purpose +2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658, +2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674, +2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690, +2691,2692,2693,2694,2695,2696,2697,2698,2699,1542, 880,2700,2701,2702,2703,2704, +2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720, +2721,2722,2723,2724,2725,1543,2726,2727,2728,2729,2730,2731,2732,1544,2733,2734, +2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750, +2751,2752,2753,2754,1545,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765, +2766,1546,2767,1547,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779, +2780,2781,2782,2783,2784,2785,2786,1548,2787,2788,2789,1109,2790,2791,2792,2793, +2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809, +2810,2811,2812,1329,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824, +2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840, +2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856, +1549,2857,2858,2859,2860,1550,2861,2862,1551,2863,2864,2865,2866,2867,2868,2869, +2870,2871,2872,2873,2874,1110,1330,2875,2876,2877,2878,2879,2880,2881,2882,2883, +2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899, +2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915, +2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,1331, +2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,1552,2944,2945, +2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961, +2962,2963,2964,1252,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976, +2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992, +2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008, +3009,3010,3011,3012,1553,3013,3014,3015,3016,3017,1554,3018,1332,3019,3020,3021, +3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037, +3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,1555,3051,3052, +3053,1556,1557,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066, +3067,1558,3068,3069,3070,3071,3072,3073,3074,3075,3076,1559,3077,3078,3079,3080, +3081,3082,3083,1253,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095, +3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,1152,3109,3110, +3111,3112,3113,1560,3114,3115,3116,3117,1111,3118,3119,3120,3121,3122,3123,3124, +3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140, +3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156, +3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172, +3173,3174,3175,3176,1333,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187, +3188,3189,1561,3190,3191,1334,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201, +3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217, +3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233, +3234,1562,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248, +3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264, +3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,1563,3278,3279, +3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295, +3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311, +3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327, +3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343, +3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359, +3360,3361,3362,3363,3364,1335,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374, +3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,1336,3388,3389, +3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405, +3406,3407,3408,3409,3410,3411,3412,3413,3414,1337,3415,3416,3417,3418,3419,1338, +3420,3421,3422,1564,1565,3423,3424,3425,3426,3427,3428,3429,3430,3431,1254,3432, +3433,3434,1339,3435,3436,3437,3438,3439,1566,3440,3441,3442,3443,3444,3445,3446, +3447,3448,3449,3450,3451,3452,3453,3454,1255,3455,3456,3457,3458,3459,1567,1191, +3460,1568,1569,3461,3462,3463,1570,3464,3465,3466,3467,3468,1571,3469,3470,3471, +3472,3473,1572,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486, +1340,3487,3488,3489,3490,3491,3492,1021,3493,3494,3495,3496,3497,3498,1573,3499, +1341,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,1342,3512,3513, +3514,3515,3516,1574,1343,3517,3518,3519,1575,3520,1576,3521,3522,3523,3524,3525, +3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541, +3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557, +3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573, +3574,3575,3576,3577,3578,3579,3580,1577,3581,3582,1578,3583,3584,3585,3586,3587, +3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603, +3604,1579,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618, +3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,1580,3630,3631,1581,3632, +3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648, +3649,3650,3651,3652,3653,3654,3655,3656,1582,3657,3658,3659,3660,3661,3662,3663, +3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679, +3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695, +3696,3697,3698,3699,3700,1192,3701,3702,3703,3704,1256,3705,3706,3707,3708,1583, +1257,3709,3710,3711,3712,3713,3714,3715,3716,1584,3717,3718,3719,3720,3721,3722, +3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738, +3739,3740,3741,3742,3743,3744,3745,1344,3746,3747,3748,3749,3750,3751,3752,3753, +3754,3755,3756,1585,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,1586,3767, +3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,1345,3779,3780,3781,3782, +3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,1346,1587,3796, +3797,1588,3798,3799,3800,3801,3802,3803,3804,3805,3806,1347,3807,3808,3809,3810, +3811,1589,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,1590,3822,3823,1591, +1348,3824,3825,3826,3827,3828,3829,3830,1592,3831,3832,1593,3833,3834,3835,3836, +3837,3838,3839,3840,3841,3842,3843,3844,1349,3845,3846,3847,3848,3849,3850,3851, +3852,3853,3854,3855,3856,3857,3858,1594,3859,3860,3861,3862,3863,3864,3865,3866, +3867,3868,3869,1595,3870,3871,3872,3873,1596,3874,3875,3876,3877,3878,3879,3880, +3881,3882,3883,3884,3885,3886,1597,3887,3888,3889,3890,3891,3892,3893,3894,3895, +1598,3896,3897,3898,1599,1600,3899,1350,3900,1351,3901,3902,1352,3903,3904,3905, +3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921, +3922,3923,3924,1258,3925,3926,3927,3928,3929,3930,3931,1193,3932,1601,3933,3934, +3935,3936,3937,3938,3939,3940,3941,3942,3943,1602,3944,3945,3946,3947,3948,1603, +3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964, +3965,1604,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,1353,3978, +3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,1354,3992,3993, +3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009, +4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,1355,4024, +4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040, +1605,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055, +4056,4057,4058,4059,4060,1606,4061,4062,4063,4064,1607,4065,4066,4067,4068,4069, +4070,4071,4072,4073,4074,4075,4076,1194,4077,4078,1608,4079,4080,4081,4082,4083, +4084,4085,4086,4087,1609,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098, +4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,1259,4109,4110,4111,4112,4113, +4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,1195,4125,4126,4127,1610, +4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,1356,4138,4139,4140,4141,4142, +4143,4144,1611,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157, +4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173, +4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189, +4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205, +4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,1612,4220, +4221,4222,4223,4224,4225,4226,4227,1357,4228,1613,4229,4230,4231,4232,4233,4234, +4235,4236,4237,4238,4239,4240,4241,4242,4243,1614,4244,4245,4246,4247,4248,4249, +4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265, +4266,4267,4268,4269,4270,1196,1358,4271,4272,4273,4274,4275,4276,4277,4278,4279, +4280,4281,4282,4283,4284,4285,4286,4287,1615,4288,4289,4290,4291,4292,4293,4294, +4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310, +4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326, +4327,4328,4329,4330,4331,4332,4333,4334,1616,4335,4336,4337,4338,4339,4340,4341, +4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357, +4358,4359,4360,1617,4361,4362,4363,4364,4365,1618,4366,4367,4368,4369,4370,4371, +4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387, +4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403, +4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,1619,4417,4418, +4419,4420,4421,4422,4423,4424,4425,1112,4426,4427,4428,4429,4430,1620,4431,4432, +4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,1260,1261,4443,4444,4445,4446, +4447,4448,4449,4450,4451,4452,4453,4454,4455,1359,4456,4457,4458,4459,4460,4461, +4462,4463,4464,4465,1621,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476, +4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,1055,4490,4491, +4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507, +4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,1622,4519,4520,4521,1623, +4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,1360,4536, +4537,4538,4539,4540,4541,4542,4543, 975,4544,4545,4546,4547,4548,4549,4550,4551, +4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567, +4568,4569,4570,4571,1624,4572,4573,4574,4575,4576,1625,4577,4578,4579,4580,4581, +4582,4583,4584,1626,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,1627, +4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611, +4612,4613,4614,4615,1628,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626, +4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642, +4643,4644,4645,4646,4647,4648,4649,1361,4650,4651,4652,4653,4654,4655,4656,4657, +4658,4659,4660,4661,1362,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672, +4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,1629,4683,4684,4685,4686,4687, +1630,4688,4689,4690,4691,1153,4692,4693,4694,1113,4695,4696,4697,4698,4699,4700, +4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,1197,4712,4713,4714,4715, +4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731, +4732,4733,4734,4735,1631,4736,1632,4737,4738,4739,4740,4741,4742,4743,4744,1633, +4745,4746,4747,4748,4749,1262,4750,4751,4752,4753,4754,1363,4755,4756,4757,4758, +4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,1634,4769,4770,4771,4772,4773, +4774,4775,4776,4777,4778,1635,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788, +4789,1636,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803, +4804,4805,4806,1637,4807,4808,4809,1638,4810,4811,4812,4813,4814,4815,4816,4817, +4818,1639,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832, +4833,1077,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847, +4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863, +4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879, +4880,4881,4882,4883,1640,4884,4885,1641,4886,4887,4888,4889,4890,4891,4892,4893, +4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909, +4910,4911,1642,4912,4913,4914,1364,4915,4916,4917,4918,4919,4920,4921,4922,4923, +4924,4925,4926,4927,4928,4929,4930,4931,1643,4932,4933,4934,4935,4936,4937,4938, +4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954, +4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970, +4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,1644,4981,4982,4983,4984,1645, +4985,4986,1646,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999, +5000,5001,5002,5003,5004,5005,1647,5006,1648,5007,5008,5009,5010,5011,5012,1078, +5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028, +1365,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,1649,5040,5041,5042, +5043,5044,5045,1366,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,1650,5056, +5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072, +5073,5074,5075,5076,5077,1651,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087, +5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103, +5104,5105,5106,5107,5108,5109,5110,1652,5111,5112,5113,5114,5115,5116,5117,5118, +1367,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,1653,5130,5131,5132, +5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148, +5149,1368,5150,1654,5151,1369,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161, +5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,5176,5177, +5178,1370,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,5189,5190,5191,5192, +5193,5194,5195,5196,5197,5198,1655,5199,5200,5201,5202,1656,5203,5204,5205,5206, +1371,5207,1372,5208,5209,5210,5211,1373,5212,5213,1374,5214,5215,5216,5217,5218, +5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234, +5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,1657,5248,5249, +5250,5251,1658,1263,5252,5253,5254,5255,5256,1375,5257,5258,5259,5260,5261,5262, +5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278, +5279,5280,5281,5282,5283,1659,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293, +5294,5295,5296,5297,5298,5299,5300,1660,5301,5302,5303,5304,5305,5306,5307,5308, +5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,1376,5322,5323, +5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,1198,5334,5335,5336,5337,5338, +5339,5340,5341,5342,5343,1661,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353, +5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369, +5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,5384,5385, +5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,1264,5399,5400, +5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,1662,5413,5414,5415, +5416,1663,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,5429,5430, +5431,5432,5433,5434,5435,5436,5437,5438,1664,5439,5440,5441,5442,5443,5444,5445, +5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,5459,5460,5461, +5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,5474,5475,5476,5477, +5478,1154,5479,5480,5481,5482,5483,5484,5485,1665,5486,5487,5488,5489,5490,5491, +5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504,5505,5506,5507, +5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520,5521,5522,5523, +5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539, +5540,5541,5542,5543,5544,5545,5546,5547,5548,1377,5549,5550,5551,5552,5553,5554, +5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570, +1114,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585, +5586,5587,5588,5589,5590,5591,5592,1378,5593,5594,5595,5596,5597,5598,5599,5600, +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,1379,5615, +5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631, +5632,5633,5634,1380,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646, +5647,5648,5649,1381,1056,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660, +1666,5661,5662,5663,5664,5665,5666,5667,5668,1667,5669,1668,5670,5671,5672,5673, +5674,5675,5676,5677,5678,1155,5679,5680,5681,5682,5683,5684,5685,5686,5687,5688, +5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,1669,5699,5700,5701,5702,5703, +5704,5705,1670,5706,5707,5708,5709,5710,1671,5711,5712,5713,5714,1382,5715,5716, +5717,5718,5719,5720,5721,5722,5723,5724,5725,1672,5726,5727,1673,1674,5728,5729, +5730,5731,5732,5733,5734,5735,5736,1675,5737,5738,5739,5740,5741,5742,5743,5744, +1676,5745,5746,5747,5748,5749,5750,5751,1383,5752,5753,5754,5755,5756,5757,5758, +5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,1677,5769,5770,5771,5772,5773, +1678,5774,5775,5776, 998,5777,5778,5779,5780,5781,5782,5783,5784,5785,1384,5786, +5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,1679,5801, +5802,5803,1115,1116,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815, +5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831, +5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847, +5848,5849,5850,5851,5852,5853,5854,5855,1680,5856,5857,5858,5859,5860,5861,5862, +5863,5864,1681,5865,5866,5867,1682,5868,5869,5870,5871,5872,5873,5874,5875,5876, +5877,5878,5879,1683,5880,1684,5881,5882,5883,5884,1685,5885,5886,5887,5888,5889, +5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905, +5906,5907,1686,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,1687, +5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951, +5952,1688,1689,5953,1199,5954,5955,5956,5957,5958,5959,5960,5961,1690,5962,5963, +5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979, +5980,5981,1385,5982,1386,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993, +5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009, +6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025, +6026,6027,1265,6028,6029,1691,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039, +6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055, +6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071, +6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,1692,6085,6086, +6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102, +6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118, +6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,1693,6132,6133, +6134,6135,6136,1694,6137,6138,6139,6140,6141,1695,6142,6143,6144,6145,6146,6147, +6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163, +6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179, +6180,6181,6182,6183,6184,6185,1696,6186,6187,6188,6189,6190,6191,6192,6193,6194, +6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210, +6211,6212,6213,6214,6215,6216,6217,6218,6219,1697,6220,6221,6222,6223,6224,6225, +6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241, +6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,1698,6254,6255,6256, +6257,6258,6259,6260,6261,6262,6263,1200,6264,6265,6266,6267,6268,6269,6270,6271, #1024 +6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,6286,6287, +6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,1699, +6303,6304,1700,6305,6306,6307,6308,6309,6310,6311,6312,6313,6314,6315,6316,6317, +6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333, +6334,6335,6336,6337,6338,6339,1701,6340,6341,6342,6343,6344,1387,6345,6346,6347, +6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363, +6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379, +6380,6381,6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395, +6396,6397,6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411, +6412,6413,1702,6414,6415,6416,6417,6418,6419,6420,6421,6422,1703,6423,6424,6425, +6426,6427,6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,1704,6439,6440, +6441,6442,6443,6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456, +6457,6458,6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472, +6473,6474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488, +6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,1266, +6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519, +6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535, +6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551, +1705,1706,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565, +6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581, +6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597, +6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613, +6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629, +6630,6631,6632,6633,6634,6635,6636,6637,1388,6638,6639,6640,6641,6642,6643,6644, +1707,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,6659, +6660,6661,6662,6663,1708,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674, +1201,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,6689, +6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705, +6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,6719,6720,6721, +6722,6723,6724,6725,1389,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736, +1390,1709,6737,6738,6739,6740,6741,6742,1710,6743,6744,6745,6746,1391,6747,6748, +6749,6750,6751,6752,6753,6754,6755,6756,6757,1392,6758,6759,6760,6761,6762,6763, +6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779, +6780,1202,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,6794, +6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,6809,1711, +6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,6824,6825, +6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,1393,6837,6838,6839,6840, +6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856, +6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872, +6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888, +6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,6899,6900,6901,6902,1712,6903, +6904,6905,6906,6907,6908,6909,6910,1713,6911,6912,6913,6914,6915,6916,6917,6918, +6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934, +6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950, +6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966, +6967,6968,6969,6970,6971,6972,6973,6974,1714,6975,6976,6977,6978,6979,6980,6981, +6982,6983,6984,6985,6986,6987,6988,1394,6989,6990,6991,6992,6993,6994,6995,6996, +6997,6998,6999,7000,1715,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011, +7012,7013,7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027, +7028,1716,7029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042, +7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058, +7059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074, +7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090, +7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106, +7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122, +7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138, +7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154, +7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,7169,7170, +7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,7184,7185,7186, +7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202, +7203,7204,7205,7206,7207,1395,7208,7209,7210,7211,7212,7213,1717,7214,7215,7216, +7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,7230,7231,7232, +7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245,7246,7247,7248, +7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261,7262,7263,7264, +7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280, +7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,7296, +7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308,7309,7310,7311,7312, +7313,1718,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327, +7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343, +7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359, +7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375, +7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391, +7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407, +7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423, +7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,7439, +7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455, +7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,7469,7470,7471, +7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487, +7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503, +7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519, +7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535, +7536,7537,7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,7550,7551, +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, +7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583, +7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599, +7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615, +7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631, +7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647, +7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663, +7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,7678,7679, +7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,7693,7694,7695, +7696,7697,7698,7699,7700,7701,7702,7703,7704,7705,7706,7707,7708,7709,7710,7711, +7712,7713,7714,7715,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727, +7728,7729,7730,7731,7732,7733,7734,7735,7736,7737,7738,7739,7740,7741,7742,7743, +7744,7745,7746,7747,7748,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7759, +7760,7761,7762,7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775, +7776,7777,7778,7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791, +7792,7793,7794,7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,7806,7807, +7808,7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823, +7824,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839, +7840,7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855, +7856,7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871, +7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887, +7888,7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903, +7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919, +7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271, +8272,8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287, +8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303, +8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319, +8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335, +8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351, +8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367, +8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,8383, +8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399, +8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415, +8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431, +8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443,8444,8445,8446,8447, +8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463, +8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479, +8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495, +8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511, +8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8526,8527, +8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543, +8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559, +8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575, +8576,8577,8578,8579,8580,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591, +8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607, +8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,8623, +8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,8639, +8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655, +8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671, +8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,8685,8686,8687, +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, +8704,8705,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719, +8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735, +8736,8737,8738,8739,8740,8741) + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/euckrprober.py b/pipenv/vendor/requests/packages/chardet/euckrprober.py new file mode 100644 index 00000000..5982a46b --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/euckrprober.py @@ -0,0 +1,42 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import EUCKRSMModel + + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCKRSMModel) + self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-KR" diff --git a/pipenv/vendor/requests/packages/chardet/euctwfreq.py b/pipenv/vendor/requests/packages/chardet/euctwfreq.py new file mode 100644 index 00000000..576e7504 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/euctwfreq.py @@ -0,0 +1,428 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 8102 + +EUCTWCharToFreqOrder = ( + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +#Everything below is of no interest for detection purpose +2515,1613,4582,8119,3312,3866,2516,8120,4058,8121,1637,4059,2466,4583,3867,8122, # 8118 +2493,3016,3734,8123,8124,2192,8125,8126,2162,8127,8128,8129,8130,8131,8132,8133, # 8134 +8134,8135,8136,8137,8138,8139,8140,8141,8142,8143,8144,8145,8146,8147,8148,8149, # 8150 +8150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8160,8161,8162,8163,8164,8165, # 8166 +8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181, # 8182 +8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197, # 8198 +8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213, # 8214 +8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229, # 8230 +8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245, # 8246 +8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261, # 8262 +8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277, # 8278 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,8293, # 8294 +8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,8308,8309, # 8310 +8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325, # 8326 +8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341, # 8342 +8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357, # 8358 +8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373, # 8374 +8374,8375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389, # 8390 +8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405, # 8406 +8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421, # 8422 +8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437, # 8438 +8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453, # 8454 +8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469, # 8470 +8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485, # 8486 +8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501, # 8502 +8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517, # 8518 +8518,8519,8520,8521,8522,8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533, # 8534 +8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549, # 8550 +8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,8565, # 8566 +8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,8576,8577,8578,8579,8580,8581, # 8582 +8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597, # 8598 +8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613, # 8614 +8614,8615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629, # 8630 +8630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645, # 8646 +8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661, # 8662 +8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677, # 8678 +8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693, # 8694 +8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709, # 8710 +8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725, # 8726 +8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741) # 8742 + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/euctwprober.py b/pipenv/vendor/requests/packages/chardet/euctwprober.py new file mode 100644 index 00000000..fe652fe3 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/euctwprober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCTWDistributionAnalysis +from .mbcssm import EUCTWSMModel + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCTWSMModel) + self._mDistributionAnalyzer = EUCTWDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-TW" diff --git a/pipenv/vendor/requests/packages/chardet/gb2312freq.py b/pipenv/vendor/requests/packages/chardet/gb2312freq.py new file mode 100644 index 00000000..1238f510 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/gb2312freq.py @@ -0,0 +1,472 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312CharToFreqOrder = ( +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, # last 512 +#Everything below is of no interest for detection purpose +5508,6484,3900,3414,3974,4441,4024,3537,4037,5628,5099,3633,6485,3148,6486,3636, +5509,3257,5510,5973,5445,5872,4941,4403,3174,4627,5873,6276,2286,4230,5446,5874, +5122,6102,6103,4162,5447,5123,5323,4849,6277,3980,3851,5066,4246,5774,5067,6278, +3001,2807,5695,3346,5775,5974,5158,5448,6487,5975,5976,5776,3598,6279,5696,4806, +4211,4154,6280,6488,6489,6490,6281,4212,5037,3374,4171,6491,4562,4807,4722,4827, +5977,6104,4532,4079,5159,5324,5160,4404,3858,5359,5875,3975,4288,4610,3486,4512, +5325,3893,5360,6282,6283,5560,2522,4231,5978,5186,5449,2569,3878,6284,5401,3578, +4415,6285,4656,5124,5979,2506,4247,4449,3219,3417,4334,4969,4329,6492,4576,4828, +4172,4416,4829,5402,6286,3927,3852,5361,4369,4830,4477,4867,5876,4173,6493,6105, +4657,6287,6106,5877,5450,6494,4155,4868,5451,3700,5629,4384,6288,6289,5878,3189, +4881,6107,6290,6495,4513,6496,4692,4515,4723,5100,3356,6497,6291,3810,4080,5561, +3570,4430,5980,6498,4355,5697,6499,4724,6108,6109,3764,4050,5038,5879,4093,3226, +6292,5068,5217,4693,3342,5630,3504,4831,4377,4466,4309,5698,4431,5777,6293,5778, +4272,3706,6110,5326,3752,4676,5327,4273,5403,4767,5631,6500,5699,5880,3475,5039, +6294,5562,5125,4348,4301,4482,4068,5126,4593,5700,3380,3462,5981,5563,3824,5404, +4970,5511,3825,4738,6295,6501,5452,4516,6111,5881,5564,6502,6296,5982,6503,4213, +4163,3454,6504,6112,4009,4450,6113,4658,6297,6114,3035,6505,6115,3995,4904,4739, +4563,4942,4110,5040,3661,3928,5362,3674,6506,5292,3612,4791,5565,4149,5983,5328, +5259,5021,4725,4577,4564,4517,4364,6298,5405,4578,5260,4594,4156,4157,5453,3592, +3491,6507,5127,5512,4709,4922,5984,5701,4726,4289,6508,4015,6116,5128,4628,3424, +4241,5779,6299,4905,6509,6510,5454,5702,5780,6300,4365,4923,3971,6511,5161,3270, +3158,5985,4100, 867,5129,5703,6117,5363,3695,3301,5513,4467,6118,6512,5455,4232, +4242,4629,6513,3959,4478,6514,5514,5329,5986,4850,5162,5566,3846,4694,6119,5456, +4869,5781,3779,6301,5704,5987,5515,4710,6302,5882,6120,4392,5364,5705,6515,6121, +6516,6517,3736,5988,5457,5989,4695,2457,5883,4551,5782,6303,6304,6305,5130,4971, +6122,5163,6123,4870,3263,5365,3150,4871,6518,6306,5783,5069,5706,3513,3498,4409, +5330,5632,5366,5458,5459,3991,5990,4502,3324,5991,5784,3696,4518,5633,4119,6519, +4630,5634,4417,5707,4832,5992,3418,6124,5993,5567,4768,5218,6520,4595,3458,5367, +6125,5635,6126,4202,6521,4740,4924,6307,3981,4069,4385,6308,3883,2675,4051,3834, +4302,4483,5568,5994,4972,4101,5368,6309,5164,5884,3922,6127,6522,6523,5261,5460, +5187,4164,5219,3538,5516,4111,3524,5995,6310,6311,5369,3181,3386,2484,5188,3464, +5569,3627,5708,6524,5406,5165,4677,4492,6312,4872,4851,5885,4468,5996,6313,5709, +5710,6128,2470,5886,6314,5293,4882,5785,3325,5461,5101,6129,5711,5786,6525,4906, +6526,6527,4418,5887,5712,4808,2907,3701,5713,5888,6528,3765,5636,5331,6529,6530, +3593,5889,3637,4943,3692,5714,5787,4925,6315,6130,5462,4405,6131,6132,6316,5262, +6531,6532,5715,3859,5716,5070,4696,5102,3929,5788,3987,4792,5997,6533,6534,3920, +4809,5000,5998,6535,2974,5370,6317,5189,5263,5717,3826,6536,3953,5001,4883,3190, +5463,5890,4973,5999,4741,6133,6134,3607,5570,6000,4711,3362,3630,4552,5041,6318, +6001,2950,2953,5637,4646,5371,4944,6002,2044,4120,3429,6319,6537,5103,4833,6538, +6539,4884,4647,3884,6003,6004,4758,3835,5220,5789,4565,5407,6540,6135,5294,4697, +4852,6320,6321,3206,4907,6541,6322,4945,6542,6136,6543,6323,6005,4631,3519,6544, +5891,6545,5464,3784,5221,6546,5571,4659,6547,6324,6137,5190,6548,3853,6549,4016, +4834,3954,6138,5332,3827,4017,3210,3546,4469,5408,5718,3505,4648,5790,5131,5638, +5791,5465,4727,4318,6325,6326,5792,4553,4010,4698,3439,4974,3638,4335,3085,6006, +5104,5042,5166,5892,5572,6327,4356,4519,5222,5573,5333,5793,5043,6550,5639,5071, +4503,6328,6139,6551,6140,3914,3901,5372,6007,5640,4728,4793,3976,3836,4885,6552, +4127,6553,4451,4102,5002,6554,3686,5105,6555,5191,5072,5295,4611,5794,5296,6556, +5893,5264,5894,4975,5466,5265,4699,4976,4370,4056,3492,5044,4886,6557,5795,4432, +4769,4357,5467,3940,4660,4290,6141,4484,4770,4661,3992,6329,4025,4662,5022,4632, +4835,4070,5297,4663,4596,5574,5132,5409,5895,6142,4504,5192,4664,5796,5896,3885, +5575,5797,5023,4810,5798,3732,5223,4712,5298,4084,5334,5468,6143,4052,4053,4336, +4977,4794,6558,5335,4908,5576,5224,4233,5024,4128,5469,5225,4873,6008,5045,4729, +4742,4633,3675,4597,6559,5897,5133,5577,5003,5641,5719,6330,6560,3017,2382,3854, +4406,4811,6331,4393,3964,4946,6561,2420,3722,6562,4926,4378,3247,1736,4442,6332, +5134,6333,5226,3996,2918,5470,4319,4003,4598,4743,4744,4485,3785,3902,5167,5004, +5373,4394,5898,6144,4874,1793,3997,6334,4085,4214,5106,5642,4909,5799,6009,4419, +4189,3330,5899,4165,4420,5299,5720,5227,3347,6145,4081,6335,2876,3930,6146,3293, +3786,3910,3998,5900,5300,5578,2840,6563,5901,5579,6147,3531,5374,6564,6565,5580, +4759,5375,6566,6148,3559,5643,6336,6010,5517,6337,6338,5721,5902,3873,6011,6339, +6567,5518,3868,3649,5722,6568,4771,4947,6569,6149,4812,6570,2853,5471,6340,6341, +5644,4795,6342,6012,5723,6343,5724,6013,4349,6344,3160,6150,5193,4599,4514,4493, +5168,4320,6345,4927,3666,4745,5169,5903,5005,4928,6346,5725,6014,4730,4203,5046, +4948,3395,5170,6015,4150,6016,5726,5519,6347,5047,3550,6151,6348,4197,4310,5904, +6571,5581,2965,6152,4978,3960,4291,5135,6572,5301,5727,4129,4026,5905,4853,5728, +5472,6153,6349,4533,2700,4505,5336,4678,3583,5073,2994,4486,3043,4554,5520,6350, +6017,5800,4487,6351,3931,4103,5376,6352,4011,4321,4311,4190,5136,6018,3988,3233, +4350,5906,5645,4198,6573,5107,3432,4191,3435,5582,6574,4139,5410,6353,5411,3944, +5583,5074,3198,6575,6354,4358,6576,5302,4600,5584,5194,5412,6577,6578,5585,5413, +5303,4248,5414,3879,4433,6579,4479,5025,4854,5415,6355,4760,4772,3683,2978,4700, +3797,4452,3965,3932,3721,4910,5801,6580,5195,3551,5907,3221,3471,3029,6019,3999, +5908,5909,5266,5267,3444,3023,3828,3170,4796,5646,4979,4259,6356,5647,5337,3694, +6357,5648,5338,4520,4322,5802,3031,3759,4071,6020,5586,4836,4386,5048,6581,3571, +4679,4174,4949,6154,4813,3787,3402,3822,3958,3215,3552,5268,4387,3933,4950,4359, +6021,5910,5075,3579,6358,4234,4566,5521,6359,3613,5049,6022,5911,3375,3702,3178, +4911,5339,4521,6582,6583,4395,3087,3811,5377,6023,6360,6155,4027,5171,5649,4421, +4249,2804,6584,2270,6585,4000,4235,3045,6156,5137,5729,4140,4312,3886,6361,4330, +6157,4215,6158,3500,3676,4929,4331,3713,4930,5912,4265,3776,3368,5587,4470,4855, +3038,4980,3631,6159,6160,4132,4680,6161,6362,3923,4379,5588,4255,6586,4121,6587, +6363,4649,6364,3288,4773,4774,6162,6024,6365,3543,6588,4274,3107,3737,5050,5803, +4797,4522,5589,5051,5730,3714,4887,5378,4001,4523,6163,5026,5522,4701,4175,2791, +3760,6589,5473,4224,4133,3847,4814,4815,4775,3259,5416,6590,2738,6164,6025,5304, +3733,5076,5650,4816,5590,6591,6165,6592,3934,5269,6593,3396,5340,6594,5804,3445, +3602,4042,4488,5731,5732,3525,5591,4601,5196,6166,6026,5172,3642,4612,3202,4506, +4798,6366,3818,5108,4303,5138,5139,4776,3332,4304,2915,3415,4434,5077,5109,4856, +2879,5305,4817,6595,5913,3104,3144,3903,4634,5341,3133,5110,5651,5805,6167,4057, +5592,2945,4371,5593,6596,3474,4182,6367,6597,6168,4507,4279,6598,2822,6599,4777, +4713,5594,3829,6169,3887,5417,6170,3653,5474,6368,4216,2971,5228,3790,4579,6369, +5733,6600,6601,4951,4746,4555,6602,5418,5475,6027,3400,4665,5806,6171,4799,6028, +5052,6172,3343,4800,4747,5006,6370,4556,4217,5476,4396,5229,5379,5477,3839,5914, +5652,5807,4714,3068,4635,5808,6173,5342,4192,5078,5419,5523,5734,6174,4557,6175, +4602,6371,6176,6603,5809,6372,5735,4260,3869,5111,5230,6029,5112,6177,3126,4681, +5524,5915,2706,3563,4748,3130,6178,4018,5525,6604,6605,5478,4012,4837,6606,4534, +4193,5810,4857,3615,5479,6030,4082,3697,3539,4086,5270,3662,4508,4931,5916,4912, +5811,5027,3888,6607,4397,3527,3302,3798,2775,2921,2637,3966,4122,4388,4028,4054, +1633,4858,5079,3024,5007,3982,3412,5736,6608,3426,3236,5595,3030,6179,3427,3336, +3279,3110,6373,3874,3039,5080,5917,5140,4489,3119,6374,5812,3405,4494,6031,4666, +4141,6180,4166,6032,5813,4981,6609,5081,4422,4982,4112,3915,5653,3296,3983,6375, +4266,4410,5654,6610,6181,3436,5082,6611,5380,6033,3819,5596,4535,5231,5306,5113, +6612,4952,5918,4275,3113,6613,6376,6182,6183,5814,3073,4731,4838,5008,3831,6614, +4888,3090,3848,4280,5526,5232,3014,5655,5009,5737,5420,5527,6615,5815,5343,5173, +5381,4818,6616,3151,4953,6617,5738,2796,3204,4360,2989,4281,5739,5174,5421,5197, +3132,5141,3849,5142,5528,5083,3799,3904,4839,5480,2880,4495,3448,6377,6184,5271, +5919,3771,3193,6034,6035,5920,5010,6036,5597,6037,6378,6038,3106,5422,6618,5423, +5424,4142,6619,4889,5084,4890,4313,5740,6620,3437,5175,5307,5816,4199,5198,5529, +5817,5199,5656,4913,5028,5344,3850,6185,2955,5272,5011,5818,4567,4580,5029,5921, +3616,5233,6621,6622,6186,4176,6039,6379,6380,3352,5200,5273,2908,5598,5234,3837, +5308,6623,6624,5819,4496,4323,5309,5201,6625,6626,4983,3194,3838,4167,5530,5922, +5274,6381,6382,3860,3861,5599,3333,4292,4509,6383,3553,5481,5820,5531,4778,6187, +3955,3956,4324,4389,4218,3945,4325,3397,2681,5923,4779,5085,4019,5482,4891,5382, +5383,6040,4682,3425,5275,4094,6627,5310,3015,5483,5657,4398,5924,3168,4819,6628, +5925,6629,5532,4932,4613,6041,6630,4636,6384,4780,4204,5658,4423,5821,3989,4683, +5822,6385,4954,6631,5345,6188,5425,5012,5384,3894,6386,4490,4104,6632,5741,5053, +6633,5823,5926,5659,5660,5927,6634,5235,5742,5824,4840,4933,4820,6387,4859,5928, +4955,6388,4143,3584,5825,5346,5013,6635,5661,6389,5014,5484,5743,4337,5176,5662, +6390,2836,6391,3268,6392,6636,6042,5236,6637,4158,6638,5744,5663,4471,5347,3663, +4123,5143,4293,3895,6639,6640,5311,5929,5826,3800,6189,6393,6190,5664,5348,3554, +3594,4749,4603,6641,5385,4801,6043,5827,4183,6642,5312,5426,4761,6394,5665,6191, +4715,2669,6643,6644,5533,3185,5427,5086,5930,5931,5386,6192,6044,6645,4781,4013, +5745,4282,4435,5534,4390,4267,6045,5746,4984,6046,2743,6193,3501,4087,5485,5932, +5428,4184,4095,5747,4061,5054,3058,3862,5933,5600,6646,5144,3618,6395,3131,5055, +5313,6396,4650,4956,3855,6194,3896,5202,4985,4029,4225,6195,6647,5828,5486,5829, +3589,3002,6648,6397,4782,5276,6649,6196,6650,4105,3803,4043,5237,5830,6398,4096, +3643,6399,3528,6651,4453,3315,4637,6652,3984,6197,5535,3182,3339,6653,3096,2660, +6400,6654,3449,5934,4250,4236,6047,6401,5831,6655,5487,3753,4062,5832,6198,6199, +6656,3766,6657,3403,4667,6048,6658,4338,2897,5833,3880,2797,3780,4326,6659,5748, +5015,6660,5387,4351,5601,4411,6661,3654,4424,5935,4339,4072,5277,4568,5536,6402, +6662,5238,6663,5349,5203,6200,5204,6201,5145,4536,5016,5056,4762,5834,4399,4957, +6202,6403,5666,5749,6664,4340,6665,5936,5177,5667,6666,6667,3459,4668,6404,6668, +6669,4543,6203,6670,4276,6405,4480,5537,6671,4614,5205,5668,6672,3348,2193,4763, +6406,6204,5937,5602,4177,5669,3419,6673,4020,6205,4443,4569,5388,3715,3639,6407, +6049,4058,6206,6674,5938,4544,6050,4185,4294,4841,4651,4615,5488,6207,6408,6051, +5178,3241,3509,5835,6208,4958,5836,4341,5489,5278,6209,2823,5538,5350,5206,5429, +6675,4638,4875,4073,3516,4684,4914,4860,5939,5603,5389,6052,5057,3237,5490,3791, +6676,6409,6677,4821,4915,4106,5351,5058,4243,5539,4244,5604,4842,4916,5239,3028, +3716,5837,5114,5605,5390,5940,5430,6210,4332,6678,5540,4732,3667,3840,6053,4305, +3408,5670,5541,6410,2744,5240,5750,6679,3234,5606,6680,5607,5671,3608,4283,4159, +4400,5352,4783,6681,6411,6682,4491,4802,6211,6412,5941,6413,6414,5542,5751,6683, +4669,3734,5942,6684,6415,5943,5059,3328,4670,4144,4268,6685,6686,6687,6688,4372, +3603,6689,5944,5491,4373,3440,6416,5543,4784,4822,5608,3792,4616,5838,5672,3514, +5391,6417,4892,6690,4639,6691,6054,5673,5839,6055,6692,6056,5392,6212,4038,5544, +5674,4497,6057,6693,5840,4284,5675,4021,4545,5609,6418,4454,6419,6213,4113,4472, +5314,3738,5087,5279,4074,5610,4959,4063,3179,4750,6058,6420,6214,3476,4498,4716, +5431,4960,4685,6215,5241,6694,6421,6216,6695,5841,5945,6422,3748,5946,5179,3905, +5752,5545,5947,4374,6217,4455,6423,4412,6218,4803,5353,6696,3832,5280,6219,4327, +4702,6220,6221,6059,4652,5432,6424,3749,4751,6425,5753,4986,5393,4917,5948,5030, +5754,4861,4733,6426,4703,6697,6222,4671,5949,4546,4961,5180,6223,5031,3316,5281, +6698,4862,4295,4934,5207,3644,6427,5842,5950,6428,6429,4570,5843,5282,6430,6224, +5088,3239,6060,6699,5844,5755,6061,6431,2701,5546,6432,5115,5676,4039,3993,3327, +4752,4425,5315,6433,3941,6434,5677,4617,4604,3074,4581,6225,5433,6435,6226,6062, +4823,5756,5116,6227,3717,5678,4717,5845,6436,5679,5846,6063,5847,6064,3977,3354, +6437,3863,5117,6228,5547,5394,4499,4524,6229,4605,6230,4306,4500,6700,5951,6065, +3693,5952,5089,4366,4918,6701,6231,5548,6232,6702,6438,4704,5434,6703,6704,5953, +4168,6705,5680,3420,6706,5242,4407,6066,3812,5757,5090,5954,4672,4525,3481,5681, +4618,5395,5354,5316,5955,6439,4962,6707,4526,6440,3465,4673,6067,6441,5682,6708, +5435,5492,5758,5683,4619,4571,4674,4804,4893,4686,5493,4753,6233,6068,4269,6442, +6234,5032,4705,5146,5243,5208,5848,6235,6443,4963,5033,4640,4226,6236,5849,3387, +6444,6445,4436,4437,5850,4843,5494,4785,4894,6709,4361,6710,5091,5956,3331,6237, +4987,5549,6069,6711,4342,3517,4473,5317,6070,6712,6071,4706,6446,5017,5355,6713, +6714,4988,5436,6447,4734,5759,6715,4735,4547,4456,4754,6448,5851,6449,6450,3547, +5852,5318,6451,6452,5092,4205,6716,6238,4620,4219,5611,6239,6072,4481,5760,5957, +5958,4059,6240,6453,4227,4537,6241,5761,4030,4186,5244,5209,3761,4457,4876,3337, +5495,5181,6242,5959,5319,5612,5684,5853,3493,5854,6073,4169,5613,5147,4895,6074, +5210,6717,5182,6718,3830,6243,2798,3841,6075,6244,5855,5614,3604,4606,5496,5685, +5118,5356,6719,6454,5960,5357,5961,6720,4145,3935,4621,5119,5962,4261,6721,6455, +4786,5963,4375,4582,6245,6246,6247,6076,5437,4877,5856,3376,4380,6248,4160,6722, +5148,6456,5211,6457,6723,4718,6458,6724,6249,5358,4044,3297,6459,6250,5857,5615, +5497,5245,6460,5498,6725,6251,6252,5550,3793,5499,2959,5396,6461,6462,4572,5093, +5500,5964,3806,4146,6463,4426,5762,5858,6077,6253,4755,3967,4220,5965,6254,4989, +5501,6464,4352,6726,6078,4764,2290,5246,3906,5438,5283,3767,4964,2861,5763,5094, +6255,6256,4622,5616,5859,5860,4707,6727,4285,4708,4824,5617,6257,5551,4787,5212, +4965,4935,4687,6465,6728,6466,5686,6079,3494,4413,2995,5247,5966,5618,6729,5967, +5764,5765,5687,5502,6730,6731,6080,5397,6467,4990,6258,6732,4538,5060,5619,6733, +4719,5688,5439,5018,5149,5284,5503,6734,6081,4607,6259,5120,3645,5861,4583,6260, +4584,4675,5620,4098,5440,6261,4863,2379,3306,4585,5552,5689,4586,5285,6735,4864, +6736,5286,6082,6737,4623,3010,4788,4381,4558,5621,4587,4896,3698,3161,5248,4353, +4045,6262,3754,5183,4588,6738,6263,6739,6740,5622,3936,6741,6468,6742,6264,5095, +6469,4991,5968,6743,4992,6744,6083,4897,6745,4256,5766,4307,3108,3968,4444,5287, +3889,4343,6084,4510,6085,4559,6086,4898,5969,6746,5623,5061,4919,5249,5250,5504, +5441,6265,5320,4878,3242,5862,5251,3428,6087,6747,4237,5624,5442,6266,5553,4539, +6748,2585,3533,5398,4262,6088,5150,4736,4438,6089,6267,5505,4966,6749,6268,6750, +6269,5288,5554,3650,6090,6091,4624,6092,5690,6751,5863,4270,5691,4277,5555,5864, +6752,5692,4720,4865,6470,5151,4688,4825,6753,3094,6754,6471,3235,4653,6755,5213, +5399,6756,3201,4589,5865,4967,6472,5866,6473,5019,3016,6757,5321,4756,3957,4573, +6093,4993,5767,4721,6474,6758,5625,6759,4458,6475,6270,6760,5556,4994,5214,5252, +6271,3875,5768,6094,5034,5506,4376,5769,6761,2120,6476,5253,5770,6762,5771,5970, +3990,5971,5557,5558,5772,6477,6095,2787,4641,5972,5121,6096,6097,6272,6763,3703, +5867,5507,6273,4206,6274,4789,6098,6764,3619,3646,3833,3804,2394,3788,4936,3978, +4866,4899,6099,6100,5559,6478,6765,3599,5868,6101,5869,5870,6275,6766,4527,6767) + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/gb2312prober.py b/pipenv/vendor/requests/packages/chardet/gb2312prober.py new file mode 100644 index 00000000..0325a2d8 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/gb2312prober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import GB2312DistributionAnalysis +from .mbcssm import GB2312SMModel + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(GB2312SMModel) + self._mDistributionAnalyzer = GB2312DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "GB2312" diff --git a/pipenv/vendor/requests/packages/chardet/hebrewprober.py b/pipenv/vendor/requests/packages/chardet/hebrewprober.py new file mode 100644 index 00000000..ba225c5e --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/hebrewprober.py @@ -0,0 +1,283 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .constants import eNotMe, eDetecting +from .compat import wrap_ord + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +# windows-1255 / ISO-8859-8 code points of interest +FINAL_KAF = 0xea +NORMAL_KAF = 0xeb +FINAL_MEM = 0xed +NORMAL_MEM = 0xee +FINAL_NUN = 0xef +NORMAL_NUN = 0xf0 +FINAL_PE = 0xf3 +NORMAL_PE = 0xf4 +FINAL_TSADI = 0xf5 +NORMAL_TSADI = 0xf6 + +# Minimum Visual vs Logical final letter score difference. +# If the difference is below this, don't rely solely on the final letter score +# distance. +MIN_FINAL_CHAR_DISTANCE = 5 + +# Minimum Visual vs Logical model score difference. +# If the difference is below this, don't rely at all on the model score +# distance. +MIN_MODEL_DISTANCE = 0.01 + +VISUAL_HEBREW_NAME = "ISO-8859-8" +LOGICAL_HEBREW_NAME = "windows-1255" + + +class HebrewProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mLogicalProber = None + self._mVisualProber = None + self.reset() + + def reset(self): + self._mFinalCharLogicalScore = 0 + self._mFinalCharVisualScore = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate + # a word delimiter at the beginning of the data + self._mPrev = ' ' + self._mBeforePrev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._mLogicalProber = logicalProber + self._mVisualProber = visualProber + + def is_final(self, c): + return wrap_ord(c) in [FINAL_KAF, FINAL_MEM, FINAL_NUN, FINAL_PE, + FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters + # causing the Non-Final tsadi to appear at an end of a word even + # though this is not the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being + # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' + # for example legally end with a Non-Final Pe or Kaf. However, the + # benefit of these letters as Non-Final letters outweighs the damage + # since these words are quite rare. + return wrap_ord(c) in [NORMAL_KAF, NORMAL_MEM, NORMAL_NUN, NORMAL_PE] + + def feed(self, aBuf): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew + # or visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is + # an indication that the text is laid out "naturally" since the + # final letter really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In + # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, + # should not end with the Non-Final form of that letter. Exceptions + # to this rule are mentioned above in isNonFinal(). This is an + # indication that the text is laid out backwards. +1 for visual + # score + # 3) A word longer than 1 letter, starting with a final letter. Final + # letters should not appear at the beginning of a word. This is an + # indication that the text is laid out backwards. +1 for visual + # score. + # + # The visual score and logical score are accumulated throughout the + # text and are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since + # that case is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with + # spaces) so the word boundary detection works properly. [MAP] + + if self.get_state() == eNotMe: + # Both model probers say it's not them. No reason to continue. + return eNotMe + + aBuf = self.filter_high_bit_only(aBuf) + + for cur in aBuf: + if cur == ' ': + # We stand on a space - a word just ended + if self._mBeforePrev != ' ': + # next-to-last char was not a space so self._mPrev is not a + # 1 letter word + if self.is_final(self._mPrev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._mFinalCharLogicalScore += 1 + elif self.is_non_final(self._mPrev): + # case (2) [-2:not space][-1:Non-Final letter][ + # cur:space] + self._mFinalCharVisualScore += 1 + else: + # Not standing on a space + if ((self._mBeforePrev == ' ') and + (self.is_final(self._mPrev)) and (cur != ' ')): + # case (3) [-2:space][-1:final letter][cur:not space] + self._mFinalCharVisualScore += 1 + self._mBeforePrev = self._mPrev + self._mPrev = cur + + # Forever detecting, till the end or until both model probers return + # eNotMe (handled above) + return eDetecting + + def get_charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._mFinalCharLogicalScore - self._mFinalCharVisualScore + if finalsub >= MIN_FINAL_CHAR_DISTANCE: + return LOGICAL_HEBREW_NAME + if finalsub <= -MIN_FINAL_CHAR_DISTANCE: + return VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = (self._mLogicalProber.get_confidence() + - self._mVisualProber.get_confidence()) + if modelsub > MIN_MODEL_DISTANCE: + return LOGICAL_HEBREW_NAME + if modelsub < -MIN_MODEL_DISTANCE: + return VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the + # day. + if finalsub < 0.0: + return VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to + # Logical. + return LOGICAL_HEBREW_NAME + + def get_state(self): + # Remain active as long as any of the model probers are active. + if (self._mLogicalProber.get_state() == eNotMe) and \ + (self._mVisualProber.get_state() == eNotMe): + return eNotMe + return eDetecting diff --git a/pipenv/vendor/requests/packages/chardet/jisfreq.py b/pipenv/vendor/requests/packages/chardet/jisfreq.py new file mode 100644 index 00000000..064345b0 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/jisfreq.py @@ -0,0 +1,569 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JISCharToFreqOrder = ( + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +#Everything below is of no interest for detection purpose +2138,2122,3730,2888,1995,1820,1044,6190,6191,6192,6193,6194,6195,6196,6197,6198, # 4384 +6199,6200,6201,6202,6203,6204,6205,4670,6206,6207,6208,6209,6210,6211,6212,6213, # 4400 +6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229, # 4416 +6230,6231,6232,6233,6234,6235,6236,6237,3187,6238,6239,3969,6240,6241,6242,6243, # 4432 +6244,4671,6245,6246,4672,6247,6248,4133,6249,6250,4364,6251,2923,2556,2613,4673, # 4448 +4365,3970,6252,6253,6254,6255,4674,6256,6257,6258,2768,2353,4366,4675,4676,3188, # 4464 +4367,3463,6259,4134,4677,4678,6260,2267,6261,3842,3332,4368,3543,6262,6263,6264, # 4480 +3013,1954,1928,4135,4679,6265,6266,2478,3091,6267,4680,4369,6268,6269,1699,6270, # 4496 +3544,4136,4681,6271,4137,6272,4370,2804,6273,6274,2593,3971,3972,4682,6275,2236, # 4512 +4683,6276,6277,4684,6278,6279,4138,3973,4685,6280,6281,3258,6282,6283,6284,6285, # 4528 +3974,4686,2841,3975,6286,6287,3545,6288,6289,4139,4687,4140,6290,4141,6291,4142, # 4544 +6292,6293,3333,6294,6295,6296,4371,6297,3399,6298,6299,4372,3976,6300,6301,6302, # 4560 +4373,6303,6304,3843,3731,6305,4688,4374,6306,6307,3259,2294,6308,3732,2530,4143, # 4576 +6309,4689,6310,6311,6312,3048,6313,6314,4690,3733,2237,6315,6316,2282,3334,6317, # 4592 +6318,3844,6319,6320,4691,6321,3400,4692,6322,4693,6323,3049,6324,4375,6325,3977, # 4608 +6326,6327,6328,3546,6329,4694,3335,6330,4695,4696,6331,6332,6333,6334,4376,3978, # 4624 +6335,4697,3979,4144,6336,3980,4698,6337,6338,6339,6340,6341,4699,4700,4701,6342, # 4640 +6343,4702,6344,6345,4703,6346,6347,4704,6348,4705,4706,3135,6349,4707,6350,4708, # 4656 +6351,4377,6352,4709,3734,4145,6353,2506,4710,3189,6354,3050,4711,3981,6355,3547, # 4672 +3014,4146,4378,3735,2651,3845,3260,3136,2224,1986,6356,3401,6357,4712,2594,3627, # 4688 +3137,2573,3736,3982,4713,3628,4714,4715,2682,3629,4716,6358,3630,4379,3631,6359, # 4704 +6360,6361,3983,6362,6363,6364,6365,4147,3846,4717,6366,6367,3737,2842,6368,4718, # 4720 +2628,6369,3261,6370,2386,6371,6372,3738,3984,4719,3464,4720,3402,6373,2924,3336, # 4736 +4148,2866,6374,2805,3262,4380,2704,2069,2531,3138,2806,2984,6375,2769,6376,4721, # 4752 +4722,3403,6377,6378,3548,6379,6380,2705,3092,1979,4149,2629,3337,2889,6381,3338, # 4768 +4150,2557,3339,4381,6382,3190,3263,3739,6383,4151,4723,4152,2558,2574,3404,3191, # 4784 +6384,6385,4153,6386,4724,4382,6387,6388,4383,6389,6390,4154,6391,4725,3985,6392, # 4800 +3847,4155,6393,6394,6395,6396,6397,3465,6398,4384,6399,6400,6401,6402,6403,6404, # 4816 +4156,6405,6406,6407,6408,2123,6409,6410,2326,3192,4726,6411,6412,6413,6414,4385, # 4832 +4157,6415,6416,4158,6417,3093,3848,6418,3986,6419,6420,3849,6421,6422,6423,4159, # 4848 +6424,6425,4160,6426,3740,6427,6428,6429,6430,3987,6431,4727,6432,2238,6433,6434, # 4864 +4386,3988,6435,6436,3632,6437,6438,2843,6439,6440,6441,6442,3633,6443,2958,6444, # 4880 +6445,3466,6446,2364,4387,3850,6447,4388,2959,3340,6448,3851,6449,4728,6450,6451, # 4896 +3264,4729,6452,3193,6453,4389,4390,2706,3341,4730,6454,3139,6455,3194,6456,3051, # 4912 +2124,3852,1602,4391,4161,3853,1158,3854,4162,3989,4392,3990,4731,4732,4393,2040, # 4928 +4163,4394,3265,6457,2807,3467,3855,6458,6459,6460,3991,3468,4733,4734,6461,3140, # 4944 +2960,6462,4735,6463,6464,6465,6466,4736,4737,4738,4739,6467,6468,4164,2403,3856, # 4960 +6469,6470,2770,2844,6471,4740,6472,6473,6474,6475,6476,6477,6478,3195,6479,4741, # 4976 +4395,6480,2867,6481,4742,2808,6482,2493,4165,6483,6484,6485,6486,2295,4743,6487, # 4992 +6488,6489,3634,6490,6491,6492,6493,6494,6495,6496,2985,4744,6497,6498,4745,6499, # 5008 +6500,2925,3141,4166,6501,6502,4746,6503,6504,4747,6505,6506,6507,2890,6508,6509, # 5024 +6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,3469,4167,6520,6521,6522,4748, # 5040 +4396,3741,4397,4749,4398,3342,2125,4750,6523,4751,4752,4753,3052,6524,2961,4168, # 5056 +6525,4754,6526,4755,4399,2926,4169,6527,3857,6528,4400,4170,6529,4171,6530,6531, # 5072 +2595,6532,6533,6534,6535,3635,6536,6537,6538,6539,6540,6541,6542,4756,6543,6544, # 5088 +6545,6546,6547,6548,4401,6549,6550,6551,6552,4402,3405,4757,4403,6553,6554,6555, # 5104 +4172,3742,6556,6557,6558,3992,3636,6559,6560,3053,2726,6561,3549,4173,3054,4404, # 5120 +6562,6563,3993,4405,3266,3550,2809,4406,6564,6565,6566,4758,4759,6567,3743,6568, # 5136 +4760,3744,4761,3470,6569,6570,6571,4407,6572,3745,4174,6573,4175,2810,4176,3196, # 5152 +4762,6574,4177,6575,6576,2494,2891,3551,6577,6578,3471,6579,4408,6580,3015,3197, # 5168 +6581,3343,2532,3994,3858,6582,3094,3406,4409,6583,2892,4178,4763,4410,3016,4411, # 5184 +6584,3995,3142,3017,2683,6585,4179,6586,6587,4764,4412,6588,6589,4413,6590,2986, # 5200 +6591,2962,3552,6592,2963,3472,6593,6594,4180,4765,6595,6596,2225,3267,4414,6597, # 5216 +3407,3637,4766,6598,6599,3198,6600,4415,6601,3859,3199,6602,3473,4767,2811,4416, # 5232 +1856,3268,3200,2575,3996,3997,3201,4417,6603,3095,2927,6604,3143,6605,2268,6606, # 5248 +3998,3860,3096,2771,6607,6608,3638,2495,4768,6609,3861,6610,3269,2745,4769,4181, # 5264 +3553,6611,2845,3270,6612,6613,6614,3862,6615,6616,4770,4771,6617,3474,3999,4418, # 5280 +4419,6618,3639,3344,6619,4772,4182,6620,2126,6621,6622,6623,4420,4773,6624,3018, # 5296 +6625,4774,3554,6626,4183,2025,3746,6627,4184,2707,6628,4421,4422,3097,1775,4185, # 5312 +3555,6629,6630,2868,6631,6632,4423,6633,6634,4424,2414,2533,2928,6635,4186,2387, # 5328 +6636,4775,6637,4187,6638,1891,4425,3202,3203,6639,6640,4776,6641,3345,6642,6643, # 5344 +3640,6644,3475,3346,3641,4000,6645,3144,6646,3098,2812,4188,3642,3204,6647,3863, # 5360 +3476,6648,3864,6649,4426,4001,6650,6651,6652,2576,6653,4189,4777,6654,6655,6656, # 5376 +2846,6657,3477,3205,4002,6658,4003,6659,3347,2252,6660,6661,6662,4778,6663,6664, # 5392 +6665,6666,6667,6668,6669,4779,4780,2048,6670,3478,3099,6671,3556,3747,4004,6672, # 5408 +6673,6674,3145,4005,3748,6675,6676,6677,6678,6679,3408,6680,6681,6682,6683,3206, # 5424 +3207,6684,6685,4781,4427,6686,4782,4783,4784,6687,6688,6689,4190,6690,6691,3479, # 5440 +6692,2746,6693,4428,6694,6695,6696,6697,6698,6699,4785,6700,6701,3208,2727,6702, # 5456 +3146,6703,6704,3409,2196,6705,4429,6706,6707,6708,2534,1996,6709,6710,6711,2747, # 5472 +6712,6713,6714,4786,3643,6715,4430,4431,6716,3557,6717,4432,4433,6718,6719,6720, # 5488 +6721,3749,6722,4006,4787,6723,6724,3644,4788,4434,6725,6726,4789,2772,6727,6728, # 5504 +6729,6730,6731,2708,3865,2813,4435,6732,6733,4790,4791,3480,6734,6735,6736,6737, # 5520 +4436,3348,6738,3410,4007,6739,6740,4008,6741,6742,4792,3411,4191,6743,6744,6745, # 5536 +6746,6747,3866,6748,3750,6749,6750,6751,6752,6753,6754,6755,3867,6756,4009,6757, # 5552 +4793,4794,6758,2814,2987,6759,6760,6761,4437,6762,6763,6764,6765,3645,6766,6767, # 5568 +3481,4192,6768,3751,6769,6770,2174,6771,3868,3752,6772,6773,6774,4193,4795,4438, # 5584 +3558,4796,4439,6775,4797,6776,6777,4798,6778,4799,3559,4800,6779,6780,6781,3482, # 5600 +6782,2893,6783,6784,4194,4801,4010,6785,6786,4440,6787,4011,6788,6789,6790,6791, # 5616 +6792,6793,4802,6794,6795,6796,4012,6797,6798,6799,6800,3349,4803,3483,6801,4804, # 5632 +4195,6802,4013,6803,6804,4196,6805,4014,4015,6806,2847,3271,2848,6807,3484,6808, # 5648 +6809,6810,4441,6811,4442,4197,4443,3272,4805,6812,3412,4016,1579,6813,6814,4017, # 5664 +6815,3869,6816,2964,6817,4806,6818,6819,4018,3646,6820,6821,4807,4019,4020,6822, # 5680 +6823,3560,6824,6825,4021,4444,6826,4198,6827,6828,4445,6829,6830,4199,4808,6831, # 5696 +6832,6833,3870,3019,2458,6834,3753,3413,3350,6835,4809,3871,4810,3561,4446,6836, # 5712 +6837,4447,4811,4812,6838,2459,4448,6839,4449,6840,6841,4022,3872,6842,4813,4814, # 5728 +6843,6844,4815,4200,4201,4202,6845,4023,6846,6847,4450,3562,3873,6848,6849,4816, # 5744 +4817,6850,4451,4818,2139,6851,3563,6852,6853,3351,6854,6855,3352,4024,2709,3414, # 5760 +4203,4452,6856,4204,6857,6858,3874,3875,6859,6860,4819,6861,6862,6863,6864,4453, # 5776 +3647,6865,6866,4820,6867,6868,6869,6870,4454,6871,2869,6872,6873,4821,6874,3754, # 5792 +6875,4822,4205,6876,6877,6878,3648,4206,4455,6879,4823,6880,4824,3876,6881,3055, # 5808 +4207,6882,3415,6883,6884,6885,4208,4209,6886,4210,3353,6887,3354,3564,3209,3485, # 5824 +2652,6888,2728,6889,3210,3755,6890,4025,4456,6891,4825,6892,6893,6894,6895,4211, # 5840 +6896,6897,6898,4826,6899,6900,4212,6901,4827,6902,2773,3565,6903,4828,6904,6905, # 5856 +6906,6907,3649,3650,6908,2849,3566,6909,3567,3100,6910,6911,6912,6913,6914,6915, # 5872 +4026,6916,3355,4829,3056,4457,3756,6917,3651,6918,4213,3652,2870,6919,4458,6920, # 5888 +2438,6921,6922,3757,2774,4830,6923,3356,4831,4832,6924,4833,4459,3653,2507,6925, # 5904 +4834,2535,6926,6927,3273,4027,3147,6928,3568,6929,6930,6931,4460,6932,3877,4461, # 5920 +2729,3654,6933,6934,6935,6936,2175,4835,2630,4214,4028,4462,4836,4215,6937,3148, # 5936 +4216,4463,4837,4838,4217,6938,6939,2850,4839,6940,4464,6941,6942,6943,4840,6944, # 5952 +4218,3274,4465,6945,6946,2710,6947,4841,4466,6948,6949,2894,6950,6951,4842,6952, # 5968 +4219,3057,2871,6953,6954,6955,6956,4467,6957,2711,6958,6959,6960,3275,3101,4843, # 5984 +6961,3357,3569,6962,4844,6963,6964,4468,4845,3570,6965,3102,4846,3758,6966,4847, # 6000 +3878,4848,4849,4029,6967,2929,3879,4850,4851,6968,6969,1733,6970,4220,6971,6972, # 6016 +6973,6974,6975,6976,4852,6977,6978,6979,6980,6981,6982,3759,6983,6984,6985,3486, # 6032 +3487,6986,3488,3416,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,4853, # 6048 +6998,6999,4030,7000,7001,3211,7002,7003,4221,7004,7005,3571,4031,7006,3572,7007, # 6064 +2614,4854,2577,7008,7009,2965,3655,3656,4855,2775,3489,3880,4222,4856,3881,4032, # 6080 +3882,3657,2730,3490,4857,7010,3149,7011,4469,4858,2496,3491,4859,2283,7012,7013, # 6096 +7014,2365,4860,4470,7015,7016,3760,7017,7018,4223,1917,7019,7020,7021,4471,7022, # 6112 +2776,4472,7023,7024,7025,7026,4033,7027,3573,4224,4861,4034,4862,7028,7029,1929, # 6128 +3883,4035,7030,4473,3058,7031,2536,3761,3884,7032,4036,7033,2966,2895,1968,4474, # 6144 +3276,4225,3417,3492,4226,2105,7034,7035,1754,2596,3762,4227,4863,4475,3763,4864, # 6160 +3764,2615,2777,3103,3765,3658,3418,4865,2296,3766,2815,7036,7037,7038,3574,2872, # 6176 +3277,4476,7039,4037,4477,7040,7041,4038,7042,7043,7044,7045,7046,7047,2537,7048, # 6192 +7049,7050,7051,7052,7053,7054,4478,7055,7056,3767,3659,4228,3575,7057,7058,4229, # 6208 +7059,7060,7061,3660,7062,3212,7063,3885,4039,2460,7064,7065,7066,7067,7068,7069, # 6224 +7070,7071,7072,7073,7074,4866,3768,4867,7075,7076,7077,7078,4868,3358,3278,2653, # 6240 +7079,7080,4479,3886,7081,7082,4869,7083,7084,7085,7086,7087,7088,2538,7089,7090, # 6256 +7091,4040,3150,3769,4870,4041,2896,3359,4230,2930,7092,3279,7093,2967,4480,3213, # 6272 +4481,3661,7094,7095,7096,7097,7098,7099,7100,7101,7102,2461,3770,7103,7104,4231, # 6288 +3151,7105,7106,7107,4042,3662,7108,7109,4871,3663,4872,4043,3059,7110,7111,7112, # 6304 +3493,2988,7113,4873,7114,7115,7116,3771,4874,7117,7118,4232,4875,7119,3576,2336, # 6320 +4876,7120,4233,3419,4044,4877,4878,4482,4483,4879,4484,4234,7121,3772,4880,1045, # 6336 +3280,3664,4881,4882,7122,7123,7124,7125,4883,7126,2778,7127,4485,4486,7128,4884, # 6352 +3214,3887,7129,7130,3215,7131,4885,4045,7132,7133,4046,7134,7135,7136,7137,7138, # 6368 +7139,7140,7141,7142,7143,4235,7144,4886,7145,7146,7147,4887,7148,7149,7150,4487, # 6384 +4047,4488,7151,7152,4888,4048,2989,3888,7153,3665,7154,4049,7155,7156,7157,7158, # 6400 +7159,7160,2931,4889,4890,4489,7161,2631,3889,4236,2779,7162,7163,4891,7164,3060, # 6416 +7165,1672,4892,7166,4893,4237,3281,4894,7167,7168,3666,7169,3494,7170,7171,4050, # 6432 +7172,7173,3104,3360,3420,4490,4051,2684,4052,7174,4053,7175,7176,7177,2253,4054, # 6448 +7178,7179,4895,7180,3152,3890,3153,4491,3216,7181,7182,7183,2968,4238,4492,4055, # 6464 +7184,2990,7185,2479,7186,7187,4493,7188,7189,7190,7191,7192,4896,7193,4897,2969, # 6480 +4494,4898,7194,3495,7195,7196,4899,4495,7197,3105,2731,7198,4900,7199,7200,7201, # 6496 +4056,7202,3361,7203,7204,4496,4901,4902,7205,4497,7206,7207,2315,4903,7208,4904, # 6512 +7209,4905,2851,7210,7211,3577,7212,3578,4906,7213,4057,3667,4907,7214,4058,2354, # 6528 +3891,2376,3217,3773,7215,7216,7217,7218,7219,4498,7220,4908,3282,2685,7221,3496, # 6544 +4909,2632,3154,4910,7222,2337,7223,4911,7224,7225,7226,4912,4913,3283,4239,4499, # 6560 +7227,2816,7228,7229,7230,7231,7232,7233,7234,4914,4500,4501,7235,7236,7237,2686, # 6576 +7238,4915,7239,2897,4502,7240,4503,7241,2516,7242,4504,3362,3218,7243,7244,7245, # 6592 +4916,7246,7247,4505,3363,7248,7249,7250,7251,3774,4506,7252,7253,4917,7254,7255, # 6608 +3284,2991,4918,4919,3219,3892,4920,3106,3497,4921,7256,7257,7258,4922,7259,4923, # 6624 +3364,4507,4508,4059,7260,4240,3498,7261,7262,4924,7263,2992,3893,4060,3220,7264, # 6640 +7265,7266,7267,7268,7269,4509,3775,7270,2817,7271,4061,4925,4510,3776,7272,4241, # 6656 +4511,3285,7273,7274,3499,7275,7276,7277,4062,4512,4926,7278,3107,3894,7279,7280, # 6672 +4927,7281,4513,7282,7283,3668,7284,7285,4242,4514,4243,7286,2058,4515,4928,4929, # 6688 +4516,7287,3286,4244,7288,4517,7289,7290,7291,3669,7292,7293,4930,4931,4932,2355, # 6704 +4933,7294,2633,4518,7295,4245,7296,7297,4519,7298,7299,4520,4521,4934,7300,4246, # 6720 +4522,7301,7302,7303,3579,7304,4247,4935,7305,4936,7306,7307,7308,7309,3777,7310, # 6736 +4523,7311,7312,7313,4248,3580,7314,4524,3778,4249,7315,3581,7316,3287,7317,3221, # 6752 +7318,4937,7319,7320,7321,7322,7323,7324,4938,4939,7325,4525,7326,7327,7328,4063, # 6768 +7329,7330,4940,7331,7332,4941,7333,4526,7334,3500,2780,1741,4942,2026,1742,7335, # 6784 +7336,3582,4527,2388,7337,7338,7339,4528,7340,4250,4943,7341,7342,7343,4944,7344, # 6800 +7345,7346,3020,7347,4945,7348,7349,7350,7351,3895,7352,3896,4064,3897,7353,7354, # 6816 +7355,4251,7356,7357,3898,7358,3779,7359,3780,3288,7360,7361,4529,7362,4946,4530, # 6832 +2027,7363,3899,4531,4947,3222,3583,7364,4948,7365,7366,7367,7368,4949,3501,4950, # 6848 +3781,4951,4532,7369,2517,4952,4252,4953,3155,7370,4954,4955,4253,2518,4533,7371, # 6864 +7372,2712,4254,7373,7374,7375,3670,4956,3671,7376,2389,3502,4065,7377,2338,7378, # 6880 +7379,7380,7381,3061,7382,4957,7383,7384,7385,7386,4958,4534,7387,7388,2993,7389, # 6896 +3062,7390,4959,7391,7392,7393,4960,3108,4961,7394,4535,7395,4962,3421,4536,7396, # 6912 +4963,7397,4964,1857,7398,4965,7399,7400,2176,3584,4966,7401,7402,3422,4537,3900, # 6928 +3585,7403,3782,7404,2852,7405,7406,7407,4538,3783,2654,3423,4967,4539,7408,3784, # 6944 +3586,2853,4540,4541,7409,3901,7410,3902,7411,7412,3785,3109,2327,3903,7413,7414, # 6960 +2970,4066,2932,7415,7416,7417,3904,3672,3424,7418,4542,4543,4544,7419,4968,7420, # 6976 +7421,4255,7422,7423,7424,7425,7426,4067,7427,3673,3365,4545,7428,3110,2559,3674, # 6992 +7429,7430,3156,7431,7432,3503,7433,3425,4546,7434,3063,2873,7435,3223,4969,4547, # 7008 +4548,2898,4256,4068,7436,4069,3587,3786,2933,3787,4257,4970,4971,3788,7437,4972, # 7024 +3064,7438,4549,7439,7440,7441,7442,7443,4973,3905,7444,2874,7445,7446,7447,7448, # 7040 +3021,7449,4550,3906,3588,4974,7450,7451,3789,3675,7452,2578,7453,4070,7454,7455, # 7056 +7456,4258,3676,7457,4975,7458,4976,4259,3790,3504,2634,4977,3677,4551,4260,7459, # 7072 +7460,7461,7462,3907,4261,4978,7463,7464,7465,7466,4979,4980,7467,7468,2213,4262, # 7088 +7469,7470,7471,3678,4981,7472,2439,7473,4263,3224,3289,7474,3908,2415,4982,7475, # 7104 +4264,7476,4983,2655,7477,7478,2732,4552,2854,2875,7479,7480,4265,7481,4553,4984, # 7120 +7482,7483,4266,7484,3679,3366,3680,2818,2781,2782,3367,3589,4554,3065,7485,4071, # 7136 +2899,7486,7487,3157,2462,4072,4555,4073,4985,4986,3111,4267,2687,3368,4556,4074, # 7152 +3791,4268,7488,3909,2783,7489,2656,1962,3158,4557,4987,1963,3159,3160,7490,3112, # 7168 +4988,4989,3022,4990,4991,3792,2855,7491,7492,2971,4558,7493,7494,4992,7495,7496, # 7184 +7497,7498,4993,7499,3426,4559,4994,7500,3681,4560,4269,4270,3910,7501,4075,4995, # 7200 +4271,7502,7503,4076,7504,4996,7505,3225,4997,4272,4077,2819,3023,7506,7507,2733, # 7216 +4561,7508,4562,7509,3369,3793,7510,3590,2508,7511,7512,4273,3113,2994,2616,7513, # 7232 +7514,7515,7516,7517,7518,2820,3911,4078,2748,7519,7520,4563,4998,7521,7522,7523, # 7248 +7524,4999,4274,7525,4564,3682,2239,4079,4565,7526,7527,7528,7529,5000,7530,7531, # 7264 +5001,4275,3794,7532,7533,7534,3066,5002,4566,3161,7535,7536,4080,7537,3162,7538, # 7280 +7539,4567,7540,7541,7542,7543,7544,7545,5003,7546,4568,7547,7548,7549,7550,7551, # 7296 +7552,7553,7554,7555,7556,5004,7557,7558,7559,5005,7560,3795,7561,4569,7562,7563, # 7312 +7564,2821,3796,4276,4277,4081,7565,2876,7566,5006,7567,7568,2900,7569,3797,3912, # 7328 +7570,7571,7572,4278,7573,7574,7575,5007,7576,7577,5008,7578,7579,4279,2934,7580, # 7344 +7581,5009,7582,4570,7583,4280,7584,7585,7586,4571,4572,3913,7587,4573,3505,7588, # 7360 +5010,7589,7590,7591,7592,3798,4574,7593,7594,5011,7595,4281,7596,7597,7598,4282, # 7376 +5012,7599,7600,5013,3163,7601,5014,7602,3914,7603,7604,2734,4575,4576,4577,7605, # 7392 +7606,7607,7608,7609,3506,5015,4578,7610,4082,7611,2822,2901,2579,3683,3024,4579, # 7408 +3507,7612,4580,7613,3226,3799,5016,7614,7615,7616,7617,7618,7619,7620,2995,3290, # 7424 +7621,4083,7622,5017,7623,7624,7625,7626,7627,4581,3915,7628,3291,7629,5018,7630, # 7440 +7631,7632,7633,4084,7634,7635,3427,3800,7636,7637,4582,7638,5019,4583,5020,7639, # 7456 +3916,7640,3801,5021,4584,4283,7641,7642,3428,3591,2269,7643,2617,7644,4585,3592, # 7472 +7645,4586,2902,7646,7647,3227,5022,7648,4587,7649,4284,7650,7651,7652,4588,2284, # 7488 +7653,5023,7654,7655,7656,4589,5024,3802,7657,7658,5025,3508,4590,7659,7660,7661, # 7504 +1969,5026,7662,7663,3684,1821,2688,7664,2028,2509,4285,7665,2823,1841,7666,2689, # 7520 +3114,7667,3917,4085,2160,5027,5028,2972,7668,5029,7669,7670,7671,3593,4086,7672, # 7536 +4591,4087,5030,3803,7673,7674,7675,7676,7677,7678,7679,4286,2366,4592,4593,3067, # 7552 +2328,7680,7681,4594,3594,3918,2029,4287,7682,5031,3919,3370,4288,4595,2856,7683, # 7568 +3509,7684,7685,5032,5033,7686,7687,3804,2784,7688,7689,7690,7691,3371,7692,7693, # 7584 +2877,5034,7694,7695,3920,4289,4088,7696,7697,7698,5035,7699,5036,4290,5037,5038, # 7600 +5039,7700,7701,7702,5040,5041,3228,7703,1760,7704,5042,3229,4596,2106,4089,7705, # 7616 +4597,2824,5043,2107,3372,7706,4291,4090,5044,7707,4091,7708,5045,3025,3805,4598, # 7632 +4292,4293,4294,3373,7709,4599,7710,5046,7711,7712,5047,5048,3806,7713,7714,7715, # 7648 +5049,7716,7717,7718,7719,4600,5050,7720,7721,7722,5051,7723,4295,3429,7724,7725, # 7664 +7726,7727,3921,7728,3292,5052,4092,7729,7730,7731,7732,7733,7734,7735,5053,5054, # 7680 +7736,7737,7738,7739,3922,3685,7740,7741,7742,7743,2635,5055,7744,5056,4601,7745, # 7696 +7746,2560,7747,7748,7749,7750,3923,7751,7752,7753,7754,7755,4296,2903,7756,7757, # 7712 +7758,7759,7760,3924,7761,5057,4297,7762,7763,5058,4298,7764,4093,7765,7766,5059, # 7728 +3925,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,3595,7777,4299,5060,4094, # 7744 +7778,3293,5061,7779,7780,4300,7781,7782,4602,7783,3596,7784,7785,3430,2367,7786, # 7760 +3164,5062,5063,4301,7787,7788,4095,5064,5065,7789,3374,3115,7790,7791,7792,7793, # 7776 +7794,7795,7796,3597,4603,7797,7798,3686,3116,3807,5066,7799,7800,5067,7801,7802, # 7792 +4604,4302,5068,4303,4096,7803,7804,3294,7805,7806,5069,4605,2690,7807,3026,7808, # 7808 +7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824, # 7824 +7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7840 +7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856, # 7856 +7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872, # 7872 +7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888, # 7888 +7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904, # 7904 +7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920, # 7920 +7921,7922,7923,7924,3926,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, # 7936 +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, # 7952 +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, # 7968 +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, # 7984 +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, # 8000 +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, # 8016 +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, # 8032 +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, # 8048 +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, # 8064 +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, # 8080 +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, # 8096 +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, # 8112 +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, # 8128 +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, # 8144 +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, # 8160 +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, # 8176 +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, # 8192 +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, # 8208 +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, # 8224 +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, # 8240 +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, # 8256 +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271) # 8272 + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/jpcntx.py b/pipenv/vendor/requests/packages/chardet/jpcntx.py new file mode 100644 index 00000000..59aeb6a8 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/jpcntx.py @@ -0,0 +1,227 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .compat import wrap_ord + +NUM_OF_CATEGORY = 6 +DONT_KNOW = -1 +ENOUGH_REL_THRESHOLD = 100 +MAX_REL_THRESHOLD = 1000 +MINIMUM_DATA_THRESHOLD = 4 + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis: + def __init__(self): + self.reset() + + def reset(self): + self._mTotalRel = 0 # total sequence received + # category counters, each interger counts sequence in its category + self._mRelSample = [0] * NUM_OF_CATEGORY + # if last byte in current buffer is not the last byte of a character, + # we need to know how many bytes to skip in next buffer + self._mNeedToSkipCharNum = 0 + self._mLastCharOrder = -1 # The order of previous char + # If this flag is set to True, detection is done and conclusion has + # been made + self._mDone = False + + def feed(self, aBuf, aLen): + if self._mDone: + return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not + # complete, we record how many byte needed to complete that character + # and skip these bytes here. We can choose to record those bytes as + # well and analyse the character once it is complete, but since a + # character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._mNeedToSkipCharNum + while i < aLen: + order, charLen = self.get_order(aBuf[i:i + 2]) + i += charLen + if i > aLen: + self._mNeedToSkipCharNum = i - aLen + self._mLastCharOrder = -1 + else: + if (order != -1) and (self._mLastCharOrder != -1): + self._mTotalRel += 1 + if self._mTotalRel > MAX_REL_THRESHOLD: + self._mDone = True + break + self._mRelSample[jp2CharContext[self._mLastCharOrder][order]] += 1 + self._mLastCharOrder = order + + def got_enough_data(self): + return self._mTotalRel > ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._mTotalRel > MINIMUM_DATA_THRESHOLD: + return (self._mTotalRel - self._mRelSample[0]) / self._mTotalRel + else: + return DONT_KNOW + + def get_order(self, aBuf): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def __init__(self): + self.charset_name = "SHIFT_JIS" + + def get_charset_name(self): + return self.charset_name + + def get_order(self, aBuf): + if not aBuf: + return -1, 1 + # find out current char's byte length + first_char = wrap_ord(aBuf[0]) + if ((0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC)): + charLen = 2 + if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): + self.charset_name = "CP932" + else: + charLen = 1 + + # return its order if it is hiragana + if len(aBuf) > 1: + second_char = wrap_ord(aBuf[1]) + if (first_char == 202) and (0x9F <= second_char <= 0xF1): + return second_char - 0x9F, charLen + + return -1, charLen + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, aBuf): + if not aBuf: + return -1, 1 + # find out current char's byte length + first_char = wrap_ord(aBuf[0]) + if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): + charLen = 2 + elif first_char == 0x8F: + charLen = 3 + else: + charLen = 1 + + # return its order if it is hiragana + if len(aBuf) > 1: + second_char = wrap_ord(aBuf[1]) + if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): + return second_char - 0xA1, charLen + + return -1, charLen + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langbulgarianmodel.py b/pipenv/vendor/requests/packages/chardet/langbulgarianmodel.py new file mode 100644 index 00000000..e5788fc6 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langbulgarianmodel.py @@ -0,0 +1,229 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,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,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { + 'charToOrderMap': Latin5_BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-5" +} + +Win1251BulgarianModel = { + 'charToOrderMap': win1251BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': False, + 'charsetName': "windows-1251" +} + + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langcyrillicmodel.py b/pipenv/vendor/requests/packages/chardet/langcyrillicmodel.py new file mode 100644 index 00000000..a86f54bd --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langcyrillicmodel.py @@ -0,0 +1,329 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# KOI8-R language model +# Character Mapping Table: +KOI8R_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,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,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { + 'charToOrderMap': KOI8R_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "KOI8-R" +} + +Win1251CyrillicModel = { + 'charToOrderMap': win1251_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "windows-1251" +} + +Latin5CyrillicModel = { + 'charToOrderMap': latin5_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-5" +} + +MacCyrillicModel = { + 'charToOrderMap': macCyrillic_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "MacCyrillic" +}; + +Ibm866Model = { + 'charToOrderMap': IBM866_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "IBM866" +} + +Ibm855Model = { + 'charToOrderMap': IBM855_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "IBM855" +} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langgreekmodel.py b/pipenv/vendor/requests/packages/chardet/langgreekmodel.py new file mode 100644 index 00000000..ddb58376 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { + 'charToOrderMap': Latin7_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-7" +} + +Win1253GreekModel = { + 'charToOrderMap': win1253_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': False, + 'charsetName': "windows-1253" +} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langhebrewmodel.py b/pipenv/vendor/requests/packages/chardet/langhebrewmodel.py new file mode 100644 index 00000000..75f2bc7f --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langhebrewmodel.py @@ -0,0 +1,201 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +win1255_CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HebrewLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +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,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +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,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +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,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +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,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +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,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +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,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { + 'charToOrderMap': win1255_CharToOrderMap, + 'precedenceMatrix': HebrewLangModel, + 'mTypicalPositiveRatio': 0.984004, + 'keepEnglishLetter': False, + 'charsetName': "windows-1255" +} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langhungarianmodel.py b/pipenv/vendor/requests/packages/chardet/langhungarianmodel.py new file mode 100644 index 00000000..49d2f0fe --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,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,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { + 'charToOrderMap': Latin2_HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': True, + 'charsetName': "ISO-8859-2" +} + +Win1250HungarianModel = { + 'charToOrderMap': win1250HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': True, + 'charsetName': "windows-1250" +} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/langthaimodel.py b/pipenv/vendor/requests/packages/chardet/langthaimodel.py new file mode 100644 index 00000000..0508b1b1 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/langthaimodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { + 'charToOrderMap': TIS620CharToOrderMap, + 'precedenceMatrix': ThaiLangModel, + 'mTypicalPositiveRatio': 0.926386, + 'keepEnglishLetter': False, + 'charsetName': "TIS-620" +} + +# flake8: noqa diff --git a/pipenv/vendor/requests/packages/chardet/latin1prober.py b/pipenv/vendor/requests/packages/chardet/latin1prober.py new file mode 100644 index 00000000..eef35735 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/latin1prober.py @@ -0,0 +1,139 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .constants import eNotMe +from .compat import wrap_ord + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( + # UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + + +class Latin1Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self.reset() + + def reset(self): + self._mLastCharClass = OTH + self._mFreqCounter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + def get_charset_name(self): + return "windows-1252" + + def feed(self, aBuf): + aBuf = self.filter_with_english_letters(aBuf) + for c in aBuf: + charClass = Latin1_CharToClass[wrap_ord(c)] + freq = Latin1ClassModel[(self._mLastCharClass * CLASS_NUM) + + charClass] + if freq == 0: + self._mState = eNotMe + break + self._mFreqCounter[freq] += 1 + self._mLastCharClass = charClass + + return self.get_state() + + def get_confidence(self): + if self.get_state() == eNotMe: + return 0.01 + + total = sum(self._mFreqCounter) + if total < 0.01: + confidence = 0.0 + else: + confidence = ((self._mFreqCounter[3] - self._mFreqCounter[1] * 20.0) + / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate + # detector can take priority. + confidence = confidence * 0.73 + return confidence diff --git a/pipenv/vendor/requests/packages/chardet/mbcharsetprober.py b/pipenv/vendor/requests/packages/chardet/mbcharsetprober.py new file mode 100644 index 00000000..bb42f2fb --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/mbcharsetprober.py @@ -0,0 +1,86 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys +from . import constants +from .charsetprober import CharSetProber + + +class MultiByteCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mDistributionAnalyzer = None + self._mCodingSM = None + self._mLastChar = [0, 0] + + def reset(self): + CharSetProber.reset(self) + if self._mCodingSM: + self._mCodingSM.reset() + if self._mDistributionAnalyzer: + self._mDistributionAnalyzer.reset() + self._mLastChar = [0, 0] + + def get_charset_name(self): + pass + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == constants.eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + + ' prober hit error at byte ' + str(i) + + '\n') + self._mState = constants.eNotMe + break + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == constants.eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mDistributionAnalyzer.feed(aBuf[i - 1:i + 1], + charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if (self._mDistributionAnalyzer.got_enough_data() and + (self.get_confidence() > constants.SHORTCUT_THRESHOLD)): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + return self._mDistributionAnalyzer.get_confidence() diff --git a/pipenv/vendor/requests/packages/chardet/mbcsgroupprober.py b/pipenv/vendor/requests/packages/chardet/mbcsgroupprober.py new file mode 100644 index 00000000..03c9dcf3 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/mbcsgroupprober.py @@ -0,0 +1,54 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .utf8prober import UTF8Prober +from .sjisprober import SJISProber +from .eucjpprober import EUCJPProber +from .gb2312prober import GB2312Prober +from .euckrprober import EUCKRProber +from .cp949prober import CP949Prober +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + CP949Prober(), + Big5Prober(), + EUCTWProber() + ] + self.reset() diff --git a/pipenv/vendor/requests/packages/chardet/mbcssm.py b/pipenv/vendor/requests/packages/chardet/mbcssm.py new file mode 100644 index 00000000..efe678ca --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart, eError, eItsMe + +# BIG5 + +BIG5_cls = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +BIG5_st = ( + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,#08-0f + eError,eStart,eStart,eStart,eStart,eStart,eStart,eStart#10-17 +) + +Big5CharLenTable = (0, 1, 1, 2, 0) + +Big5SMModel = {'classTable': BIG5_cls, + 'classFactor': 5, + 'stateTable': BIG5_st, + 'charLenTable': Big5CharLenTable, + 'name': 'Big5'} + +# CP949 + +CP949_cls = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_st = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + eError,eStart, 3,eError,eStart,eStart, 4, 5,eError, 6, # eStart + eError,eError,eError,eError,eError,eError,eError,eError,eError,eError, # eError + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe, # eItsMe + eError,eError,eStart,eStart,eError,eError,eError,eStart,eStart,eStart, # 3 + eError,eError,eStart,eStart,eStart,eStart,eStart,eStart,eStart,eStart, # 4 + eError,eStart,eStart,eStart,eStart,eStart,eStart,eStart,eStart,eStart, # 5 + eError,eStart,eStart,eStart,eStart,eError,eError,eStart,eStart,eStart, # 6 +) + +CP949CharLenTable = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949SMModel = {'classTable': CP949_cls, + 'classFactor': 10, + 'stateTable': CP949_st, + 'charLenTable': CP949CharLenTable, + 'name': 'CP949'} + +# EUC-JP + +EUCJP_cls = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5 # f8 - ff +) + +EUCJP_st = ( + 3, 4, 3, 5,eStart,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eStart,eError,eStart,eError,eError,eError,#10-17 + eError,eError,eStart,eError,eError,eError, 3,eError,#18-1f + 3,eError,eError,eError,eStart,eStart,eStart,eStart#20-27 +) + +EUCJPCharLenTable = (2, 2, 2, 3, 1, 0) + +EUCJPSMModel = {'classTable': EUCJP_cls, + 'classFactor': 6, + 'stateTable': EUCJP_st, + 'charLenTable': EUCJPCharLenTable, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_cls = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0 # f8 - ff +) + +EUCKR_st = ( + eError,eStart, 3,eError,eError,eError,eError,eError,#00-07 + eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,eStart #08-0f +) + +EUCKRCharLenTable = (0, 1, 2, 0) + +EUCKRSMModel = {'classTable': EUCKR_cls, + 'classFactor': 4, + 'stateTable': EUCKR_st, + 'charLenTable': EUCKRCharLenTable, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_cls = ( + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +EUCTW_st = ( + eError,eError,eStart, 3, 3, 3, 4,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eStart,eError,#10-17 + eStart,eStart,eStart,eError,eError,eError,eError,eError,#18-1f + 5,eError,eError,eError,eStart,eError,eStart,eStart,#20-27 + eStart,eError,eStart,eStart,eStart,eStart,eStart,eStart #28-2f +) + +EUCTWCharLenTable = (0, 0, 1, 2, 2, 2, 3) + +EUCTWSMModel = {'classTable': EUCTW_cls, + 'classFactor': 7, + 'stateTable': EUCTW_st, + 'charLenTable': EUCTWCharLenTable, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_cls = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0 # f8 - ff +) + +GB2312_st = ( + eError,eStart,eStart,eStart,eStart,eStart, 3,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,#10-17 + 4,eError,eStart,eStart,eError,eError,eError,eError,#18-1f + eError,eError, 5,eError,eError,eError,eItsMe,eError,#20-27 + eError,eError,eStart,eStart,eStart,eStart,eStart,eStart #28-2f +) + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validing +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312CharLenTable = (0, 1, 1, 1, 1, 1, 2) + +GB2312SMModel = {'classTable': GB2312_cls, + 'classFactor': 7, + 'stateTable': GB2312_st, + 'charLenTable': GB2312CharLenTable, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_cls = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,2,2,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_st = ( + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eError,eError,eStart,eStart,eStart,eStart #10-17 +) + +SJISCharLenTable = (0, 1, 1, 2, 0, 0) + +SJISSMModel = {'classTable': SJIS_cls, + 'classFactor': 6, + 'stateTable': SJIS_st, + 'charLenTable': SJISCharLenTable, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_cls = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2BE_st = ( + 5, 7, 7,eError, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 6, 6, 6, 6,eError,eError,#10-17 + 6, 6, 6, 6, 6,eItsMe, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,eError,#20-27 + 5, 8, 6, 6,eError, 6, 6, 6,#28-2f + 6, 6, 6, 6,eError,eError,eStart,eStart #30-37 +) + +UCS2BECharLenTable = (2, 2, 2, 0, 2, 2) + +UCS2BESMModel = {'classTable': UCS2BE_cls, + 'classFactor': 6, + 'stateTable': UCS2BE_st, + 'charLenTable': UCS2BECharLenTable, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_cls = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2LE_st = ( + 6, 6, 7, 6, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 5, 5, 5,eError,eItsMe,eError,#10-17 + 5, 5, 5,eError, 5,eError, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,eError,#20-27 + 5, 5, 5,eError,eError,eError, 5, 5,#28-2f + 5, 5, 5,eError, 5,eError,eStart,eStart #30-37 +) + +UCS2LECharLenTable = (2, 2, 2, 2, 2, 2) + +UCS2LESMModel = {'classTable': UCS2LE_cls, + 'classFactor': 6, + 'stateTable': UCS2LE_st, + 'charLenTable': UCS2LECharLenTable, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_cls = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0 # f8 - ff +) + +UTF8_st = ( + eError,eStart,eError,eError,eError,eError, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + eError,eError,eError,eError,eError,eError,eError,eError,#10-17 + eError,eError,eError,eError,eError,eError,eError,eError,#18-1f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#20-27 + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#28-2f + eError,eError, 5, 5, 5, 5,eError,eError,#30-37 + eError,eError,eError,eError,eError,eError,eError,eError,#38-3f + eError,eError,eError, 5, 5, 5,eError,eError,#40-47 + eError,eError,eError,eError,eError,eError,eError,eError,#48-4f + eError,eError, 7, 7, 7, 7,eError,eError,#50-57 + eError,eError,eError,eError,eError,eError,eError,eError,#58-5f + eError,eError,eError,eError, 7, 7,eError,eError,#60-67 + eError,eError,eError,eError,eError,eError,eError,eError,#68-6f + eError,eError, 9, 9, 9, 9,eError,eError,#70-77 + eError,eError,eError,eError,eError,eError,eError,eError,#78-7f + eError,eError,eError,eError,eError, 9,eError,eError,#80-87 + eError,eError,eError,eError,eError,eError,eError,eError,#88-8f + eError,eError, 12, 12, 12, 12,eError,eError,#90-97 + eError,eError,eError,eError,eError,eError,eError,eError,#98-9f + eError,eError,eError,eError,eError, 12,eError,eError,#a0-a7 + eError,eError,eError,eError,eError,eError,eError,eError,#a8-af + eError,eError, 12, 12, 12,eError,eError,eError,#b0-b7 + eError,eError,eError,eError,eError,eError,eError,eError,#b8-bf + eError,eError,eStart,eStart,eStart,eStart,eError,eError,#c0-c7 + eError,eError,eError,eError,eError,eError,eError,eError #c8-cf +) + +UTF8CharLenTable = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8SMModel = {'classTable': UTF8_cls, + 'classFactor': 16, + 'stateTable': UTF8_st, + 'charLenTable': UTF8CharLenTable, + 'name': 'UTF-8'} diff --git a/pipenv/vendor/requests/packages/chardet/sbcharsetprober.py b/pipenv/vendor/requests/packages/chardet/sbcharsetprober.py new file mode 100644 index 00000000..37291bd2 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/sbcharsetprober.py @@ -0,0 +1,120 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys +from . import constants +from .charsetprober import CharSetProber +from .compat import wrap_ord + +SAMPLE_SIZE = 64 +SB_ENOUGH_REL_THRESHOLD = 1024 +POSITIVE_SHORTCUT_THRESHOLD = 0.95 +NEGATIVE_SHORTCUT_THRESHOLD = 0.05 +SYMBOL_CAT_ORDER = 250 +NUMBER_OF_SEQ_CAT = 4 +POSITIVE_CAT = NUMBER_OF_SEQ_CAT - 1 +#NEGATIVE_CAT = 0 + + +class SingleByteCharSetProber(CharSetProber): + def __init__(self, model, reversed=False, nameProber=None): + CharSetProber.__init__(self) + self._mModel = model + # TRUE if we need to reverse every pair in the model lookup + self._mReversed = reversed + # Optional auxiliary prober for name decision + self._mNameProber = nameProber + self.reset() + + def reset(self): + CharSetProber.reset(self) + # char order of last character + self._mLastOrder = 255 + self._mSeqCounters = [0] * NUMBER_OF_SEQ_CAT + self._mTotalSeqs = 0 + self._mTotalChar = 0 + # characters that fall in our sampling range + self._mFreqChar = 0 + + def get_charset_name(self): + if self._mNameProber: + return self._mNameProber.get_charset_name() + else: + return self._mModel['charsetName'] + + def feed(self, aBuf): + if not self._mModel['keepEnglishLetter']: + aBuf = self.filter_without_english_letters(aBuf) + aLen = len(aBuf) + if not aLen: + return self.get_state() + for c in aBuf: + order = self._mModel['charToOrderMap'][wrap_ord(c)] + if order < SYMBOL_CAT_ORDER: + self._mTotalChar += 1 + if order < SAMPLE_SIZE: + self._mFreqChar += 1 + if self._mLastOrder < SAMPLE_SIZE: + self._mTotalSeqs += 1 + if not self._mReversed: + i = (self._mLastOrder * SAMPLE_SIZE) + order + model = self._mModel['precedenceMatrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * SAMPLE_SIZE) + self._mLastOrder + model = self._mModel['precedenceMatrix'][i] + self._mSeqCounters[model] += 1 + self._mLastOrder = order + + if self.get_state() == constants.eDetecting: + if self._mTotalSeqs > SB_ENOUGH_REL_THRESHOLD: + cf = self.get_confidence() + if cf > POSITIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, we have a' + 'winner\n' % + (self._mModel['charsetName'], cf)) + self._mState = constants.eFoundIt + elif cf < NEGATIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, below negative' + 'shortcut threshhold %s\n' % + (self._mModel['charsetName'], cf, + NEGATIVE_SHORTCUT_THRESHOLD)) + self._mState = constants.eNotMe + + return self.get_state() + + def get_confidence(self): + r = 0.01 + if self._mTotalSeqs > 0: + r = ((1.0 * self._mSeqCounters[POSITIVE_CAT]) / self._mTotalSeqs + / self._mModel['mTypicalPositiveRatio']) + r = r * self._mFreqChar / self._mTotalChar + if r >= 1.0: + r = 0.99 + return r diff --git a/pipenv/vendor/requests/packages/chardet/sbcsgroupprober.py b/pipenv/vendor/requests/packages/chardet/sbcsgroupprober.py new file mode 100644 index 00000000..1b6196cd --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/sbcsgroupprober.py @@ -0,0 +1,69 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, + Latin5CyrillicModel, MacCyrillicModel, + Ibm866Model, Ibm855Model) +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + SingleByteCharSetProber(Latin2HungarianModel), + SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + ] + hebrewProber = HebrewProber() + logicalHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrewProber) + visualHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrewProber) + hebrewProber.set_model_probers(logicalHebrewProber, visualHebrewProber) + self._mProbers.extend([hebrewProber, logicalHebrewProber, + visualHebrewProber]) + + self.reset() diff --git a/pipenv/vendor/requests/packages/chardet/sjisprober.py b/pipenv/vendor/requests/packages/chardet/sjisprober.py new file mode 100644 index 00000000..cd0e9e70 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/sjisprober.py @@ -0,0 +1,91 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJISSMModel +from . import constants + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(SJISSMModel) + self._mDistributionAnalyzer = SJISDistributionAnalysis() + self._mContextAnalyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return self._mContextAnalyzer.get_charset_name() + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == constants.eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + + ' prober hit error at byte ' + str(i) + + '\n') + self._mState = constants.eNotMe + break + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == constants.eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar[2 - charLen:], + charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i + 1 - charLen:i + 3 + - charLen], charLen) + self._mDistributionAnalyzer.feed(aBuf[i - 1:i + 1], + charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if (self._mContextAnalyzer.got_enough_data() and + (self.get_confidence() > constants.SHORTCUT_THRESHOLD)): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/pipenv/vendor/requests/packages/chardet/universaldetector.py b/pipenv/vendor/requests/packages/chardet/universaldetector.py new file mode 100644 index 00000000..476522b9 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/universaldetector.py @@ -0,0 +1,170 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +import codecs +from .latin1prober import Latin1Prober # windows-1252 +from .mbcsgroupprober import MBCSGroupProber # multi-byte character sets +from .sbcsgroupprober import SBCSGroupProber # single-byte character sets +from .escprober import EscCharSetProber # ISO-2122, etc. +import re + +MINIMUM_THRESHOLD = 0.20 +ePureAscii = 0 +eEscAscii = 1 +eHighbyte = 2 + + +class UniversalDetector: + def __init__(self): + self._highBitDetector = re.compile(b'[\x80-\xFF]') + self._escDetector = re.compile(b'(\033|~{)') + self._mEscCharSetProber = None + self._mCharSetProbers = [] + self.reset() + + def reset(self): + self.result = {'encoding': None, 'confidence': 0.0} + self.done = False + self._mStart = True + self._mGotData = False + self._mInputState = ePureAscii + self._mLastChar = b'' + if self._mEscCharSetProber: + self._mEscCharSetProber.reset() + for prober in self._mCharSetProbers: + prober.reset() + + def feed(self, aBuf): + if self.done: + return + + aLen = len(aBuf) + if not aLen: + return + + if not self._mGotData: + # If the data starts with BOM, we know it is UTF + if aBuf[:3] == codecs.BOM_UTF8: + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", 'confidence': 1.0} + elif aBuf[:4] == codecs.BOM_UTF32_LE: + # FF FE 00 00 UTF-32, little-endian BOM + self.result = {'encoding': "UTF-32LE", 'confidence': 1.0} + elif aBuf[:4] == codecs.BOM_UTF32_BE: + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32BE", 'confidence': 1.0} + elif aBuf[:4] == b'\xFE\xFF\x00\x00': + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = { + 'encoding': "X-ISO-10646-UCS-4-3412", + 'confidence': 1.0 + } + elif aBuf[:4] == b'\x00\x00\xFF\xFE': + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = { + 'encoding': "X-ISO-10646-UCS-4-2143", + 'confidence': 1.0 + } + elif aBuf[:2] == codecs.BOM_LE: + # FF FE UTF-16, little endian BOM + self.result = {'encoding': "UTF-16LE", 'confidence': 1.0} + elif aBuf[:2] == codecs.BOM_BE: + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16BE", 'confidence': 1.0} + + self._mGotData = True + if self.result['encoding'] and (self.result['confidence'] > 0.0): + self.done = True + return + + if self._mInputState == ePureAscii: + if self._highBitDetector.search(aBuf): + self._mInputState = eHighbyte + elif ((self._mInputState == ePureAscii) and + self._escDetector.search(self._mLastChar + aBuf)): + self._mInputState = eEscAscii + + self._mLastChar = aBuf[-1:] + + if self._mInputState == eEscAscii: + if not self._mEscCharSetProber: + self._mEscCharSetProber = EscCharSetProber() + if self._mEscCharSetProber.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': self._mEscCharSetProber.get_charset_name(), + 'confidence': self._mEscCharSetProber.get_confidence()} + self.done = True + elif self._mInputState == eHighbyte: + if not self._mCharSetProbers: + self._mCharSetProbers = [MBCSGroupProber(), SBCSGroupProber(), + Latin1Prober()] + for prober in self._mCharSetProbers: + if prober.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': prober.get_charset_name(), + 'confidence': prober.get_confidence()} + self.done = True + break + + def close(self): + if self.done: + return + if not self._mGotData: + if constants._debug: + sys.stderr.write('no data received!\n') + return + self.done = True + + if self._mInputState == ePureAscii: + self.result = {'encoding': 'ascii', 'confidence': 1.0} + return self.result + + if self._mInputState == eHighbyte: + proberConfidence = None + maxProberConfidence = 0.0 + maxProber = None + for prober in self._mCharSetProbers: + if not prober: + continue + proberConfidence = prober.get_confidence() + if proberConfidence > maxProberConfidence: + maxProberConfidence = proberConfidence + maxProber = prober + if maxProber and (maxProberConfidence > MINIMUM_THRESHOLD): + self.result = {'encoding': maxProber.get_charset_name(), + 'confidence': maxProber.get_confidence()} + return self.result + + if constants._debug: + sys.stderr.write('no probers hit minimum threshhold\n') + for prober in self._mCharSetProbers[0].mProbers: + if not prober: + continue + sys.stderr.write('%s confidence = %s\n' % + (prober.get_charset_name(), + prober.get_confidence())) diff --git a/pipenv/vendor/requests/packages/chardet/utf8prober.py b/pipenv/vendor/requests/packages/chardet/utf8prober.py new file mode 100644 index 00000000..1c0bb5d8 --- /dev/null +++ b/pipenv/vendor/requests/packages/chardet/utf8prober.py @@ -0,0 +1,76 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8SMModel + +ONE_CHAR_PROB = 0.5 + + +class UTF8Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(UTF8SMModel) + self.reset() + + def reset(self): + CharSetProber.reset(self) + self._mCodingSM.reset() + self._mNumOfMBChar = 0 + + def get_charset_name(self): + return "utf-8" + + def feed(self, aBuf): + for c in aBuf: + codingState = self._mCodingSM.next_state(c) + if codingState == constants.eError: + self._mState = constants.eNotMe + break + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == constants.eStart: + if self._mCodingSM.get_current_charlen() >= 2: + self._mNumOfMBChar += 1 + + if self.get_state() == constants.eDetecting: + if self.get_confidence() > constants.SHORTCUT_THRESHOLD: + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + unlike = 0.99 + if self._mNumOfMBChar < 6: + for i in range(0, self._mNumOfMBChar): + unlike = unlike * ONE_CHAR_PROB + return 1.0 - unlike + else: + return unlike diff --git a/pipenv/vendor/requests/packages/idna/__init__.py b/pipenv/vendor/requests/packages/idna/__init__.py new file mode 100644 index 00000000..bb67a43f --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/__init__.py @@ -0,0 +1 @@ +from .core import * diff --git a/pipenv/vendor/requests/packages/idna/codec.py b/pipenv/vendor/requests/packages/idna/codec.py new file mode 100644 index 00000000..98c65ead --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/codec.py @@ -0,0 +1,118 @@ +from .core import encode, decode, alabel, ulabel, IDNAError +import codecs +import re + +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +class Codec(codecs.Codec): + + def encode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return "", 0 + + return encode(data), len(data) + + def decode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return u"", 0 + + return decode(data), len(data) + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return ("", 0) + + labels = _unicode_dots_re.split(data) + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = '.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = '.' + + result = [] + size = 0 + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + # Join with U+002E + result = ".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return (u"", 0) + + # IDNA allows decoding to operate on Unicode strings, too. + if isinstance(data, unicode): + labels = _unicode_dots_re.split(data) + else: + # Must be ASCII string + data = str(data) + unicode(data, "ascii") + labels = data.split(".") + + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = u'.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = u'.' + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result = u".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + +class StreamReader(Codec, codecs.StreamReader): + pass + +def getregentry(): + return codecs.CodecInfo( + name='idna', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) diff --git a/pipenv/vendor/requests/packages/idna/compat.py b/pipenv/vendor/requests/packages/idna/compat.py new file mode 100644 index 00000000..4d47f336 --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/compat.py @@ -0,0 +1,12 @@ +from .core import * +from .codec import * + +def ToASCII(label): + return encode(label) + +def ToUnicode(label): + return decode(label) + +def nameprep(s): + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") + diff --git a/pipenv/vendor/requests/packages/idna/core.py b/pipenv/vendor/requests/packages/idna/core.py new file mode 100644 index 00000000..ff3b38d6 --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/core.py @@ -0,0 +1,387 @@ +from . import idnadata +import bisect +import unicodedata +import re +import sys +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b'xn--' +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +if sys.version_info[0] == 3: + unicode = str + unichr = chr + +class IDNAError(UnicodeError): + """ Base exception for all IDNA-encoding related problems """ + pass + + +class IDNABidiError(IDNAError): + """ Exception when bidirectional requirements are not satisfied """ + pass + + +class InvalidCodepoint(IDNAError): + """ Exception when a disallowed or unallocated codepoint is used """ + pass + + +class InvalidCodepointContext(IDNAError): + """ Exception when the codepoint is not valid in the context it is used """ + pass + + +def _combining_class(cp): + return unicodedata.combining(unichr(cp)) + +def _is_script(cp, script): + return intranges_contain(ord(cp), idnadata.scripts[script]) + +def _punycode(s): + return s.encode('punycode') + +def _unot(s): + return 'U+{0:04X}'.format(s) + + +def valid_label_length(label): + + if len(label) > 63: + return False + return True + + +def valid_string_length(label, trailing_dot): + + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label, check_ltr=False): + + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == '': + # String likely comes from a newer version of Unicode + raise IDNABidiError('Unknown directionality in label {0} at position {1}'.format(repr(label), idx)) + if direction in ['R', 'AL', 'AN']: + bidi_label = True + break + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ['R', 'AL']: + rtl = True + elif direction == 'L': + rtl = False + else: + raise IDNABidiError('First codepoint in label {0} must be directionality L, R or AL'.format(repr(label))) + + valid_ending = False + number_type = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a right-to-left label'.format(idx)) + # Bidi rule 3 + if direction in ['R', 'AL', 'EN', 'AN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + # Bidi rule 4 + if direction in ['AN', 'EN']: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError('Can not mix numeral types in a right-to-left label') + else: + # Bidi rule 5 + if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a left-to-right label'.format(idx)) + # Bidi rule 6 + if direction in ['L', 'EN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + + if not valid_ending: + raise IDNABidiError('Label ends with illegal codepoint directionality') + + return True + + +def check_initial_combiner(label): + + if unicodedata.category(label[0])[0] == 'M': + raise IDNAError('Label begins with an illegal combining character') + return True + + +def check_hyphen_ok(label): + + if label[2:4] == '--': + raise IDNAError('Label has disallowed hyphens in 3rd and 4th position') + if label[0] == '-' or label[-1] == '-': + raise IDNAError('Label must not start or end with a hyphen') + return True + + +def check_nfc(label): + + if unicodedata.normalize('NFC', label) != label: + raise IDNAError('Label must be in Normalization Form C') + + +def valid_contextj(label, pos): + + cp_value = ord(label[pos]) + + if cp_value == 0x200c: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos-1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == 'T': + continue + if joining_type in ['L', 'D']: + ok = True + break + + if not ok: + return False + + ok = False + for i in range(pos+1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == 'T': + continue + if joining_type in ['R', 'D']: + ok = True + break + return ok + + if cp_value == 0x200d: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + + return False + + +def valid_contexto(label, pos, exception=False): + + cp_value = ord(label[pos]) + + if cp_value == 0x00b7: + if 0 < pos < len(label)-1: + if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label)-1 and len(label) > 1: + return _is_script(label[pos + 1], 'Greek') + return False + + elif cp_value == 0x05f3 or cp_value == 0x05f4: + if pos > 0: + return _is_script(label[pos - 1], 'Hebrew') + return False + + elif cp_value == 0x30fb: + for cp in label: + if cp == u'\u30fb': + continue + if not _is_script(cp, 'Hiragana') and not _is_script(cp, 'Katakana') and not _is_script(cp, 'Han'): + return False + return True + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6f0 <= ord(cp) <= 0x06f9: + return False + return True + + elif 0x6f0 <= cp_value <= 0x6f9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + +def check_label(label): + + if isinstance(label, (bytes, bytearray)): + label = label.decode('utf-8') + if len(label) == 0: + raise IDNAError('Empty Label') + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for (pos, cp) in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']): + if not valid_contextj(label, pos): + raise InvalidCodepointContext('Joiner {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label))) + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']): + if not valid_contexto(label, pos): + raise InvalidCodepointContext('Codepoint {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label))) + else: + raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label))) + + check_bidi(label) + + +def alabel(label): + + try: + label = label.encode('ascii') + try: + ulabel(label) + except: + raise IDNAError('The label {0} is not a valid A-label'.format(label)) + if not valid_label_length(label): + raise IDNAError('Label too long') + return label + except UnicodeError: + pass + + if not label: + raise IDNAError('No Input') + + label = unicode(label) + check_label(label) + label = _punycode(label) + label = _alabel_prefix + label + + if not valid_label_length(label): + raise IDNAError('Label too long') + + return label + + +def ulabel(label): + + if not isinstance(label, (bytes, bytearray)): + try: + label = label.encode('ascii') + except UnicodeError: + check_label(label) + return label + + label = label.lower() + if label.startswith(_alabel_prefix): + label = label[len(_alabel_prefix):] + else: + check_label(label) + return label.decode('ascii') + + label = label.decode('punycode') + check_label(label) + return label + + +def uts46_remap(domain, std3_rules=True, transitional=False): + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + output = u"" + try: + for pos, char in enumerate(domain): + code_point = ord(char) + uts46row = uts46data[code_point if code_point < 256 else + bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement = uts46row[2] if len(uts46row) == 3 else None + if (status == "V" or + (status == "D" and not transitional) or + (status == "3" and std3_rules and replacement is None)): + output += char + elif replacement is not None and (status == "M" or + (status == "3" and std3_rules) or + (status == "D" and transitional)): + output += replacement + elif status != "I": + raise IndexError() + return unicodedata.normalize("NFC", output) + except IndexError: + raise InvalidCodepoint( + "Codepoint {0} not allowed at position {1} in {2}".format( + _unot(code_point), pos + 1, repr(domain))) + + +def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split('.') + else: + labels = _unicode_dots_re.split(s) + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if labels[-1] == '': + del labels[-1] + trailing_dot = True + for label in labels: + result.append(alabel(label)) + if trailing_dot: + result.append(b'') + s = b'.'.join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError('Domain too long') + return s + + +def decode(s, strict=False, uts46=False, std3_rules=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(u'.') + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + result.append(ulabel(label)) + if trailing_dot: + result.append(u'') + return u'.'.join(result) diff --git a/pipenv/vendor/requests/packages/idna/idnadata.py b/pipenv/vendor/requests/packages/idna/idnadata.py new file mode 100644 index 00000000..2bffe527 --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/idnadata.py @@ -0,0 +1,1584 @@ +# This file is automatically generated by build-idnadata.py + +scripts = { + 'Greek': ( + (0x370, 0x374), + (0x375, 0x378), + (0x37a, 0x37e), + (0x384, 0x385), + (0x386, 0x387), + (0x388, 0x38b), + (0x38c, 0x38d), + (0x38e, 0x3a2), + (0x3a3, 0x3e2), + (0x3f0, 0x400), + (0x1d26, 0x1d2b), + (0x1d5d, 0x1d62), + (0x1d66, 0x1d6b), + (0x1dbf, 0x1dc0), + (0x1f00, 0x1f16), + (0x1f18, 0x1f1e), + (0x1f20, 0x1f46), + (0x1f48, 0x1f4e), + (0x1f50, 0x1f58), + (0x1f59, 0x1f5a), + (0x1f5b, 0x1f5c), + (0x1f5d, 0x1f5e), + (0x1f5f, 0x1f7e), + (0x1f80, 0x1fb5), + (0x1fb6, 0x1fc5), + (0x1fc6, 0x1fd4), + (0x1fd6, 0x1fdc), + (0x1fdd, 0x1ff0), + (0x1ff2, 0x1ff5), + (0x1ff6, 0x1fff), + (0x2126, 0x2127), + (0x10140, 0x1018b), + (0x1d200, 0x1d246), + ), + 'Han': ( + (0x2e80, 0x2e9a), + (0x2e9b, 0x2ef4), + (0x2f00, 0x2fd6), + (0x3005, 0x3006), + (0x3007, 0x3008), + (0x3021, 0x302a), + (0x3038, 0x303c), + (0x3400, 0x4db6), + (0x4e00, 0x9fcd), + (0xf900, 0xfa6e), + (0xfa70, 0xfada), + (0x20000, 0x2a6d7), + (0x2a700, 0x2b735), + (0x2b740, 0x2b81e), + (0x2f800, 0x2fa1e), + ), + 'Hebrew': ( + (0x591, 0x5c8), + (0x5d0, 0x5eb), + (0x5f0, 0x5f5), + (0xfb1d, 0xfb37), + (0xfb38, 0xfb3d), + (0xfb3e, 0xfb3f), + (0xfb40, 0xfb42), + (0xfb43, 0xfb45), + (0xfb46, 0xfb50), + ), + 'Hiragana': ( + (0x3041, 0x3097), + (0x309d, 0x30a0), + (0x1b001, 0x1b002), + (0x1f200, 0x1f201), + ), + 'Katakana': ( + (0x30a1, 0x30fb), + (0x30fd, 0x3100), + (0x31f0, 0x3200), + (0x32d0, 0x32ff), + (0x3300, 0x3358), + (0xff66, 0xff70), + (0xff71, 0xff9e), + (0x1b000, 0x1b001), + ), +} +joining_types = { + 0x600: 'U', + 0x601: 'U', + 0x602: 'U', + 0x603: 'U', + 0x604: 'U', + 0x608: 'U', + 0x60b: 'U', + 0x620: 'D', + 0x621: 'U', + 0x622: 'R', + 0x623: 'R', + 0x624: 'R', + 0x625: 'R', + 0x626: 'D', + 0x627: 'R', + 0x628: 'D', + 0x629: 'R', + 0x62a: 'D', + 0x62b: 'D', + 0x62c: 'D', + 0x62d: 'D', + 0x62e: 'D', + 0x62f: 'R', + 0x630: 'R', + 0x631: 'R', + 0x632: 'R', + 0x633: 'D', + 0x634: 'D', + 0x635: 'D', + 0x636: 'D', + 0x637: 'D', + 0x638: 'D', + 0x639: 'D', + 0x63a: 'D', + 0x63b: 'D', + 0x63c: 'D', + 0x63d: 'D', + 0x63e: 'D', + 0x63f: 'D', + 0x640: 'C', + 0x641: 'D', + 0x642: 'D', + 0x643: 'D', + 0x644: 'D', + 0x645: 'D', + 0x646: 'D', + 0x647: 'D', + 0x648: 'R', + 0x649: 'D', + 0x64a: 'D', + 0x66e: 'D', + 0x66f: 'D', + 0x671: 'R', + 0x672: 'R', + 0x673: 'R', + 0x674: 'U', + 0x675: 'R', + 0x676: 'R', + 0x677: 'R', + 0x678: 'D', + 0x679: 'D', + 0x67a: 'D', + 0x67b: 'D', + 0x67c: 'D', + 0x67d: 'D', + 0x67e: 'D', + 0x67f: 'D', + 0x680: 'D', + 0x681: 'D', + 0x682: 'D', + 0x683: 'D', + 0x684: 'D', + 0x685: 'D', + 0x686: 'D', + 0x687: 'D', + 0x688: 'R', + 0x689: 'R', + 0x68a: 'R', + 0x68b: 'R', + 0x68c: 'R', + 0x68d: 'R', + 0x68e: 'R', + 0x68f: 'R', + 0x690: 'R', + 0x691: 'R', + 0x692: 'R', + 0x693: 'R', + 0x694: 'R', + 0x695: 'R', + 0x696: 'R', + 0x697: 'R', + 0x698: 'R', + 0x699: 'R', + 0x69a: 'D', + 0x69b: 'D', + 0x69c: 'D', + 0x69d: 'D', + 0x69e: 'D', + 0x69f: 'D', + 0x6a0: 'D', + 0x6a1: 'D', + 0x6a2: 'D', + 0x6a3: 'D', + 0x6a4: 'D', + 0x6a5: 'D', + 0x6a6: 'D', + 0x6a7: 'D', + 0x6a8: 'D', + 0x6a9: 'D', + 0x6aa: 'D', + 0x6ab: 'D', + 0x6ac: 'D', + 0x6ad: 'D', + 0x6ae: 'D', + 0x6af: 'D', + 0x6b0: 'D', + 0x6b1: 'D', + 0x6b2: 'D', + 0x6b3: 'D', + 0x6b4: 'D', + 0x6b5: 'D', + 0x6b6: 'D', + 0x6b7: 'D', + 0x6b8: 'D', + 0x6b9: 'D', + 0x6ba: 'D', + 0x6bb: 'D', + 0x6bc: 'D', + 0x6bd: 'D', + 0x6be: 'D', + 0x6bf: 'D', + 0x6c0: 'R', + 0x6c1: 'D', + 0x6c2: 'D', + 0x6c3: 'R', + 0x6c4: 'R', + 0x6c5: 'R', + 0x6c6: 'R', + 0x6c7: 'R', + 0x6c8: 'R', + 0x6c9: 'R', + 0x6ca: 'R', + 0x6cb: 'R', + 0x6cc: 'D', + 0x6cd: 'R', + 0x6ce: 'D', + 0x6cf: 'R', + 0x6d0: 'D', + 0x6d1: 'D', + 0x6d2: 'R', + 0x6d3: 'R', + 0x6d5: 'R', + 0x6dd: 'U', + 0x6ee: 'R', + 0x6ef: 'R', + 0x6fa: 'D', + 0x6fb: 'D', + 0x6fc: 'D', + 0x6ff: 'D', + 0x710: 'R', + 0x712: 'D', + 0x713: 'D', + 0x714: 'D', + 0x715: 'R', + 0x716: 'R', + 0x717: 'R', + 0x718: 'R', + 0x719: 'R', + 0x71a: 'D', + 0x71b: 'D', + 0x71c: 'D', + 0x71d: 'D', + 0x71e: 'R', + 0x71f: 'D', + 0x720: 'D', + 0x721: 'D', + 0x722: 'D', + 0x723: 'D', + 0x724: 'D', + 0x725: 'D', + 0x726: 'D', + 0x727: 'D', + 0x728: 'R', + 0x729: 'D', + 0x72a: 'R', + 0x72b: 'D', + 0x72c: 'R', + 0x72d: 'D', + 0x72e: 'D', + 0x72f: 'R', + 0x74d: 'R', + 0x74e: 'D', + 0x74f: 'D', + 0x750: 'D', + 0x751: 'D', + 0x752: 'D', + 0x753: 'D', + 0x754: 'D', + 0x755: 'D', + 0x756: 'D', + 0x757: 'D', + 0x758: 'D', + 0x759: 'R', + 0x75a: 'R', + 0x75b: 'R', + 0x75c: 'D', + 0x75d: 'D', + 0x75e: 'D', + 0x75f: 'D', + 0x760: 'D', + 0x761: 'D', + 0x762: 'D', + 0x763: 'D', + 0x764: 'D', + 0x765: 'D', + 0x766: 'D', + 0x767: 'D', + 0x768: 'D', + 0x769: 'D', + 0x76a: 'D', + 0x76b: 'R', + 0x76c: 'R', + 0x76d: 'D', + 0x76e: 'D', + 0x76f: 'D', + 0x770: 'D', + 0x771: 'R', + 0x772: 'D', + 0x773: 'R', + 0x774: 'R', + 0x775: 'D', + 0x776: 'D', + 0x777: 'D', + 0x778: 'R', + 0x779: 'R', + 0x77a: 'D', + 0x77b: 'D', + 0x77c: 'D', + 0x77d: 'D', + 0x77e: 'D', + 0x77f: 'D', + 0x7ca: 'D', + 0x7cb: 'D', + 0x7cc: 'D', + 0x7cd: 'D', + 0x7ce: 'D', + 0x7cf: 'D', + 0x7d0: 'D', + 0x7d1: 'D', + 0x7d2: 'D', + 0x7d3: 'D', + 0x7d4: 'D', + 0x7d5: 'D', + 0x7d6: 'D', + 0x7d7: 'D', + 0x7d8: 'D', + 0x7d9: 'D', + 0x7da: 'D', + 0x7db: 'D', + 0x7dc: 'D', + 0x7dd: 'D', + 0x7de: 'D', + 0x7df: 'D', + 0x7e0: 'D', + 0x7e1: 'D', + 0x7e2: 'D', + 0x7e3: 'D', + 0x7e4: 'D', + 0x7e5: 'D', + 0x7e6: 'D', + 0x7e7: 'D', + 0x7e8: 'D', + 0x7e9: 'D', + 0x7ea: 'D', + 0x7fa: 'C', + 0x840: 'R', + 0x841: 'D', + 0x842: 'D', + 0x843: 'D', + 0x844: 'D', + 0x845: 'D', + 0x846: 'R', + 0x847: 'D', + 0x848: 'D', + 0x849: 'R', + 0x84a: 'D', + 0x84b: 'D', + 0x84c: 'D', + 0x84d: 'D', + 0x84e: 'D', + 0x84f: 'R', + 0x850: 'D', + 0x851: 'D', + 0x852: 'D', + 0x853: 'D', + 0x854: 'R', + 0x855: 'D', + 0x856: 'U', + 0x857: 'U', + 0x858: 'U', + 0x8a0: 'D', + 0x8a2: 'D', + 0x8a3: 'D', + 0x8a4: 'D', + 0x8a5: 'D', + 0x8a6: 'D', + 0x8a7: 'D', + 0x8a8: 'D', + 0x8a9: 'D', + 0x8aa: 'R', + 0x8ab: 'R', + 0x8ac: 'R', + 0x1806: 'U', + 0x1807: 'D', + 0x180a: 'C', + 0x180e: 'U', + 0x1820: 'D', + 0x1821: 'D', + 0x1822: 'D', + 0x1823: 'D', + 0x1824: 'D', + 0x1825: 'D', + 0x1826: 'D', + 0x1827: 'D', + 0x1828: 'D', + 0x1829: 'D', + 0x182a: 'D', + 0x182b: 'D', + 0x182c: 'D', + 0x182d: 'D', + 0x182e: 'D', + 0x182f: 'D', + 0x1830: 'D', + 0x1831: 'D', + 0x1832: 'D', + 0x1833: 'D', + 0x1834: 'D', + 0x1835: 'D', + 0x1836: 'D', + 0x1837: 'D', + 0x1838: 'D', + 0x1839: 'D', + 0x183a: 'D', + 0x183b: 'D', + 0x183c: 'D', + 0x183d: 'D', + 0x183e: 'D', + 0x183f: 'D', + 0x1840: 'D', + 0x1841: 'D', + 0x1842: 'D', + 0x1843: 'D', + 0x1844: 'D', + 0x1845: 'D', + 0x1846: 'D', + 0x1847: 'D', + 0x1848: 'D', + 0x1849: 'D', + 0x184a: 'D', + 0x184b: 'D', + 0x184c: 'D', + 0x184d: 'D', + 0x184e: 'D', + 0x184f: 'D', + 0x1850: 'D', + 0x1851: 'D', + 0x1852: 'D', + 0x1853: 'D', + 0x1854: 'D', + 0x1855: 'D', + 0x1856: 'D', + 0x1857: 'D', + 0x1858: 'D', + 0x1859: 'D', + 0x185a: 'D', + 0x185b: 'D', + 0x185c: 'D', + 0x185d: 'D', + 0x185e: 'D', + 0x185f: 'D', + 0x1860: 'D', + 0x1861: 'D', + 0x1862: 'D', + 0x1863: 'D', + 0x1864: 'D', + 0x1865: 'D', + 0x1866: 'D', + 0x1867: 'D', + 0x1868: 'D', + 0x1869: 'D', + 0x186a: 'D', + 0x186b: 'D', + 0x186c: 'D', + 0x186d: 'D', + 0x186e: 'D', + 0x186f: 'D', + 0x1870: 'D', + 0x1871: 'D', + 0x1872: 'D', + 0x1873: 'D', + 0x1874: 'D', + 0x1875: 'D', + 0x1876: 'D', + 0x1877: 'D', + 0x1880: 'U', + 0x1881: 'U', + 0x1882: 'U', + 0x1883: 'U', + 0x1884: 'U', + 0x1885: 'U', + 0x1886: 'U', + 0x1887: 'D', + 0x1888: 'D', + 0x1889: 'D', + 0x188a: 'D', + 0x188b: 'D', + 0x188c: 'D', + 0x188d: 'D', + 0x188e: 'D', + 0x188f: 'D', + 0x1890: 'D', + 0x1891: 'D', + 0x1892: 'D', + 0x1893: 'D', + 0x1894: 'D', + 0x1895: 'D', + 0x1896: 'D', + 0x1897: 'D', + 0x1898: 'D', + 0x1899: 'D', + 0x189a: 'D', + 0x189b: 'D', + 0x189c: 'D', + 0x189d: 'D', + 0x189e: 'D', + 0x189f: 'D', + 0x18a0: 'D', + 0x18a1: 'D', + 0x18a2: 'D', + 0x18a3: 'D', + 0x18a4: 'D', + 0x18a5: 'D', + 0x18a6: 'D', + 0x18a7: 'D', + 0x18a8: 'D', + 0x18aa: 'D', + 0x200c: 'U', + 0x200d: 'C', + 0x2066: 'U', + 0x2067: 'U', + 0x2068: 'U', + 0x2069: 'U', + 0xa840: 'D', + 0xa841: 'D', + 0xa842: 'D', + 0xa843: 'D', + 0xa844: 'D', + 0xa845: 'D', + 0xa846: 'D', + 0xa847: 'D', + 0xa848: 'D', + 0xa849: 'D', + 0xa84a: 'D', + 0xa84b: 'D', + 0xa84c: 'D', + 0xa84d: 'D', + 0xa84e: 'D', + 0xa84f: 'D', + 0xa850: 'D', + 0xa851: 'D', + 0xa852: 'D', + 0xa853: 'D', + 0xa854: 'D', + 0xa855: 'D', + 0xa856: 'D', + 0xa857: 'D', + 0xa858: 'D', + 0xa859: 'D', + 0xa85a: 'D', + 0xa85b: 'D', + 0xa85c: 'D', + 0xa85d: 'D', + 0xa85e: 'D', + 0xa85f: 'D', + 0xa860: 'D', + 0xa861: 'D', + 0xa862: 'D', + 0xa863: 'D', + 0xa864: 'D', + 0xa865: 'D', + 0xa866: 'D', + 0xa867: 'D', + 0xa868: 'D', + 0xa869: 'D', + 0xa86a: 'D', + 0xa86b: 'D', + 0xa86c: 'D', + 0xa86d: 'D', + 0xa86e: 'D', + 0xa86f: 'D', + 0xa870: 'D', + 0xa871: 'D', + 0xa872: 'L', + 0xa873: 'U', +} +codepoint_classes = { + 'PVALID': ( + (0x2d, 0x2e), + (0x30, 0x3a), + (0x61, 0x7b), + (0xdf, 0xf7), + (0xf8, 0x100), + (0x101, 0x102), + (0x103, 0x104), + (0x105, 0x106), + (0x107, 0x108), + (0x109, 0x10a), + (0x10b, 0x10c), + (0x10d, 0x10e), + (0x10f, 0x110), + (0x111, 0x112), + (0x113, 0x114), + (0x115, 0x116), + (0x117, 0x118), + (0x119, 0x11a), + (0x11b, 0x11c), + (0x11d, 0x11e), + (0x11f, 0x120), + (0x121, 0x122), + (0x123, 0x124), + (0x125, 0x126), + (0x127, 0x128), + (0x129, 0x12a), + (0x12b, 0x12c), + (0x12d, 0x12e), + (0x12f, 0x130), + (0x131, 0x132), + (0x135, 0x136), + (0x137, 0x139), + (0x13a, 0x13b), + (0x13c, 0x13d), + (0x13e, 0x13f), + (0x142, 0x143), + (0x144, 0x145), + (0x146, 0x147), + (0x148, 0x149), + (0x14b, 0x14c), + (0x14d, 0x14e), + (0x14f, 0x150), + (0x151, 0x152), + (0x153, 0x154), + (0x155, 0x156), + (0x157, 0x158), + (0x159, 0x15a), + (0x15b, 0x15c), + (0x15d, 0x15e), + (0x15f, 0x160), + (0x161, 0x162), + (0x163, 0x164), + (0x165, 0x166), + (0x167, 0x168), + (0x169, 0x16a), + (0x16b, 0x16c), + (0x16d, 0x16e), + (0x16f, 0x170), + (0x171, 0x172), + (0x173, 0x174), + (0x175, 0x176), + (0x177, 0x178), + (0x17a, 0x17b), + (0x17c, 0x17d), + (0x17e, 0x17f), + (0x180, 0x181), + (0x183, 0x184), + (0x185, 0x186), + (0x188, 0x189), + (0x18c, 0x18e), + (0x192, 0x193), + (0x195, 0x196), + (0x199, 0x19c), + (0x19e, 0x19f), + (0x1a1, 0x1a2), + (0x1a3, 0x1a4), + (0x1a5, 0x1a6), + (0x1a8, 0x1a9), + (0x1aa, 0x1ac), + (0x1ad, 0x1ae), + (0x1b0, 0x1b1), + (0x1b4, 0x1b5), + (0x1b6, 0x1b7), + (0x1b9, 0x1bc), + (0x1bd, 0x1c4), + (0x1ce, 0x1cf), + (0x1d0, 0x1d1), + (0x1d2, 0x1d3), + (0x1d4, 0x1d5), + (0x1d6, 0x1d7), + (0x1d8, 0x1d9), + (0x1da, 0x1db), + (0x1dc, 0x1de), + (0x1df, 0x1e0), + (0x1e1, 0x1e2), + (0x1e3, 0x1e4), + (0x1e5, 0x1e6), + (0x1e7, 0x1e8), + (0x1e9, 0x1ea), + (0x1eb, 0x1ec), + (0x1ed, 0x1ee), + (0x1ef, 0x1f1), + (0x1f5, 0x1f6), + (0x1f9, 0x1fa), + (0x1fb, 0x1fc), + (0x1fd, 0x1fe), + (0x1ff, 0x200), + (0x201, 0x202), + (0x203, 0x204), + (0x205, 0x206), + (0x207, 0x208), + (0x209, 0x20a), + (0x20b, 0x20c), + (0x20d, 0x20e), + (0x20f, 0x210), + (0x211, 0x212), + (0x213, 0x214), + (0x215, 0x216), + (0x217, 0x218), + (0x219, 0x21a), + (0x21b, 0x21c), + (0x21d, 0x21e), + (0x21f, 0x220), + (0x221, 0x222), + (0x223, 0x224), + (0x225, 0x226), + (0x227, 0x228), + (0x229, 0x22a), + (0x22b, 0x22c), + (0x22d, 0x22e), + (0x22f, 0x230), + (0x231, 0x232), + (0x233, 0x23a), + (0x23c, 0x23d), + (0x23f, 0x241), + (0x242, 0x243), + (0x247, 0x248), + (0x249, 0x24a), + (0x24b, 0x24c), + (0x24d, 0x24e), + (0x24f, 0x2b0), + (0x2b9, 0x2c2), + (0x2c6, 0x2d2), + (0x2ec, 0x2ed), + (0x2ee, 0x2ef), + (0x300, 0x340), + (0x342, 0x343), + (0x346, 0x34f), + (0x350, 0x370), + (0x371, 0x372), + (0x373, 0x374), + (0x377, 0x378), + (0x37b, 0x37e), + (0x390, 0x391), + (0x3ac, 0x3cf), + (0x3d7, 0x3d8), + (0x3d9, 0x3da), + (0x3db, 0x3dc), + (0x3dd, 0x3de), + (0x3df, 0x3e0), + (0x3e1, 0x3e2), + (0x3e3, 0x3e4), + (0x3e5, 0x3e6), + (0x3e7, 0x3e8), + (0x3e9, 0x3ea), + (0x3eb, 0x3ec), + (0x3ed, 0x3ee), + (0x3ef, 0x3f0), + (0x3f3, 0x3f4), + (0x3f8, 0x3f9), + (0x3fb, 0x3fd), + (0x430, 0x460), + (0x461, 0x462), + (0x463, 0x464), + (0x465, 0x466), + (0x467, 0x468), + (0x469, 0x46a), + (0x46b, 0x46c), + (0x46d, 0x46e), + (0x46f, 0x470), + (0x471, 0x472), + (0x473, 0x474), + (0x475, 0x476), + (0x477, 0x478), + (0x479, 0x47a), + (0x47b, 0x47c), + (0x47d, 0x47e), + (0x47f, 0x480), + (0x481, 0x482), + (0x483, 0x488), + (0x48b, 0x48c), + (0x48d, 0x48e), + (0x48f, 0x490), + (0x491, 0x492), + (0x493, 0x494), + (0x495, 0x496), + (0x497, 0x498), + (0x499, 0x49a), + (0x49b, 0x49c), + (0x49d, 0x49e), + (0x49f, 0x4a0), + (0x4a1, 0x4a2), + (0x4a3, 0x4a4), + (0x4a5, 0x4a6), + (0x4a7, 0x4a8), + (0x4a9, 0x4aa), + (0x4ab, 0x4ac), + (0x4ad, 0x4ae), + (0x4af, 0x4b0), + (0x4b1, 0x4b2), + (0x4b3, 0x4b4), + (0x4b5, 0x4b6), + (0x4b7, 0x4b8), + (0x4b9, 0x4ba), + (0x4bb, 0x4bc), + (0x4bd, 0x4be), + (0x4bf, 0x4c0), + (0x4c2, 0x4c3), + (0x4c4, 0x4c5), + (0x4c6, 0x4c7), + (0x4c8, 0x4c9), + (0x4ca, 0x4cb), + (0x4cc, 0x4cd), + (0x4ce, 0x4d0), + (0x4d1, 0x4d2), + (0x4d3, 0x4d4), + (0x4d5, 0x4d6), + (0x4d7, 0x4d8), + (0x4d9, 0x4da), + (0x4db, 0x4dc), + (0x4dd, 0x4de), + (0x4df, 0x4e0), + (0x4e1, 0x4e2), + (0x4e3, 0x4e4), + (0x4e5, 0x4e6), + (0x4e7, 0x4e8), + (0x4e9, 0x4ea), + (0x4eb, 0x4ec), + (0x4ed, 0x4ee), + (0x4ef, 0x4f0), + (0x4f1, 0x4f2), + (0x4f3, 0x4f4), + (0x4f5, 0x4f6), + (0x4f7, 0x4f8), + (0x4f9, 0x4fa), + (0x4fb, 0x4fc), + (0x4fd, 0x4fe), + (0x4ff, 0x500), + (0x501, 0x502), + (0x503, 0x504), + (0x505, 0x506), + (0x507, 0x508), + (0x509, 0x50a), + (0x50b, 0x50c), + (0x50d, 0x50e), + (0x50f, 0x510), + (0x511, 0x512), + (0x513, 0x514), + (0x515, 0x516), + (0x517, 0x518), + (0x519, 0x51a), + (0x51b, 0x51c), + (0x51d, 0x51e), + (0x51f, 0x520), + (0x521, 0x522), + (0x523, 0x524), + (0x525, 0x526), + (0x527, 0x528), + (0x559, 0x55a), + (0x561, 0x587), + (0x591, 0x5be), + (0x5bf, 0x5c0), + (0x5c1, 0x5c3), + (0x5c4, 0x5c6), + (0x5c7, 0x5c8), + (0x5d0, 0x5eb), + (0x5f0, 0x5f3), + (0x610, 0x61b), + (0x620, 0x640), + (0x641, 0x660), + (0x66e, 0x675), + (0x679, 0x6d4), + (0x6d5, 0x6dd), + (0x6df, 0x6e9), + (0x6ea, 0x6f0), + (0x6fa, 0x700), + (0x710, 0x74b), + (0x74d, 0x7b2), + (0x7c0, 0x7f6), + (0x800, 0x82e), + (0x840, 0x85c), + (0x8a0, 0x8a1), + (0x8a2, 0x8ad), + (0x8e4, 0x8ff), + (0x900, 0x958), + (0x960, 0x964), + (0x966, 0x970), + (0x971, 0x978), + (0x979, 0x980), + (0x981, 0x984), + (0x985, 0x98d), + (0x98f, 0x991), + (0x993, 0x9a9), + (0x9aa, 0x9b1), + (0x9b2, 0x9b3), + (0x9b6, 0x9ba), + (0x9bc, 0x9c5), + (0x9c7, 0x9c9), + (0x9cb, 0x9cf), + (0x9d7, 0x9d8), + (0x9e0, 0x9e4), + (0x9e6, 0x9f2), + (0xa01, 0xa04), + (0xa05, 0xa0b), + (0xa0f, 0xa11), + (0xa13, 0xa29), + (0xa2a, 0xa31), + (0xa32, 0xa33), + (0xa35, 0xa36), + (0xa38, 0xa3a), + (0xa3c, 0xa3d), + (0xa3e, 0xa43), + (0xa47, 0xa49), + (0xa4b, 0xa4e), + (0xa51, 0xa52), + (0xa5c, 0xa5d), + (0xa66, 0xa76), + (0xa81, 0xa84), + (0xa85, 0xa8e), + (0xa8f, 0xa92), + (0xa93, 0xaa9), + (0xaaa, 0xab1), + (0xab2, 0xab4), + (0xab5, 0xaba), + (0xabc, 0xac6), + (0xac7, 0xaca), + (0xacb, 0xace), + (0xad0, 0xad1), + (0xae0, 0xae4), + (0xae6, 0xaf0), + (0xb01, 0xb04), + (0xb05, 0xb0d), + (0xb0f, 0xb11), + (0xb13, 0xb29), + (0xb2a, 0xb31), + (0xb32, 0xb34), + (0xb35, 0xb3a), + (0xb3c, 0xb45), + (0xb47, 0xb49), + (0xb4b, 0xb4e), + (0xb56, 0xb58), + (0xb5f, 0xb64), + (0xb66, 0xb70), + (0xb71, 0xb72), + (0xb82, 0xb84), + (0xb85, 0xb8b), + (0xb8e, 0xb91), + (0xb92, 0xb96), + (0xb99, 0xb9b), + (0xb9c, 0xb9d), + (0xb9e, 0xba0), + (0xba3, 0xba5), + (0xba8, 0xbab), + (0xbae, 0xbba), + (0xbbe, 0xbc3), + (0xbc6, 0xbc9), + (0xbca, 0xbce), + (0xbd0, 0xbd1), + (0xbd7, 0xbd8), + (0xbe6, 0xbf0), + (0xc01, 0xc04), + (0xc05, 0xc0d), + (0xc0e, 0xc11), + (0xc12, 0xc29), + (0xc2a, 0xc34), + (0xc35, 0xc3a), + (0xc3d, 0xc45), + (0xc46, 0xc49), + (0xc4a, 0xc4e), + (0xc55, 0xc57), + (0xc58, 0xc5a), + (0xc60, 0xc64), + (0xc66, 0xc70), + (0xc82, 0xc84), + (0xc85, 0xc8d), + (0xc8e, 0xc91), + (0xc92, 0xca9), + (0xcaa, 0xcb4), + (0xcb5, 0xcba), + (0xcbc, 0xcc5), + (0xcc6, 0xcc9), + (0xcca, 0xcce), + (0xcd5, 0xcd7), + (0xcde, 0xcdf), + (0xce0, 0xce4), + (0xce6, 0xcf0), + (0xcf1, 0xcf3), + (0xd02, 0xd04), + (0xd05, 0xd0d), + (0xd0e, 0xd11), + (0xd12, 0xd3b), + (0xd3d, 0xd45), + (0xd46, 0xd49), + (0xd4a, 0xd4f), + (0xd57, 0xd58), + (0xd60, 0xd64), + (0xd66, 0xd70), + (0xd7a, 0xd80), + (0xd82, 0xd84), + (0xd85, 0xd97), + (0xd9a, 0xdb2), + (0xdb3, 0xdbc), + (0xdbd, 0xdbe), + (0xdc0, 0xdc7), + (0xdca, 0xdcb), + (0xdcf, 0xdd5), + (0xdd6, 0xdd7), + (0xdd8, 0xde0), + (0xdf2, 0xdf4), + (0xe01, 0xe33), + (0xe34, 0xe3b), + (0xe40, 0xe4f), + (0xe50, 0xe5a), + (0xe81, 0xe83), + (0xe84, 0xe85), + (0xe87, 0xe89), + (0xe8a, 0xe8b), + (0xe8d, 0xe8e), + (0xe94, 0xe98), + (0xe99, 0xea0), + (0xea1, 0xea4), + (0xea5, 0xea6), + (0xea7, 0xea8), + (0xeaa, 0xeac), + (0xead, 0xeb3), + (0xeb4, 0xeba), + (0xebb, 0xebe), + (0xec0, 0xec5), + (0xec6, 0xec7), + (0xec8, 0xece), + (0xed0, 0xeda), + (0xede, 0xee0), + (0xf00, 0xf01), + (0xf0b, 0xf0c), + (0xf18, 0xf1a), + (0xf20, 0xf2a), + (0xf35, 0xf36), + (0xf37, 0xf38), + (0xf39, 0xf3a), + (0xf3e, 0xf43), + (0xf44, 0xf48), + (0xf49, 0xf4d), + (0xf4e, 0xf52), + (0xf53, 0xf57), + (0xf58, 0xf5c), + (0xf5d, 0xf69), + (0xf6a, 0xf6d), + (0xf71, 0xf73), + (0xf74, 0xf75), + (0xf7a, 0xf81), + (0xf82, 0xf85), + (0xf86, 0xf93), + (0xf94, 0xf98), + (0xf99, 0xf9d), + (0xf9e, 0xfa2), + (0xfa3, 0xfa7), + (0xfa8, 0xfac), + (0xfad, 0xfb9), + (0xfba, 0xfbd), + (0xfc6, 0xfc7), + (0x1000, 0x104a), + (0x1050, 0x109e), + (0x10d0, 0x10fb), + (0x10fd, 0x1100), + (0x1200, 0x1249), + (0x124a, 0x124e), + (0x1250, 0x1257), + (0x1258, 0x1259), + (0x125a, 0x125e), + (0x1260, 0x1289), + (0x128a, 0x128e), + (0x1290, 0x12b1), + (0x12b2, 0x12b6), + (0x12b8, 0x12bf), + (0x12c0, 0x12c1), + (0x12c2, 0x12c6), + (0x12c8, 0x12d7), + (0x12d8, 0x1311), + (0x1312, 0x1316), + (0x1318, 0x135b), + (0x135d, 0x1360), + (0x1380, 0x1390), + (0x13a0, 0x13f5), + (0x1401, 0x166d), + (0x166f, 0x1680), + (0x1681, 0x169b), + (0x16a0, 0x16eb), + (0x1700, 0x170d), + (0x170e, 0x1715), + (0x1720, 0x1735), + (0x1740, 0x1754), + (0x1760, 0x176d), + (0x176e, 0x1771), + (0x1772, 0x1774), + (0x1780, 0x17b4), + (0x17b6, 0x17d4), + (0x17d7, 0x17d8), + (0x17dc, 0x17de), + (0x17e0, 0x17ea), + (0x1810, 0x181a), + (0x1820, 0x1878), + (0x1880, 0x18ab), + (0x18b0, 0x18f6), + (0x1900, 0x191d), + (0x1920, 0x192c), + (0x1930, 0x193c), + (0x1946, 0x196e), + (0x1970, 0x1975), + (0x1980, 0x19ac), + (0x19b0, 0x19ca), + (0x19d0, 0x19da), + (0x1a00, 0x1a1c), + (0x1a20, 0x1a5f), + (0x1a60, 0x1a7d), + (0x1a7f, 0x1a8a), + (0x1a90, 0x1a9a), + (0x1aa7, 0x1aa8), + (0x1b00, 0x1b4c), + (0x1b50, 0x1b5a), + (0x1b6b, 0x1b74), + (0x1b80, 0x1bf4), + (0x1c00, 0x1c38), + (0x1c40, 0x1c4a), + (0x1c4d, 0x1c7e), + (0x1cd0, 0x1cd3), + (0x1cd4, 0x1cf7), + (0x1d00, 0x1d2c), + (0x1d2f, 0x1d30), + (0x1d3b, 0x1d3c), + (0x1d4e, 0x1d4f), + (0x1d6b, 0x1d78), + (0x1d79, 0x1d9b), + (0x1dc0, 0x1de7), + (0x1dfc, 0x1e00), + (0x1e01, 0x1e02), + (0x1e03, 0x1e04), + (0x1e05, 0x1e06), + (0x1e07, 0x1e08), + (0x1e09, 0x1e0a), + (0x1e0b, 0x1e0c), + (0x1e0d, 0x1e0e), + (0x1e0f, 0x1e10), + (0x1e11, 0x1e12), + (0x1e13, 0x1e14), + (0x1e15, 0x1e16), + (0x1e17, 0x1e18), + (0x1e19, 0x1e1a), + (0x1e1b, 0x1e1c), + (0x1e1d, 0x1e1e), + (0x1e1f, 0x1e20), + (0x1e21, 0x1e22), + (0x1e23, 0x1e24), + (0x1e25, 0x1e26), + (0x1e27, 0x1e28), + (0x1e29, 0x1e2a), + (0x1e2b, 0x1e2c), + (0x1e2d, 0x1e2e), + (0x1e2f, 0x1e30), + (0x1e31, 0x1e32), + (0x1e33, 0x1e34), + (0x1e35, 0x1e36), + (0x1e37, 0x1e38), + (0x1e39, 0x1e3a), + (0x1e3b, 0x1e3c), + (0x1e3d, 0x1e3e), + (0x1e3f, 0x1e40), + (0x1e41, 0x1e42), + (0x1e43, 0x1e44), + (0x1e45, 0x1e46), + (0x1e47, 0x1e48), + (0x1e49, 0x1e4a), + (0x1e4b, 0x1e4c), + (0x1e4d, 0x1e4e), + (0x1e4f, 0x1e50), + (0x1e51, 0x1e52), + (0x1e53, 0x1e54), + (0x1e55, 0x1e56), + (0x1e57, 0x1e58), + (0x1e59, 0x1e5a), + (0x1e5b, 0x1e5c), + (0x1e5d, 0x1e5e), + (0x1e5f, 0x1e60), + (0x1e61, 0x1e62), + (0x1e63, 0x1e64), + (0x1e65, 0x1e66), + (0x1e67, 0x1e68), + (0x1e69, 0x1e6a), + (0x1e6b, 0x1e6c), + (0x1e6d, 0x1e6e), + (0x1e6f, 0x1e70), + (0x1e71, 0x1e72), + (0x1e73, 0x1e74), + (0x1e75, 0x1e76), + (0x1e77, 0x1e78), + (0x1e79, 0x1e7a), + (0x1e7b, 0x1e7c), + (0x1e7d, 0x1e7e), + (0x1e7f, 0x1e80), + (0x1e81, 0x1e82), + (0x1e83, 0x1e84), + (0x1e85, 0x1e86), + (0x1e87, 0x1e88), + (0x1e89, 0x1e8a), + (0x1e8b, 0x1e8c), + (0x1e8d, 0x1e8e), + (0x1e8f, 0x1e90), + (0x1e91, 0x1e92), + (0x1e93, 0x1e94), + (0x1e95, 0x1e9a), + (0x1e9c, 0x1e9e), + (0x1e9f, 0x1ea0), + (0x1ea1, 0x1ea2), + (0x1ea3, 0x1ea4), + (0x1ea5, 0x1ea6), + (0x1ea7, 0x1ea8), + (0x1ea9, 0x1eaa), + (0x1eab, 0x1eac), + (0x1ead, 0x1eae), + (0x1eaf, 0x1eb0), + (0x1eb1, 0x1eb2), + (0x1eb3, 0x1eb4), + (0x1eb5, 0x1eb6), + (0x1eb7, 0x1eb8), + (0x1eb9, 0x1eba), + (0x1ebb, 0x1ebc), + (0x1ebd, 0x1ebe), + (0x1ebf, 0x1ec0), + (0x1ec1, 0x1ec2), + (0x1ec3, 0x1ec4), + (0x1ec5, 0x1ec6), + (0x1ec7, 0x1ec8), + (0x1ec9, 0x1eca), + (0x1ecb, 0x1ecc), + (0x1ecd, 0x1ece), + (0x1ecf, 0x1ed0), + (0x1ed1, 0x1ed2), + (0x1ed3, 0x1ed4), + (0x1ed5, 0x1ed6), + (0x1ed7, 0x1ed8), + (0x1ed9, 0x1eda), + (0x1edb, 0x1edc), + (0x1edd, 0x1ede), + (0x1edf, 0x1ee0), + (0x1ee1, 0x1ee2), + (0x1ee3, 0x1ee4), + (0x1ee5, 0x1ee6), + (0x1ee7, 0x1ee8), + (0x1ee9, 0x1eea), + (0x1eeb, 0x1eec), + (0x1eed, 0x1eee), + (0x1eef, 0x1ef0), + (0x1ef1, 0x1ef2), + (0x1ef3, 0x1ef4), + (0x1ef5, 0x1ef6), + (0x1ef7, 0x1ef8), + (0x1ef9, 0x1efa), + (0x1efb, 0x1efc), + (0x1efd, 0x1efe), + (0x1eff, 0x1f08), + (0x1f10, 0x1f16), + (0x1f20, 0x1f28), + (0x1f30, 0x1f38), + (0x1f40, 0x1f46), + (0x1f50, 0x1f58), + (0x1f60, 0x1f68), + (0x1f70, 0x1f71), + (0x1f72, 0x1f73), + (0x1f74, 0x1f75), + (0x1f76, 0x1f77), + (0x1f78, 0x1f79), + (0x1f7a, 0x1f7b), + (0x1f7c, 0x1f7d), + (0x1fb0, 0x1fb2), + (0x1fb6, 0x1fb7), + (0x1fc6, 0x1fc7), + (0x1fd0, 0x1fd3), + (0x1fd6, 0x1fd8), + (0x1fe0, 0x1fe3), + (0x1fe4, 0x1fe8), + (0x1ff6, 0x1ff7), + (0x214e, 0x214f), + (0x2184, 0x2185), + (0x2c30, 0x2c5f), + (0x2c61, 0x2c62), + (0x2c65, 0x2c67), + (0x2c68, 0x2c69), + (0x2c6a, 0x2c6b), + (0x2c6c, 0x2c6d), + (0x2c71, 0x2c72), + (0x2c73, 0x2c75), + (0x2c76, 0x2c7c), + (0x2c81, 0x2c82), + (0x2c83, 0x2c84), + (0x2c85, 0x2c86), + (0x2c87, 0x2c88), + (0x2c89, 0x2c8a), + (0x2c8b, 0x2c8c), + (0x2c8d, 0x2c8e), + (0x2c8f, 0x2c90), + (0x2c91, 0x2c92), + (0x2c93, 0x2c94), + (0x2c95, 0x2c96), + (0x2c97, 0x2c98), + (0x2c99, 0x2c9a), + (0x2c9b, 0x2c9c), + (0x2c9d, 0x2c9e), + (0x2c9f, 0x2ca0), + (0x2ca1, 0x2ca2), + (0x2ca3, 0x2ca4), + (0x2ca5, 0x2ca6), + (0x2ca7, 0x2ca8), + (0x2ca9, 0x2caa), + (0x2cab, 0x2cac), + (0x2cad, 0x2cae), + (0x2caf, 0x2cb0), + (0x2cb1, 0x2cb2), + (0x2cb3, 0x2cb4), + (0x2cb5, 0x2cb6), + (0x2cb7, 0x2cb8), + (0x2cb9, 0x2cba), + (0x2cbb, 0x2cbc), + (0x2cbd, 0x2cbe), + (0x2cbf, 0x2cc0), + (0x2cc1, 0x2cc2), + (0x2cc3, 0x2cc4), + (0x2cc5, 0x2cc6), + (0x2cc7, 0x2cc8), + (0x2cc9, 0x2cca), + (0x2ccb, 0x2ccc), + (0x2ccd, 0x2cce), + (0x2ccf, 0x2cd0), + (0x2cd1, 0x2cd2), + (0x2cd3, 0x2cd4), + (0x2cd5, 0x2cd6), + (0x2cd7, 0x2cd8), + (0x2cd9, 0x2cda), + (0x2cdb, 0x2cdc), + (0x2cdd, 0x2cde), + (0x2cdf, 0x2ce0), + (0x2ce1, 0x2ce2), + (0x2ce3, 0x2ce5), + (0x2cec, 0x2ced), + (0x2cee, 0x2cf2), + (0x2cf3, 0x2cf4), + (0x2d00, 0x2d26), + (0x2d27, 0x2d28), + (0x2d2d, 0x2d2e), + (0x2d30, 0x2d68), + (0x2d7f, 0x2d97), + (0x2da0, 0x2da7), + (0x2da8, 0x2daf), + (0x2db0, 0x2db7), + (0x2db8, 0x2dbf), + (0x2dc0, 0x2dc7), + (0x2dc8, 0x2dcf), + (0x2dd0, 0x2dd7), + (0x2dd8, 0x2ddf), + (0x2de0, 0x2e00), + (0x2e2f, 0x2e30), + (0x3005, 0x3008), + (0x302a, 0x302e), + (0x303c, 0x303d), + (0x3041, 0x3097), + (0x3099, 0x309b), + (0x309d, 0x309f), + (0x30a1, 0x30fb), + (0x30fc, 0x30ff), + (0x3105, 0x312e), + (0x31a0, 0x31bb), + (0x31f0, 0x3200), + (0x3400, 0x4db6), + (0x4e00, 0x9fcd), + (0xa000, 0xa48d), + (0xa4d0, 0xa4fe), + (0xa500, 0xa60d), + (0xa610, 0xa62c), + (0xa641, 0xa642), + (0xa643, 0xa644), + (0xa645, 0xa646), + (0xa647, 0xa648), + (0xa649, 0xa64a), + (0xa64b, 0xa64c), + (0xa64d, 0xa64e), + (0xa64f, 0xa650), + (0xa651, 0xa652), + (0xa653, 0xa654), + (0xa655, 0xa656), + (0xa657, 0xa658), + (0xa659, 0xa65a), + (0xa65b, 0xa65c), + (0xa65d, 0xa65e), + (0xa65f, 0xa660), + (0xa661, 0xa662), + (0xa663, 0xa664), + (0xa665, 0xa666), + (0xa667, 0xa668), + (0xa669, 0xa66a), + (0xa66b, 0xa66c), + (0xa66d, 0xa670), + (0xa674, 0xa67e), + (0xa67f, 0xa680), + (0xa681, 0xa682), + (0xa683, 0xa684), + (0xa685, 0xa686), + (0xa687, 0xa688), + (0xa689, 0xa68a), + (0xa68b, 0xa68c), + (0xa68d, 0xa68e), + (0xa68f, 0xa690), + (0xa691, 0xa692), + (0xa693, 0xa694), + (0xa695, 0xa696), + (0xa697, 0xa698), + (0xa69f, 0xa6e6), + (0xa6f0, 0xa6f2), + (0xa717, 0xa720), + (0xa723, 0xa724), + (0xa725, 0xa726), + (0xa727, 0xa728), + (0xa729, 0xa72a), + (0xa72b, 0xa72c), + (0xa72d, 0xa72e), + (0xa72f, 0xa732), + (0xa733, 0xa734), + (0xa735, 0xa736), + (0xa737, 0xa738), + (0xa739, 0xa73a), + (0xa73b, 0xa73c), + (0xa73d, 0xa73e), + (0xa73f, 0xa740), + (0xa741, 0xa742), + (0xa743, 0xa744), + (0xa745, 0xa746), + (0xa747, 0xa748), + (0xa749, 0xa74a), + (0xa74b, 0xa74c), + (0xa74d, 0xa74e), + (0xa74f, 0xa750), + (0xa751, 0xa752), + (0xa753, 0xa754), + (0xa755, 0xa756), + (0xa757, 0xa758), + (0xa759, 0xa75a), + (0xa75b, 0xa75c), + (0xa75d, 0xa75e), + (0xa75f, 0xa760), + (0xa761, 0xa762), + (0xa763, 0xa764), + (0xa765, 0xa766), + (0xa767, 0xa768), + (0xa769, 0xa76a), + (0xa76b, 0xa76c), + (0xa76d, 0xa76e), + (0xa76f, 0xa770), + (0xa771, 0xa779), + (0xa77a, 0xa77b), + (0xa77c, 0xa77d), + (0xa77f, 0xa780), + (0xa781, 0xa782), + (0xa783, 0xa784), + (0xa785, 0xa786), + (0xa787, 0xa789), + (0xa78c, 0xa78d), + (0xa78e, 0xa78f), + (0xa791, 0xa792), + (0xa793, 0xa794), + (0xa7a1, 0xa7a2), + (0xa7a3, 0xa7a4), + (0xa7a5, 0xa7a6), + (0xa7a7, 0xa7a8), + (0xa7a9, 0xa7aa), + (0xa7fa, 0xa828), + (0xa840, 0xa874), + (0xa880, 0xa8c5), + (0xa8d0, 0xa8da), + (0xa8e0, 0xa8f8), + (0xa8fb, 0xa8fc), + (0xa900, 0xa92e), + (0xa930, 0xa954), + (0xa980, 0xa9c1), + (0xa9cf, 0xa9da), + (0xaa00, 0xaa37), + (0xaa40, 0xaa4e), + (0xaa50, 0xaa5a), + (0xaa60, 0xaa77), + (0xaa7a, 0xaa7c), + (0xaa80, 0xaac3), + (0xaadb, 0xaade), + (0xaae0, 0xaaf0), + (0xaaf2, 0xaaf7), + (0xab01, 0xab07), + (0xab09, 0xab0f), + (0xab11, 0xab17), + (0xab20, 0xab27), + (0xab28, 0xab2f), + (0xabc0, 0xabeb), + (0xabec, 0xabee), + (0xabf0, 0xabfa), + (0xac00, 0xd7a4), + (0xfa0e, 0xfa10), + (0xfa11, 0xfa12), + (0xfa13, 0xfa15), + (0xfa1f, 0xfa20), + (0xfa21, 0xfa22), + (0xfa23, 0xfa25), + (0xfa27, 0xfa2a), + (0xfb1e, 0xfb1f), + (0xfe20, 0xfe27), + (0xfe73, 0xfe74), + (0x10000, 0x1000c), + (0x1000d, 0x10027), + (0x10028, 0x1003b), + (0x1003c, 0x1003e), + (0x1003f, 0x1004e), + (0x10050, 0x1005e), + (0x10080, 0x100fb), + (0x101fd, 0x101fe), + (0x10280, 0x1029d), + (0x102a0, 0x102d1), + (0x10300, 0x1031f), + (0x10330, 0x10341), + (0x10342, 0x1034a), + (0x10380, 0x1039e), + (0x103a0, 0x103c4), + (0x103c8, 0x103d0), + (0x10428, 0x1049e), + (0x104a0, 0x104aa), + (0x10800, 0x10806), + (0x10808, 0x10809), + (0x1080a, 0x10836), + (0x10837, 0x10839), + (0x1083c, 0x1083d), + (0x1083f, 0x10856), + (0x10900, 0x10916), + (0x10920, 0x1093a), + (0x10980, 0x109b8), + (0x109be, 0x109c0), + (0x10a00, 0x10a04), + (0x10a05, 0x10a07), + (0x10a0c, 0x10a14), + (0x10a15, 0x10a18), + (0x10a19, 0x10a34), + (0x10a38, 0x10a3b), + (0x10a3f, 0x10a40), + (0x10a60, 0x10a7d), + (0x10b00, 0x10b36), + (0x10b40, 0x10b56), + (0x10b60, 0x10b73), + (0x10c00, 0x10c49), + (0x11000, 0x11047), + (0x11066, 0x11070), + (0x11080, 0x110bb), + (0x110d0, 0x110e9), + (0x110f0, 0x110fa), + (0x11100, 0x11135), + (0x11136, 0x11140), + (0x11180, 0x111c5), + (0x111d0, 0x111da), + (0x11680, 0x116b8), + (0x116c0, 0x116ca), + (0x12000, 0x1236f), + (0x13000, 0x1342f), + (0x16800, 0x16a39), + (0x16f00, 0x16f45), + (0x16f50, 0x16f7f), + (0x16f8f, 0x16fa0), + (0x1b000, 0x1b002), + (0x20000, 0x2a6d7), + (0x2a700, 0x2b735), + (0x2b740, 0x2b81e), + ), + 'CONTEXTJ': ( + (0x200c, 0x200e), + ), + 'CONTEXTO': ( + (0xb7, 0xb8), + (0x375, 0x376), + (0x5f3, 0x5f5), + (0x660, 0x66a), + (0x6f0, 0x6fa), + (0x30fb, 0x30fc), + ), +} diff --git a/pipenv/vendor/requests/packages/idna/intranges.py b/pipenv/vendor/requests/packages/idna/intranges.py new file mode 100644 index 00000000..ee8a175d --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/intranges.py @@ -0,0 +1,46 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect + +def intranges_from_list(list_): + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i+1 < len(sorted_list): + if sorted_list[i] == sorted_list[i+1]-1: + continue + current_range = sorted_list[last_write+1:i+1] + range_tuple = (current_range[0], current_range[-1] + 1) + ranges.append(range_tuple) + last_write = i + + return tuple(ranges) + + +def intranges_contain(int_, ranges): + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = (int_, int_) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = ranges[pos-1] + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = ranges[pos] + if left == int_: + return True + return False diff --git a/pipenv/vendor/requests/packages/idna/uts46data.py b/pipenv/vendor/requests/packages/idna/uts46data.py new file mode 100644 index 00000000..48da8408 --- /dev/null +++ b/pipenv/vendor/requests/packages/idna/uts46data.py @@ -0,0 +1,7633 @@ +# This file is automatically generated by tools/build-uts46data.py +# vim: set fileencoding=utf-8 : + +"""IDNA Mapping Table from UTS46.""" + + +def _seg_0(): + return [ + (0x0, '3'), + (0x1, '3'), + (0x2, '3'), + (0x3, '3'), + (0x4, '3'), + (0x5, '3'), + (0x6, '3'), + (0x7, '3'), + (0x8, '3'), + (0x9, '3'), + (0xA, '3'), + (0xB, '3'), + (0xC, '3'), + (0xD, '3'), + (0xE, '3'), + (0xF, '3'), + (0x10, '3'), + (0x11, '3'), + (0x12, '3'), + (0x13, '3'), + (0x14, '3'), + (0x15, '3'), + (0x16, '3'), + (0x17, '3'), + (0x18, '3'), + (0x19, '3'), + (0x1A, '3'), + (0x1B, '3'), + (0x1C, '3'), + (0x1D, '3'), + (0x1E, '3'), + (0x1F, '3'), + (0x20, '3'), + (0x21, '3'), + (0x22, '3'), + (0x23, '3'), + (0x24, '3'), + (0x25, '3'), + (0x26, '3'), + (0x27, '3'), + (0x28, '3'), + (0x29, '3'), + (0x2A, '3'), + (0x2B, '3'), + (0x2C, '3'), + (0x2D, 'V'), + (0x2E, 'V'), + (0x2F, '3'), + (0x30, 'V'), + (0x31, 'V'), + (0x32, 'V'), + (0x33, 'V'), + (0x34, 'V'), + (0x35, 'V'), + (0x36, 'V'), + (0x37, 'V'), + (0x38, 'V'), + (0x39, 'V'), + (0x3A, '3'), + (0x3B, '3'), + (0x3C, '3'), + (0x3D, '3'), + (0x3E, '3'), + (0x3F, '3'), + (0x40, '3'), + (0x41, 'M', u'a'), + (0x42, 'M', u'b'), + (0x43, 'M', u'c'), + (0x44, 'M', u'd'), + (0x45, 'M', u'e'), + (0x46, 'M', u'f'), + (0x47, 'M', u'g'), + (0x48, 'M', u'h'), + (0x49, 'M', u'i'), + (0x4A, 'M', u'j'), + (0x4B, 'M', u'k'), + (0x4C, 'M', u'l'), + (0x4D, 'M', u'm'), + (0x4E, 'M', u'n'), + (0x4F, 'M', u'o'), + (0x50, 'M', u'p'), + (0x51, 'M', u'q'), + (0x52, 'M', u'r'), + (0x53, 'M', u's'), + (0x54, 'M', u't'), + (0x55, 'M', u'u'), + (0x56, 'M', u'v'), + (0x57, 'M', u'w'), + (0x58, 'M', u'x'), + (0x59, 'M', u'y'), + (0x5A, 'M', u'z'), + (0x5B, '3'), + (0x5C, '3'), + (0x5D, '3'), + (0x5E, '3'), + (0x5F, '3'), + (0x60, '3'), + (0x61, 'V'), + (0x62, 'V'), + (0x63, 'V'), + ] + +def _seg_1(): + return [ + (0x64, 'V'), + (0x65, 'V'), + (0x66, 'V'), + (0x67, 'V'), + (0x68, 'V'), + (0x69, 'V'), + (0x6A, 'V'), + (0x6B, 'V'), + (0x6C, 'V'), + (0x6D, 'V'), + (0x6E, 'V'), + (0x6F, 'V'), + (0x70, 'V'), + (0x71, 'V'), + (0x72, 'V'), + (0x73, 'V'), + (0x74, 'V'), + (0x75, 'V'), + (0x76, 'V'), + (0x77, 'V'), + (0x78, 'V'), + (0x79, 'V'), + (0x7A, 'V'), + (0x7B, '3'), + (0x7C, '3'), + (0x7D, '3'), + (0x7E, '3'), + (0x7F, '3'), + (0x80, 'X'), + (0x81, 'X'), + (0x82, 'X'), + (0x83, 'X'), + (0x84, 'X'), + (0x85, 'X'), + (0x86, 'X'), + (0x87, 'X'), + (0x88, 'X'), + (0x89, 'X'), + (0x8A, 'X'), + (0x8B, 'X'), + (0x8C, 'X'), + (0x8D, 'X'), + (0x8E, 'X'), + (0x8F, 'X'), + (0x90, 'X'), + (0x91, 'X'), + (0x92, 'X'), + (0x93, 'X'), + (0x94, 'X'), + (0x95, 'X'), + (0x96, 'X'), + (0x97, 'X'), + (0x98, 'X'), + (0x99, 'X'), + (0x9A, 'X'), + (0x9B, 'X'), + (0x9C, 'X'), + (0x9D, 'X'), + (0x9E, 'X'), + (0x9F, 'X'), + (0xA0, '3', u' '), + (0xA1, 'V'), + (0xA2, 'V'), + (0xA3, 'V'), + (0xA4, 'V'), + (0xA5, 'V'), + (0xA6, 'V'), + (0xA7, 'V'), + (0xA8, '3', u' ̈'), + (0xA9, 'V'), + (0xAA, 'M', u'a'), + (0xAB, 'V'), + (0xAC, 'V'), + (0xAD, 'I'), + (0xAE, 'V'), + (0xAF, '3', u' Ì„'), + (0xB0, 'V'), + (0xB1, 'V'), + (0xB2, 'M', u'2'), + (0xB3, 'M', u'3'), + (0xB4, '3', u' Ì'), + (0xB5, 'M', u'μ'), + (0xB6, 'V'), + (0xB7, 'V'), + (0xB8, '3', u' ̧'), + (0xB9, 'M', u'1'), + (0xBA, 'M', u'o'), + (0xBB, 'V'), + (0xBC, 'M', u'1â„4'), + (0xBD, 'M', u'1â„2'), + (0xBE, 'M', u'3â„4'), + (0xBF, 'V'), + (0xC0, 'M', u'à'), + (0xC1, 'M', u'á'), + (0xC2, 'M', u'â'), + (0xC3, 'M', u'ã'), + (0xC4, 'M', u'ä'), + (0xC5, 'M', u'Ã¥'), + (0xC6, 'M', u'æ'), + (0xC7, 'M', u'ç'), + ] + +def _seg_2(): + return [ + (0xC8, 'M', u'è'), + (0xC9, 'M', u'é'), + (0xCA, 'M', u'ê'), + (0xCB, 'M', u'ë'), + (0xCC, 'M', u'ì'), + (0xCD, 'M', u'í'), + (0xCE, 'M', u'î'), + (0xCF, 'M', u'ï'), + (0xD0, 'M', u'ð'), + (0xD1, 'M', u'ñ'), + (0xD2, 'M', u'ò'), + (0xD3, 'M', u'ó'), + (0xD4, 'M', u'ô'), + (0xD5, 'M', u'õ'), + (0xD6, 'M', u'ö'), + (0xD7, 'V'), + (0xD8, 'M', u'ø'), + (0xD9, 'M', u'ù'), + (0xDA, 'M', u'ú'), + (0xDB, 'M', u'û'), + (0xDC, 'M', u'ü'), + (0xDD, 'M', u'ý'), + (0xDE, 'M', u'þ'), + (0xDF, 'D', u'ss'), + (0xE0, 'V'), + (0xE1, 'V'), + (0xE2, 'V'), + (0xE3, 'V'), + (0xE4, 'V'), + (0xE5, 'V'), + (0xE6, 'V'), + (0xE7, 'V'), + (0xE8, 'V'), + (0xE9, 'V'), + (0xEA, 'V'), + (0xEB, 'V'), + (0xEC, 'V'), + (0xED, 'V'), + (0xEE, 'V'), + (0xEF, 'V'), + (0xF0, 'V'), + (0xF1, 'V'), + (0xF2, 'V'), + (0xF3, 'V'), + (0xF4, 'V'), + (0xF5, 'V'), + (0xF6, 'V'), + (0xF7, 'V'), + (0xF8, 'V'), + (0xF9, 'V'), + (0xFA, 'V'), + (0xFB, 'V'), + (0xFC, 'V'), + (0xFD, 'V'), + (0xFE, 'V'), + (0xFF, 'V'), + (0x100, 'M', u'Ä'), + (0x101, 'V'), + (0x102, 'M', u'ă'), + (0x103, 'V'), + (0x104, 'M', u'Ä…'), + (0x105, 'V'), + (0x106, 'M', u'ć'), + (0x107, 'V'), + (0x108, 'M', u'ĉ'), + (0x109, 'V'), + (0x10A, 'M', u'Ä‹'), + (0x10B, 'V'), + (0x10C, 'M', u'Ä'), + (0x10D, 'V'), + (0x10E, 'M', u'Ä'), + (0x10F, 'V'), + (0x110, 'M', u'Ä‘'), + (0x111, 'V'), + (0x112, 'M', u'Ä“'), + (0x113, 'V'), + (0x114, 'M', u'Ä•'), + (0x115, 'V'), + (0x116, 'M', u'Ä—'), + (0x117, 'V'), + (0x118, 'M', u'Ä™'), + (0x119, 'V'), + (0x11A, 'M', u'Ä›'), + (0x11B, 'V'), + (0x11C, 'M', u'Ä'), + (0x11D, 'V'), + (0x11E, 'M', u'ÄŸ'), + (0x11F, 'V'), + (0x120, 'M', u'Ä¡'), + (0x121, 'V'), + (0x122, 'M', u'Ä£'), + (0x123, 'V'), + (0x124, 'M', u'Ä¥'), + (0x125, 'V'), + (0x126, 'M', u'ħ'), + (0x127, 'V'), + (0x128, 'M', u'Ä©'), + (0x129, 'V'), + (0x12A, 'M', u'Ä«'), + (0x12B, 'V'), + ] + +def _seg_3(): + return [ + (0x12C, 'M', u'Ä­'), + (0x12D, 'V'), + (0x12E, 'M', u'į'), + (0x12F, 'V'), + (0x130, 'M', u'i̇'), + (0x131, 'V'), + (0x132, 'M', u'ij'), + (0x134, 'M', u'ĵ'), + (0x135, 'V'), + (0x136, 'M', u'Ä·'), + (0x137, 'V'), + (0x139, 'M', u'ĺ'), + (0x13A, 'V'), + (0x13B, 'M', u'ļ'), + (0x13C, 'V'), + (0x13D, 'M', u'ľ'), + (0x13E, 'V'), + (0x13F, 'M', u'l·'), + (0x141, 'M', u'Å‚'), + (0x142, 'V'), + (0x143, 'M', u'Å„'), + (0x144, 'V'), + (0x145, 'M', u'ņ'), + (0x146, 'V'), + (0x147, 'M', u'ň'), + (0x148, 'V'), + (0x149, 'M', u'ʼn'), + (0x14A, 'M', u'Å‹'), + (0x14B, 'V'), + (0x14C, 'M', u'Å'), + (0x14D, 'V'), + (0x14E, 'M', u'Å'), + (0x14F, 'V'), + (0x150, 'M', u'Å‘'), + (0x151, 'V'), + (0x152, 'M', u'Å“'), + (0x153, 'V'), + (0x154, 'M', u'Å•'), + (0x155, 'V'), + (0x156, 'M', u'Å—'), + (0x157, 'V'), + (0x158, 'M', u'Å™'), + (0x159, 'V'), + (0x15A, 'M', u'Å›'), + (0x15B, 'V'), + (0x15C, 'M', u'Å'), + (0x15D, 'V'), + (0x15E, 'M', u'ÅŸ'), + (0x15F, 'V'), + (0x160, 'M', u'Å¡'), + (0x161, 'V'), + (0x162, 'M', u'Å£'), + (0x163, 'V'), + (0x164, 'M', u'Å¥'), + (0x165, 'V'), + (0x166, 'M', u'ŧ'), + (0x167, 'V'), + (0x168, 'M', u'Å©'), + (0x169, 'V'), + (0x16A, 'M', u'Å«'), + (0x16B, 'V'), + (0x16C, 'M', u'Å­'), + (0x16D, 'V'), + (0x16E, 'M', u'ů'), + (0x16F, 'V'), + (0x170, 'M', u'ű'), + (0x171, 'V'), + (0x172, 'M', u'ų'), + (0x173, 'V'), + (0x174, 'M', u'ŵ'), + (0x175, 'V'), + (0x176, 'M', u'Å·'), + (0x177, 'V'), + (0x178, 'M', u'ÿ'), + (0x179, 'M', u'ź'), + (0x17A, 'V'), + (0x17B, 'M', u'ż'), + (0x17C, 'V'), + (0x17D, 'M', u'ž'), + (0x17E, 'V'), + (0x17F, 'M', u's'), + (0x180, 'V'), + (0x181, 'M', u'É“'), + (0x182, 'M', u'ƃ'), + (0x183, 'V'), + (0x184, 'M', u'Æ…'), + (0x185, 'V'), + (0x186, 'M', u'É”'), + (0x187, 'M', u'ƈ'), + (0x188, 'V'), + (0x189, 'M', u'É–'), + (0x18A, 'M', u'É—'), + (0x18B, 'M', u'ÆŒ'), + (0x18C, 'V'), + (0x18E, 'M', u'Ç'), + (0x18F, 'M', u'É™'), + (0x190, 'M', u'É›'), + (0x191, 'M', u'Æ’'), + (0x192, 'V'), + (0x193, 'M', u'É '), + ] + +def _seg_4(): + return [ + (0x194, 'M', u'É£'), + (0x195, 'V'), + (0x196, 'M', u'É©'), + (0x197, 'M', u'ɨ'), + (0x198, 'M', u'Æ™'), + (0x199, 'V'), + (0x19C, 'M', u'ɯ'), + (0x19D, 'M', u'ɲ'), + (0x19E, 'V'), + (0x19F, 'M', u'ɵ'), + (0x1A0, 'M', u'Æ¡'), + (0x1A1, 'V'), + (0x1A2, 'M', u'Æ£'), + (0x1A3, 'V'), + (0x1A4, 'M', u'Æ¥'), + (0x1A5, 'V'), + (0x1A6, 'M', u'Ê€'), + (0x1A7, 'M', u'ƨ'), + (0x1A8, 'V'), + (0x1A9, 'M', u'ʃ'), + (0x1AA, 'V'), + (0x1AC, 'M', u'Æ­'), + (0x1AD, 'V'), + (0x1AE, 'M', u'ʈ'), + (0x1AF, 'M', u'ư'), + (0x1B0, 'V'), + (0x1B1, 'M', u'ÊŠ'), + (0x1B2, 'M', u'Ê‹'), + (0x1B3, 'M', u'Æ´'), + (0x1B4, 'V'), + (0x1B5, 'M', u'ƶ'), + (0x1B6, 'V'), + (0x1B7, 'M', u'Ê’'), + (0x1B8, 'M', u'ƹ'), + (0x1B9, 'V'), + (0x1BC, 'M', u'ƽ'), + (0x1BD, 'V'), + (0x1C4, 'M', u'dž'), + (0x1C7, 'M', u'lj'), + (0x1CA, 'M', u'nj'), + (0x1CD, 'M', u'ÇŽ'), + (0x1CE, 'V'), + (0x1CF, 'M', u'Ç'), + (0x1D0, 'V'), + (0x1D1, 'M', u'Ç’'), + (0x1D2, 'V'), + (0x1D3, 'M', u'Ç”'), + (0x1D4, 'V'), + (0x1D5, 'M', u'Ç–'), + (0x1D6, 'V'), + (0x1D7, 'M', u'ǘ'), + (0x1D8, 'V'), + (0x1D9, 'M', u'Çš'), + (0x1DA, 'V'), + (0x1DB, 'M', u'Çœ'), + (0x1DC, 'V'), + (0x1DE, 'M', u'ÇŸ'), + (0x1DF, 'V'), + (0x1E0, 'M', u'Ç¡'), + (0x1E1, 'V'), + (0x1E2, 'M', u'Ç£'), + (0x1E3, 'V'), + (0x1E4, 'M', u'Ç¥'), + (0x1E5, 'V'), + (0x1E6, 'M', u'ǧ'), + (0x1E7, 'V'), + (0x1E8, 'M', u'Ç©'), + (0x1E9, 'V'), + (0x1EA, 'M', u'Ç«'), + (0x1EB, 'V'), + (0x1EC, 'M', u'Ç­'), + (0x1ED, 'V'), + (0x1EE, 'M', u'ǯ'), + (0x1EF, 'V'), + (0x1F1, 'M', u'dz'), + (0x1F4, 'M', u'ǵ'), + (0x1F5, 'V'), + (0x1F6, 'M', u'Æ•'), + (0x1F7, 'M', u'Æ¿'), + (0x1F8, 'M', u'ǹ'), + (0x1F9, 'V'), + (0x1FA, 'M', u'Ç»'), + (0x1FB, 'V'), + (0x1FC, 'M', u'ǽ'), + (0x1FD, 'V'), + (0x1FE, 'M', u'Ç¿'), + (0x1FF, 'V'), + (0x200, 'M', u'È'), + (0x201, 'V'), + (0x202, 'M', u'ȃ'), + (0x203, 'V'), + (0x204, 'M', u'È…'), + (0x205, 'V'), + (0x206, 'M', u'ȇ'), + (0x207, 'V'), + (0x208, 'M', u'ȉ'), + (0x209, 'V'), + (0x20A, 'M', u'È‹'), + (0x20B, 'V'), + (0x20C, 'M', u'È'), + ] + +def _seg_5(): + return [ + (0x20D, 'V'), + (0x20E, 'M', u'È'), + (0x20F, 'V'), + (0x210, 'M', u'È‘'), + (0x211, 'V'), + (0x212, 'M', u'È“'), + (0x213, 'V'), + (0x214, 'M', u'È•'), + (0x215, 'V'), + (0x216, 'M', u'È—'), + (0x217, 'V'), + (0x218, 'M', u'È™'), + (0x219, 'V'), + (0x21A, 'M', u'È›'), + (0x21B, 'V'), + (0x21C, 'M', u'È'), + (0x21D, 'V'), + (0x21E, 'M', u'ÈŸ'), + (0x21F, 'V'), + (0x220, 'M', u'Æž'), + (0x221, 'V'), + (0x222, 'M', u'È£'), + (0x223, 'V'), + (0x224, 'M', u'È¥'), + (0x225, 'V'), + (0x226, 'M', u'ȧ'), + (0x227, 'V'), + (0x228, 'M', u'È©'), + (0x229, 'V'), + (0x22A, 'M', u'È«'), + (0x22B, 'V'), + (0x22C, 'M', u'È­'), + (0x22D, 'V'), + (0x22E, 'M', u'ȯ'), + (0x22F, 'V'), + (0x230, 'M', u'ȱ'), + (0x231, 'V'), + (0x232, 'M', u'ȳ'), + (0x233, 'V'), + (0x23A, 'M', u'â±¥'), + (0x23B, 'M', u'ȼ'), + (0x23C, 'V'), + (0x23D, 'M', u'Æš'), + (0x23E, 'M', u'ⱦ'), + (0x23F, 'V'), + (0x241, 'M', u'É‚'), + (0x242, 'V'), + (0x243, 'M', u'Æ€'), + (0x244, 'M', u'ʉ'), + (0x245, 'M', u'ÊŒ'), + (0x246, 'M', u'ɇ'), + (0x247, 'V'), + (0x248, 'M', u'ɉ'), + (0x249, 'V'), + (0x24A, 'M', u'É‹'), + (0x24B, 'V'), + (0x24C, 'M', u'É'), + (0x24D, 'V'), + (0x24E, 'M', u'É'), + (0x24F, 'V'), + (0x2B0, 'M', u'h'), + (0x2B1, 'M', u'ɦ'), + (0x2B2, 'M', u'j'), + (0x2B3, 'M', u'r'), + (0x2B4, 'M', u'ɹ'), + (0x2B5, 'M', u'É»'), + (0x2B6, 'M', u'Ê'), + (0x2B7, 'M', u'w'), + (0x2B8, 'M', u'y'), + (0x2B9, 'V'), + (0x2D8, '3', u' ̆'), + (0x2D9, '3', u' ̇'), + (0x2DA, '3', u' ÌŠ'), + (0x2DB, '3', u' ̨'), + (0x2DC, '3', u' ̃'), + (0x2DD, '3', u' Ì‹'), + (0x2DE, 'V'), + (0x2E0, 'M', u'É£'), + (0x2E1, 'M', u'l'), + (0x2E2, 'M', u's'), + (0x2E3, 'M', u'x'), + (0x2E4, 'M', u'Ê•'), + (0x2E5, 'V'), + (0x340, 'M', u'Ì€'), + (0x341, 'M', u'Ì'), + (0x342, 'V'), + (0x343, 'M', u'Ì“'), + (0x344, 'M', u'̈Ì'), + (0x345, 'M', u'ι'), + (0x346, 'V'), + (0x34F, 'I'), + (0x350, 'V'), + (0x370, 'M', u'ͱ'), + (0x371, 'V'), + (0x372, 'M', u'ͳ'), + (0x373, 'V'), + (0x374, 'M', u'ʹ'), + (0x375, 'V'), + (0x376, 'M', u'Í·'), + (0x377, 'V'), + ] + +def _seg_6(): + return [ + (0x378, 'X'), + (0x37A, '3', u' ι'), + (0x37B, 'V'), + (0x37E, '3', u';'), + (0x37F, 'X'), + (0x384, '3', u' Ì'), + (0x385, '3', u' ̈Ì'), + (0x386, 'M', u'ά'), + (0x387, 'M', u'·'), + (0x388, 'M', u'έ'), + (0x389, 'M', u'ή'), + (0x38A, 'M', u'ί'), + (0x38B, 'X'), + (0x38C, 'M', u'ÏŒ'), + (0x38D, 'X'), + (0x38E, 'M', u'Ï'), + (0x38F, 'M', u'ÏŽ'), + (0x390, 'V'), + (0x391, 'M', u'α'), + (0x392, 'M', u'β'), + (0x393, 'M', u'γ'), + (0x394, 'M', u'δ'), + (0x395, 'M', u'ε'), + (0x396, 'M', u'ζ'), + (0x397, 'M', u'η'), + (0x398, 'M', u'θ'), + (0x399, 'M', u'ι'), + (0x39A, 'M', u'κ'), + (0x39B, 'M', u'λ'), + (0x39C, 'M', u'μ'), + (0x39D, 'M', u'ν'), + (0x39E, 'M', u'ξ'), + (0x39F, 'M', u'ο'), + (0x3A0, 'M', u'Ï€'), + (0x3A1, 'M', u'Ï'), + (0x3A2, 'X'), + (0x3A3, 'M', u'σ'), + (0x3A4, 'M', u'Ï„'), + (0x3A5, 'M', u'Ï…'), + (0x3A6, 'M', u'φ'), + (0x3A7, 'M', u'χ'), + (0x3A8, 'M', u'ψ'), + (0x3A9, 'M', u'ω'), + (0x3AA, 'M', u'ÏŠ'), + (0x3AB, 'M', u'Ï‹'), + (0x3AC, 'V'), + (0x3C2, 'D', u'σ'), + (0x3C3, 'V'), + (0x3CF, 'M', u'Ï—'), + (0x3D0, 'M', u'β'), + (0x3D1, 'M', u'θ'), + (0x3D2, 'M', u'Ï…'), + (0x3D3, 'M', u'Ï'), + (0x3D4, 'M', u'Ï‹'), + (0x3D5, 'M', u'φ'), + (0x3D6, 'M', u'Ï€'), + (0x3D7, 'V'), + (0x3D8, 'M', u'Ï™'), + (0x3D9, 'V'), + (0x3DA, 'M', u'Ï›'), + (0x3DB, 'V'), + (0x3DC, 'M', u'Ï'), + (0x3DD, 'V'), + (0x3DE, 'M', u'ÏŸ'), + (0x3DF, 'V'), + (0x3E0, 'M', u'Ï¡'), + (0x3E1, 'V'), + (0x3E2, 'M', u'Ï£'), + (0x3E3, 'V'), + (0x3E4, 'M', u'Ï¥'), + (0x3E5, 'V'), + (0x3E6, 'M', u'ϧ'), + (0x3E7, 'V'), + (0x3E8, 'M', u'Ï©'), + (0x3E9, 'V'), + (0x3EA, 'M', u'Ï«'), + (0x3EB, 'V'), + (0x3EC, 'M', u'Ï­'), + (0x3ED, 'V'), + (0x3EE, 'M', u'ϯ'), + (0x3EF, 'V'), + (0x3F0, 'M', u'κ'), + (0x3F1, 'M', u'Ï'), + (0x3F2, 'M', u'σ'), + (0x3F3, 'V'), + (0x3F4, 'M', u'θ'), + (0x3F5, 'M', u'ε'), + (0x3F6, 'V'), + (0x3F7, 'M', u'ϸ'), + (0x3F8, 'V'), + (0x3F9, 'M', u'σ'), + (0x3FA, 'M', u'Ï»'), + (0x3FB, 'V'), + (0x3FD, 'M', u'Í»'), + (0x3FE, 'M', u'ͼ'), + (0x3FF, 'M', u'ͽ'), + (0x400, 'M', u'Ñ'), + (0x401, 'M', u'Ñ‘'), + (0x402, 'M', u'Ñ’'), + (0x403, 'M', u'Ñ“'), + ] + +def _seg_7(): + return [ + (0x404, 'M', u'Ñ”'), + (0x405, 'M', u'Ñ•'), + (0x406, 'M', u'Ñ–'), + (0x407, 'M', u'Ñ—'), + (0x408, 'M', u'ј'), + (0x409, 'M', u'Ñ™'), + (0x40A, 'M', u'Ñš'), + (0x40B, 'M', u'Ñ›'), + (0x40C, 'M', u'Ñœ'), + (0x40D, 'M', u'Ñ'), + (0x40E, 'M', u'Ñž'), + (0x40F, 'M', u'ÑŸ'), + (0x410, 'M', u'а'), + (0x411, 'M', u'б'), + (0x412, 'M', u'в'), + (0x413, 'M', u'г'), + (0x414, 'M', u'д'), + (0x415, 'M', u'е'), + (0x416, 'M', u'ж'), + (0x417, 'M', u'з'), + (0x418, 'M', u'и'), + (0x419, 'M', u'й'), + (0x41A, 'M', u'к'), + (0x41B, 'M', u'л'), + (0x41C, 'M', u'м'), + (0x41D, 'M', u'н'), + (0x41E, 'M', u'о'), + (0x41F, 'M', u'п'), + (0x420, 'M', u'Ñ€'), + (0x421, 'M', u'Ñ'), + (0x422, 'M', u'Ñ‚'), + (0x423, 'M', u'у'), + (0x424, 'M', u'Ñ„'), + (0x425, 'M', u'Ñ…'), + (0x426, 'M', u'ц'), + (0x427, 'M', u'ч'), + (0x428, 'M', u'ш'), + (0x429, 'M', u'щ'), + (0x42A, 'M', u'ÑŠ'), + (0x42B, 'M', u'Ñ‹'), + (0x42C, 'M', u'ÑŒ'), + (0x42D, 'M', u'Ñ'), + (0x42E, 'M', u'ÑŽ'), + (0x42F, 'M', u'Ñ'), + (0x430, 'V'), + (0x460, 'M', u'Ñ¡'), + (0x461, 'V'), + (0x462, 'M', u'Ñ£'), + (0x463, 'V'), + (0x464, 'M', u'Ñ¥'), + (0x465, 'V'), + (0x466, 'M', u'ѧ'), + (0x467, 'V'), + (0x468, 'M', u'Ñ©'), + (0x469, 'V'), + (0x46A, 'M', u'Ñ«'), + (0x46B, 'V'), + (0x46C, 'M', u'Ñ­'), + (0x46D, 'V'), + (0x46E, 'M', u'ѯ'), + (0x46F, 'V'), + (0x470, 'M', u'ѱ'), + (0x471, 'V'), + (0x472, 'M', u'ѳ'), + (0x473, 'V'), + (0x474, 'M', u'ѵ'), + (0x475, 'V'), + (0x476, 'M', u'Ñ·'), + (0x477, 'V'), + (0x478, 'M', u'ѹ'), + (0x479, 'V'), + (0x47A, 'M', u'Ñ»'), + (0x47B, 'V'), + (0x47C, 'M', u'ѽ'), + (0x47D, 'V'), + (0x47E, 'M', u'Ñ¿'), + (0x47F, 'V'), + (0x480, 'M', u'Ò'), + (0x481, 'V'), + (0x48A, 'M', u'Ò‹'), + (0x48B, 'V'), + (0x48C, 'M', u'Ò'), + (0x48D, 'V'), + (0x48E, 'M', u'Ò'), + (0x48F, 'V'), + (0x490, 'M', u'Ò‘'), + (0x491, 'V'), + (0x492, 'M', u'Ò“'), + (0x493, 'V'), + (0x494, 'M', u'Ò•'), + (0x495, 'V'), + (0x496, 'M', u'Ò—'), + (0x497, 'V'), + (0x498, 'M', u'Ò™'), + (0x499, 'V'), + (0x49A, 'M', u'Ò›'), + (0x49B, 'V'), + (0x49C, 'M', u'Ò'), + (0x49D, 'V'), + (0x49E, 'M', u'ÒŸ'), + ] + +def _seg_8(): + return [ + (0x49F, 'V'), + (0x4A0, 'M', u'Ò¡'), + (0x4A1, 'V'), + (0x4A2, 'M', u'Ò£'), + (0x4A3, 'V'), + (0x4A4, 'M', u'Ò¥'), + (0x4A5, 'V'), + (0x4A6, 'M', u'Ò§'), + (0x4A7, 'V'), + (0x4A8, 'M', u'Ò©'), + (0x4A9, 'V'), + (0x4AA, 'M', u'Ò«'), + (0x4AB, 'V'), + (0x4AC, 'M', u'Ò­'), + (0x4AD, 'V'), + (0x4AE, 'M', u'Ò¯'), + (0x4AF, 'V'), + (0x4B0, 'M', u'Ò±'), + (0x4B1, 'V'), + (0x4B2, 'M', u'Ò³'), + (0x4B3, 'V'), + (0x4B4, 'M', u'Òµ'), + (0x4B5, 'V'), + (0x4B6, 'M', u'Ò·'), + (0x4B7, 'V'), + (0x4B8, 'M', u'Ò¹'), + (0x4B9, 'V'), + (0x4BA, 'M', u'Ò»'), + (0x4BB, 'V'), + (0x4BC, 'M', u'Ò½'), + (0x4BD, 'V'), + (0x4BE, 'M', u'Ò¿'), + (0x4BF, 'V'), + (0x4C0, 'X'), + (0x4C1, 'M', u'Ó‚'), + (0x4C2, 'V'), + (0x4C3, 'M', u'Ó„'), + (0x4C4, 'V'), + (0x4C5, 'M', u'Ó†'), + (0x4C6, 'V'), + (0x4C7, 'M', u'Óˆ'), + (0x4C8, 'V'), + (0x4C9, 'M', u'ÓŠ'), + (0x4CA, 'V'), + (0x4CB, 'M', u'ÓŒ'), + (0x4CC, 'V'), + (0x4CD, 'M', u'ÓŽ'), + (0x4CE, 'V'), + (0x4D0, 'M', u'Ó‘'), + (0x4D1, 'V'), + (0x4D2, 'M', u'Ó“'), + (0x4D3, 'V'), + (0x4D4, 'M', u'Ó•'), + (0x4D5, 'V'), + (0x4D6, 'M', u'Ó—'), + (0x4D7, 'V'), + (0x4D8, 'M', u'Ó™'), + (0x4D9, 'V'), + (0x4DA, 'M', u'Ó›'), + (0x4DB, 'V'), + (0x4DC, 'M', u'Ó'), + (0x4DD, 'V'), + (0x4DE, 'M', u'ÓŸ'), + (0x4DF, 'V'), + (0x4E0, 'M', u'Ó¡'), + (0x4E1, 'V'), + (0x4E2, 'M', u'Ó£'), + (0x4E3, 'V'), + (0x4E4, 'M', u'Ó¥'), + (0x4E5, 'V'), + (0x4E6, 'M', u'Ó§'), + (0x4E7, 'V'), + (0x4E8, 'M', u'Ó©'), + (0x4E9, 'V'), + (0x4EA, 'M', u'Ó«'), + (0x4EB, 'V'), + (0x4EC, 'M', u'Ó­'), + (0x4ED, 'V'), + (0x4EE, 'M', u'Ó¯'), + (0x4EF, 'V'), + (0x4F0, 'M', u'Ó±'), + (0x4F1, 'V'), + (0x4F2, 'M', u'Ó³'), + (0x4F3, 'V'), + (0x4F4, 'M', u'Óµ'), + (0x4F5, 'V'), + (0x4F6, 'M', u'Ó·'), + (0x4F7, 'V'), + (0x4F8, 'M', u'Ó¹'), + (0x4F9, 'V'), + (0x4FA, 'M', u'Ó»'), + (0x4FB, 'V'), + (0x4FC, 'M', u'Ó½'), + (0x4FD, 'V'), + (0x4FE, 'M', u'Ó¿'), + (0x4FF, 'V'), + (0x500, 'M', u'Ô'), + (0x501, 'V'), + (0x502, 'M', u'Ôƒ'), + (0x503, 'V'), + ] + +def _seg_9(): + return [ + (0x504, 'M', u'Ô…'), + (0x505, 'V'), + (0x506, 'M', u'Ô‡'), + (0x507, 'V'), + (0x508, 'M', u'Ô‰'), + (0x509, 'V'), + (0x50A, 'M', u'Ô‹'), + (0x50B, 'V'), + (0x50C, 'M', u'Ô'), + (0x50D, 'V'), + (0x50E, 'M', u'Ô'), + (0x50F, 'V'), + (0x510, 'M', u'Ô‘'), + (0x511, 'V'), + (0x512, 'M', u'Ô“'), + (0x513, 'V'), + (0x514, 'M', u'Ô•'), + (0x515, 'V'), + (0x516, 'M', u'Ô—'), + (0x517, 'V'), + (0x518, 'M', u'Ô™'), + (0x519, 'V'), + (0x51A, 'M', u'Ô›'), + (0x51B, 'V'), + (0x51C, 'M', u'Ô'), + (0x51D, 'V'), + (0x51E, 'M', u'ÔŸ'), + (0x51F, 'V'), + (0x520, 'M', u'Ô¡'), + (0x521, 'V'), + (0x522, 'M', u'Ô£'), + (0x523, 'V'), + (0x524, 'M', u'Ô¥'), + (0x525, 'V'), + (0x526, 'M', u'Ô§'), + (0x527, 'V'), + (0x528, 'X'), + (0x531, 'M', u'Õ¡'), + (0x532, 'M', u'Õ¢'), + (0x533, 'M', u'Õ£'), + (0x534, 'M', u'Õ¤'), + (0x535, 'M', u'Õ¥'), + (0x536, 'M', u'Õ¦'), + (0x537, 'M', u'Õ§'), + (0x538, 'M', u'Õ¨'), + (0x539, 'M', u'Õ©'), + (0x53A, 'M', u'Õª'), + (0x53B, 'M', u'Õ«'), + (0x53C, 'M', u'Õ¬'), + (0x53D, 'M', u'Õ­'), + (0x53E, 'M', u'Õ®'), + (0x53F, 'M', u'Õ¯'), + (0x540, 'M', u'Õ°'), + (0x541, 'M', u'Õ±'), + (0x542, 'M', u'Õ²'), + (0x543, 'M', u'Õ³'), + (0x544, 'M', u'Õ´'), + (0x545, 'M', u'Õµ'), + (0x546, 'M', u'Õ¶'), + (0x547, 'M', u'Õ·'), + (0x548, 'M', u'Õ¸'), + (0x549, 'M', u'Õ¹'), + (0x54A, 'M', u'Õº'), + (0x54B, 'M', u'Õ»'), + (0x54C, 'M', u'Õ¼'), + (0x54D, 'M', u'Õ½'), + (0x54E, 'M', u'Õ¾'), + (0x54F, 'M', u'Õ¿'), + (0x550, 'M', u'Ö€'), + (0x551, 'M', u'Ö'), + (0x552, 'M', u'Ö‚'), + (0x553, 'M', u'Öƒ'), + (0x554, 'M', u'Ö„'), + (0x555, 'M', u'Ö…'), + (0x556, 'M', u'Ö†'), + (0x557, 'X'), + (0x559, 'V'), + (0x560, 'X'), + (0x561, 'V'), + (0x587, 'M', u'Õ¥Ö‚'), + (0x588, 'X'), + (0x589, 'V'), + (0x58B, 'X'), + (0x58F, 'V'), + (0x590, 'X'), + (0x591, 'V'), + (0x5C8, 'X'), + (0x5D0, 'V'), + (0x5EB, 'X'), + (0x5F0, 'V'), + (0x5F5, 'X'), + (0x606, 'V'), + (0x61C, 'X'), + (0x61E, 'V'), + (0x675, 'M', u'اٴ'), + (0x676, 'M', u'وٴ'), + (0x677, 'M', u'Û‡Ù´'), + (0x678, 'M', u'يٴ'), + (0x679, 'V'), + (0x6DD, 'X'), + ] + +def _seg_10(): + return [ + (0x6DE, 'V'), + (0x70E, 'X'), + (0x710, 'V'), + (0x74B, 'X'), + (0x74D, 'V'), + (0x7B2, 'X'), + (0x7C0, 'V'), + (0x7FB, 'X'), + (0x800, 'V'), + (0x82E, 'X'), + (0x830, 'V'), + (0x83F, 'X'), + (0x840, 'V'), + (0x85C, 'X'), + (0x85E, 'V'), + (0x85F, 'X'), + (0x8A0, 'V'), + (0x8A1, 'X'), + (0x8A2, 'V'), + (0x8AD, 'X'), + (0x8E4, 'V'), + (0x8FF, 'X'), + (0x900, 'V'), + (0x958, 'M', u'क़'), + (0x959, 'M', u'ख़'), + (0x95A, 'M', u'ग़'), + (0x95B, 'M', u'ज़'), + (0x95C, 'M', u'ड़'), + (0x95D, 'M', u'ढ़'), + (0x95E, 'M', u'फ़'), + (0x95F, 'M', u'य़'), + (0x960, 'V'), + (0x978, 'X'), + (0x979, 'V'), + (0x980, 'X'), + (0x981, 'V'), + (0x984, 'X'), + (0x985, 'V'), + (0x98D, 'X'), + (0x98F, 'V'), + (0x991, 'X'), + (0x993, 'V'), + (0x9A9, 'X'), + (0x9AA, 'V'), + (0x9B1, 'X'), + (0x9B2, 'V'), + (0x9B3, 'X'), + (0x9B6, 'V'), + (0x9BA, 'X'), + (0x9BC, 'V'), + (0x9C5, 'X'), + (0x9C7, 'V'), + (0x9C9, 'X'), + (0x9CB, 'V'), + (0x9CF, 'X'), + (0x9D7, 'V'), + (0x9D8, 'X'), + (0x9DC, 'M', u'ড়'), + (0x9DD, 'M', u'ঢ়'), + (0x9DE, 'X'), + (0x9DF, 'M', u'য়'), + (0x9E0, 'V'), + (0x9E4, 'X'), + (0x9E6, 'V'), + (0x9FC, 'X'), + (0xA01, 'V'), + (0xA04, 'X'), + (0xA05, 'V'), + (0xA0B, 'X'), + (0xA0F, 'V'), + (0xA11, 'X'), + (0xA13, 'V'), + (0xA29, 'X'), + (0xA2A, 'V'), + (0xA31, 'X'), + (0xA32, 'V'), + (0xA33, 'M', u'ਲ਼'), + (0xA34, 'X'), + (0xA35, 'V'), + (0xA36, 'M', u'ਸ਼'), + (0xA37, 'X'), + (0xA38, 'V'), + (0xA3A, 'X'), + (0xA3C, 'V'), + (0xA3D, 'X'), + (0xA3E, 'V'), + (0xA43, 'X'), + (0xA47, 'V'), + (0xA49, 'X'), + (0xA4B, 'V'), + (0xA4E, 'X'), + (0xA51, 'V'), + (0xA52, 'X'), + (0xA59, 'M', u'ਖ਼'), + (0xA5A, 'M', u'ਗ਼'), + (0xA5B, 'M', u'ਜ਼'), + (0xA5C, 'V'), + (0xA5D, 'X'), + (0xA5E, 'M', u'ਫ਼'), + (0xA5F, 'X'), + ] + +def _seg_11(): + return [ + (0xA66, 'V'), + (0xA76, 'X'), + (0xA81, 'V'), + (0xA84, 'X'), + (0xA85, 'V'), + (0xA8E, 'X'), + (0xA8F, 'V'), + (0xA92, 'X'), + (0xA93, 'V'), + (0xAA9, 'X'), + (0xAAA, 'V'), + (0xAB1, 'X'), + (0xAB2, 'V'), + (0xAB4, 'X'), + (0xAB5, 'V'), + (0xABA, 'X'), + (0xABC, 'V'), + (0xAC6, 'X'), + (0xAC7, 'V'), + (0xACA, 'X'), + (0xACB, 'V'), + (0xACE, 'X'), + (0xAD0, 'V'), + (0xAD1, 'X'), + (0xAE0, 'V'), + (0xAE4, 'X'), + (0xAE6, 'V'), + (0xAF2, 'X'), + (0xB01, 'V'), + (0xB04, 'X'), + (0xB05, 'V'), + (0xB0D, 'X'), + (0xB0F, 'V'), + (0xB11, 'X'), + (0xB13, 'V'), + (0xB29, 'X'), + (0xB2A, 'V'), + (0xB31, 'X'), + (0xB32, 'V'), + (0xB34, 'X'), + (0xB35, 'V'), + (0xB3A, 'X'), + (0xB3C, 'V'), + (0xB45, 'X'), + (0xB47, 'V'), + (0xB49, 'X'), + (0xB4B, 'V'), + (0xB4E, 'X'), + (0xB56, 'V'), + (0xB58, 'X'), + (0xB5C, 'M', u'ଡ଼'), + (0xB5D, 'M', u'ଢ଼'), + (0xB5E, 'X'), + (0xB5F, 'V'), + (0xB64, 'X'), + (0xB66, 'V'), + (0xB78, 'X'), + (0xB82, 'V'), + (0xB84, 'X'), + (0xB85, 'V'), + (0xB8B, 'X'), + (0xB8E, 'V'), + (0xB91, 'X'), + (0xB92, 'V'), + (0xB96, 'X'), + (0xB99, 'V'), + (0xB9B, 'X'), + (0xB9C, 'V'), + (0xB9D, 'X'), + (0xB9E, 'V'), + (0xBA0, 'X'), + (0xBA3, 'V'), + (0xBA5, 'X'), + (0xBA8, 'V'), + (0xBAB, 'X'), + (0xBAE, 'V'), + (0xBBA, 'X'), + (0xBBE, 'V'), + (0xBC3, 'X'), + (0xBC6, 'V'), + (0xBC9, 'X'), + (0xBCA, 'V'), + (0xBCE, 'X'), + (0xBD0, 'V'), + (0xBD1, 'X'), + (0xBD7, 'V'), + (0xBD8, 'X'), + (0xBE6, 'V'), + (0xBFB, 'X'), + (0xC01, 'V'), + (0xC04, 'X'), + (0xC05, 'V'), + (0xC0D, 'X'), + (0xC0E, 'V'), + (0xC11, 'X'), + (0xC12, 'V'), + (0xC29, 'X'), + (0xC2A, 'V'), + (0xC34, 'X'), + (0xC35, 'V'), + ] + +def _seg_12(): + return [ + (0xC3A, 'X'), + (0xC3D, 'V'), + (0xC45, 'X'), + (0xC46, 'V'), + (0xC49, 'X'), + (0xC4A, 'V'), + (0xC4E, 'X'), + (0xC55, 'V'), + (0xC57, 'X'), + (0xC58, 'V'), + (0xC5A, 'X'), + (0xC60, 'V'), + (0xC64, 'X'), + (0xC66, 'V'), + (0xC70, 'X'), + (0xC78, 'V'), + (0xC80, 'X'), + (0xC82, 'V'), + (0xC84, 'X'), + (0xC85, 'V'), + (0xC8D, 'X'), + (0xC8E, 'V'), + (0xC91, 'X'), + (0xC92, 'V'), + (0xCA9, 'X'), + (0xCAA, 'V'), + (0xCB4, 'X'), + (0xCB5, 'V'), + (0xCBA, 'X'), + (0xCBC, 'V'), + (0xCC5, 'X'), + (0xCC6, 'V'), + (0xCC9, 'X'), + (0xCCA, 'V'), + (0xCCE, 'X'), + (0xCD5, 'V'), + (0xCD7, 'X'), + (0xCDE, 'V'), + (0xCDF, 'X'), + (0xCE0, 'V'), + (0xCE4, 'X'), + (0xCE6, 'V'), + (0xCF0, 'X'), + (0xCF1, 'V'), + (0xCF3, 'X'), + (0xD02, 'V'), + (0xD04, 'X'), + (0xD05, 'V'), + (0xD0D, 'X'), + (0xD0E, 'V'), + (0xD11, 'X'), + (0xD12, 'V'), + (0xD3B, 'X'), + (0xD3D, 'V'), + (0xD45, 'X'), + (0xD46, 'V'), + (0xD49, 'X'), + (0xD4A, 'V'), + (0xD4F, 'X'), + (0xD57, 'V'), + (0xD58, 'X'), + (0xD60, 'V'), + (0xD64, 'X'), + (0xD66, 'V'), + (0xD76, 'X'), + (0xD79, 'V'), + (0xD80, 'X'), + (0xD82, 'V'), + (0xD84, 'X'), + (0xD85, 'V'), + (0xD97, 'X'), + (0xD9A, 'V'), + (0xDB2, 'X'), + (0xDB3, 'V'), + (0xDBC, 'X'), + (0xDBD, 'V'), + (0xDBE, 'X'), + (0xDC0, 'V'), + (0xDC7, 'X'), + (0xDCA, 'V'), + (0xDCB, 'X'), + (0xDCF, 'V'), + (0xDD5, 'X'), + (0xDD6, 'V'), + (0xDD7, 'X'), + (0xDD8, 'V'), + (0xDE0, 'X'), + (0xDF2, 'V'), + (0xDF5, 'X'), + (0xE01, 'V'), + (0xE33, 'M', u'à¹à¸²'), + (0xE34, 'V'), + (0xE3B, 'X'), + (0xE3F, 'V'), + (0xE5C, 'X'), + (0xE81, 'V'), + (0xE83, 'X'), + (0xE84, 'V'), + (0xE85, 'X'), + (0xE87, 'V'), + ] + +def _seg_13(): + return [ + (0xE89, 'X'), + (0xE8A, 'V'), + (0xE8B, 'X'), + (0xE8D, 'V'), + (0xE8E, 'X'), + (0xE94, 'V'), + (0xE98, 'X'), + (0xE99, 'V'), + (0xEA0, 'X'), + (0xEA1, 'V'), + (0xEA4, 'X'), + (0xEA5, 'V'), + (0xEA6, 'X'), + (0xEA7, 'V'), + (0xEA8, 'X'), + (0xEAA, 'V'), + (0xEAC, 'X'), + (0xEAD, 'V'), + (0xEB3, 'M', u'à»àº²'), + (0xEB4, 'V'), + (0xEBA, 'X'), + (0xEBB, 'V'), + (0xEBE, 'X'), + (0xEC0, 'V'), + (0xEC5, 'X'), + (0xEC6, 'V'), + (0xEC7, 'X'), + (0xEC8, 'V'), + (0xECE, 'X'), + (0xED0, 'V'), + (0xEDA, 'X'), + (0xEDC, 'M', u'ຫນ'), + (0xEDD, 'M', u'ຫມ'), + (0xEDE, 'V'), + (0xEE0, 'X'), + (0xF00, 'V'), + (0xF0C, 'M', u'་'), + (0xF0D, 'V'), + (0xF43, 'M', u'གྷ'), + (0xF44, 'V'), + (0xF48, 'X'), + (0xF49, 'V'), + (0xF4D, 'M', u'ཌྷ'), + (0xF4E, 'V'), + (0xF52, 'M', u'དྷ'), + (0xF53, 'V'), + (0xF57, 'M', u'བྷ'), + (0xF58, 'V'), + (0xF5C, 'M', u'ཛྷ'), + (0xF5D, 'V'), + (0xF69, 'M', u'ཀྵ'), + (0xF6A, 'V'), + (0xF6D, 'X'), + (0xF71, 'V'), + (0xF73, 'M', u'ཱི'), + (0xF74, 'V'), + (0xF75, 'M', u'ཱུ'), + (0xF76, 'M', u'ྲྀ'), + (0xF77, 'M', u'ྲཱྀ'), + (0xF78, 'M', u'ླྀ'), + (0xF79, 'M', u'ླཱྀ'), + (0xF7A, 'V'), + (0xF81, 'M', u'ཱྀ'), + (0xF82, 'V'), + (0xF93, 'M', u'ྒྷ'), + (0xF94, 'V'), + (0xF98, 'X'), + (0xF99, 'V'), + (0xF9D, 'M', u'ྜྷ'), + (0xF9E, 'V'), + (0xFA2, 'M', u'ྡྷ'), + (0xFA3, 'V'), + (0xFA7, 'M', u'ྦྷ'), + (0xFA8, 'V'), + (0xFAC, 'M', u'ྫྷ'), + (0xFAD, 'V'), + (0xFB9, 'M', u'à¾à¾µ'), + (0xFBA, 'V'), + (0xFBD, 'X'), + (0xFBE, 'V'), + (0xFCD, 'X'), + (0xFCE, 'V'), + (0xFDB, 'X'), + (0x1000, 'V'), + (0x10A0, 'X'), + (0x10C7, 'M', u'â´§'), + (0x10C8, 'X'), + (0x10CD, 'M', u'â´­'), + (0x10CE, 'X'), + (0x10D0, 'V'), + (0x10FC, 'M', u'ნ'), + (0x10FD, 'V'), + (0x115F, 'X'), + (0x1161, 'V'), + (0x1249, 'X'), + (0x124A, 'V'), + (0x124E, 'X'), + (0x1250, 'V'), + (0x1257, 'X'), + (0x1258, 'V'), + ] + +def _seg_14(): + return [ + (0x1259, 'X'), + (0x125A, 'V'), + (0x125E, 'X'), + (0x1260, 'V'), + (0x1289, 'X'), + (0x128A, 'V'), + (0x128E, 'X'), + (0x1290, 'V'), + (0x12B1, 'X'), + (0x12B2, 'V'), + (0x12B6, 'X'), + (0x12B8, 'V'), + (0x12BF, 'X'), + (0x12C0, 'V'), + (0x12C1, 'X'), + (0x12C2, 'V'), + (0x12C6, 'X'), + (0x12C8, 'V'), + (0x12D7, 'X'), + (0x12D8, 'V'), + (0x1311, 'X'), + (0x1312, 'V'), + (0x1316, 'X'), + (0x1318, 'V'), + (0x135B, 'X'), + (0x135D, 'V'), + (0x137D, 'X'), + (0x1380, 'V'), + (0x139A, 'X'), + (0x13A0, 'V'), + (0x13F5, 'X'), + (0x1400, 'V'), + (0x1680, 'X'), + (0x1681, 'V'), + (0x169D, 'X'), + (0x16A0, 'V'), + (0x16F1, 'X'), + (0x1700, 'V'), + (0x170D, 'X'), + (0x170E, 'V'), + (0x1715, 'X'), + (0x1720, 'V'), + (0x1737, 'X'), + (0x1740, 'V'), + (0x1754, 'X'), + (0x1760, 'V'), + (0x176D, 'X'), + (0x176E, 'V'), + (0x1771, 'X'), + (0x1772, 'V'), + (0x1774, 'X'), + (0x1780, 'V'), + (0x17B4, 'X'), + (0x17B6, 'V'), + (0x17DE, 'X'), + (0x17E0, 'V'), + (0x17EA, 'X'), + (0x17F0, 'V'), + (0x17FA, 'X'), + (0x1800, 'V'), + (0x1806, 'X'), + (0x1807, 'V'), + (0x180B, 'I'), + (0x180E, 'X'), + (0x1810, 'V'), + (0x181A, 'X'), + (0x1820, 'V'), + (0x1878, 'X'), + (0x1880, 'V'), + (0x18AB, 'X'), + (0x18B0, 'V'), + (0x18F6, 'X'), + (0x1900, 'V'), + (0x191D, 'X'), + (0x1920, 'V'), + (0x192C, 'X'), + (0x1930, 'V'), + (0x193C, 'X'), + (0x1940, 'V'), + (0x1941, 'X'), + (0x1944, 'V'), + (0x196E, 'X'), + (0x1970, 'V'), + (0x1975, 'X'), + (0x1980, 'V'), + (0x19AC, 'X'), + (0x19B0, 'V'), + (0x19CA, 'X'), + (0x19D0, 'V'), + (0x19DB, 'X'), + (0x19DE, 'V'), + (0x1A1C, 'X'), + (0x1A1E, 'V'), + (0x1A5F, 'X'), + (0x1A60, 'V'), + (0x1A7D, 'X'), + (0x1A7F, 'V'), + (0x1A8A, 'X'), + (0x1A90, 'V'), + (0x1A9A, 'X'), + ] + +def _seg_15(): + return [ + (0x1AA0, 'V'), + (0x1AAE, 'X'), + (0x1B00, 'V'), + (0x1B4C, 'X'), + (0x1B50, 'V'), + (0x1B7D, 'X'), + (0x1B80, 'V'), + (0x1BF4, 'X'), + (0x1BFC, 'V'), + (0x1C38, 'X'), + (0x1C3B, 'V'), + (0x1C4A, 'X'), + (0x1C4D, 'V'), + (0x1C80, 'X'), + (0x1CC0, 'V'), + (0x1CC8, 'X'), + (0x1CD0, 'V'), + (0x1CF7, 'X'), + (0x1D00, 'V'), + (0x1D2C, 'M', u'a'), + (0x1D2D, 'M', u'æ'), + (0x1D2E, 'M', u'b'), + (0x1D2F, 'V'), + (0x1D30, 'M', u'd'), + (0x1D31, 'M', u'e'), + (0x1D32, 'M', u'Ç'), + (0x1D33, 'M', u'g'), + (0x1D34, 'M', u'h'), + (0x1D35, 'M', u'i'), + (0x1D36, 'M', u'j'), + (0x1D37, 'M', u'k'), + (0x1D38, 'M', u'l'), + (0x1D39, 'M', u'm'), + (0x1D3A, 'M', u'n'), + (0x1D3B, 'V'), + (0x1D3C, 'M', u'o'), + (0x1D3D, 'M', u'È£'), + (0x1D3E, 'M', u'p'), + (0x1D3F, 'M', u'r'), + (0x1D40, 'M', u't'), + (0x1D41, 'M', u'u'), + (0x1D42, 'M', u'w'), + (0x1D43, 'M', u'a'), + (0x1D44, 'M', u'É'), + (0x1D45, 'M', u'É‘'), + (0x1D46, 'M', u'á´‚'), + (0x1D47, 'M', u'b'), + (0x1D48, 'M', u'd'), + (0x1D49, 'M', u'e'), + (0x1D4A, 'M', u'É™'), + (0x1D4B, 'M', u'É›'), + (0x1D4C, 'M', u'Éœ'), + (0x1D4D, 'M', u'g'), + (0x1D4E, 'V'), + (0x1D4F, 'M', u'k'), + (0x1D50, 'M', u'm'), + (0x1D51, 'M', u'Å‹'), + (0x1D52, 'M', u'o'), + (0x1D53, 'M', u'É”'), + (0x1D54, 'M', u'á´–'), + (0x1D55, 'M', u'á´—'), + (0x1D56, 'M', u'p'), + (0x1D57, 'M', u't'), + (0x1D58, 'M', u'u'), + (0x1D59, 'M', u'á´'), + (0x1D5A, 'M', u'ɯ'), + (0x1D5B, 'M', u'v'), + (0x1D5C, 'M', u'á´¥'), + (0x1D5D, 'M', u'β'), + (0x1D5E, 'M', u'γ'), + (0x1D5F, 'M', u'δ'), + (0x1D60, 'M', u'φ'), + (0x1D61, 'M', u'χ'), + (0x1D62, 'M', u'i'), + (0x1D63, 'M', u'r'), + (0x1D64, 'M', u'u'), + (0x1D65, 'M', u'v'), + (0x1D66, 'M', u'β'), + (0x1D67, 'M', u'γ'), + (0x1D68, 'M', u'Ï'), + (0x1D69, 'M', u'φ'), + (0x1D6A, 'M', u'χ'), + (0x1D6B, 'V'), + (0x1D78, 'M', u'н'), + (0x1D79, 'V'), + (0x1D9B, 'M', u'É’'), + (0x1D9C, 'M', u'c'), + (0x1D9D, 'M', u'É•'), + (0x1D9E, 'M', u'ð'), + (0x1D9F, 'M', u'Éœ'), + (0x1DA0, 'M', u'f'), + (0x1DA1, 'M', u'ÉŸ'), + (0x1DA2, 'M', u'É¡'), + (0x1DA3, 'M', u'É¥'), + (0x1DA4, 'M', u'ɨ'), + (0x1DA5, 'M', u'É©'), + (0x1DA6, 'M', u'ɪ'), + (0x1DA7, 'M', u'áµ»'), + (0x1DA8, 'M', u'Ê'), + (0x1DA9, 'M', u'É­'), + ] + +def _seg_16(): + return [ + (0x1DAA, 'M', u'á¶…'), + (0x1DAB, 'M', u'ÊŸ'), + (0x1DAC, 'M', u'ɱ'), + (0x1DAD, 'M', u'ɰ'), + (0x1DAE, 'M', u'ɲ'), + (0x1DAF, 'M', u'ɳ'), + (0x1DB0, 'M', u'É´'), + (0x1DB1, 'M', u'ɵ'), + (0x1DB2, 'M', u'ɸ'), + (0x1DB3, 'M', u'Ê‚'), + (0x1DB4, 'M', u'ʃ'), + (0x1DB5, 'M', u'Æ«'), + (0x1DB6, 'M', u'ʉ'), + (0x1DB7, 'M', u'ÊŠ'), + (0x1DB8, 'M', u'á´œ'), + (0x1DB9, 'M', u'Ê‹'), + (0x1DBA, 'M', u'ÊŒ'), + (0x1DBB, 'M', u'z'), + (0x1DBC, 'M', u'Ê'), + (0x1DBD, 'M', u'Ê‘'), + (0x1DBE, 'M', u'Ê’'), + (0x1DBF, 'M', u'θ'), + (0x1DC0, 'V'), + (0x1DE7, 'X'), + (0x1DFC, 'V'), + (0x1E00, 'M', u'á¸'), + (0x1E01, 'V'), + (0x1E02, 'M', u'ḃ'), + (0x1E03, 'V'), + (0x1E04, 'M', u'ḅ'), + (0x1E05, 'V'), + (0x1E06, 'M', u'ḇ'), + (0x1E07, 'V'), + (0x1E08, 'M', u'ḉ'), + (0x1E09, 'V'), + (0x1E0A, 'M', u'ḋ'), + (0x1E0B, 'V'), + (0x1E0C, 'M', u'á¸'), + (0x1E0D, 'V'), + (0x1E0E, 'M', u'á¸'), + (0x1E0F, 'V'), + (0x1E10, 'M', u'ḑ'), + (0x1E11, 'V'), + (0x1E12, 'M', u'ḓ'), + (0x1E13, 'V'), + (0x1E14, 'M', u'ḕ'), + (0x1E15, 'V'), + (0x1E16, 'M', u'ḗ'), + (0x1E17, 'V'), + (0x1E18, 'M', u'ḙ'), + (0x1E19, 'V'), + (0x1E1A, 'M', u'ḛ'), + (0x1E1B, 'V'), + (0x1E1C, 'M', u'á¸'), + (0x1E1D, 'V'), + (0x1E1E, 'M', u'ḟ'), + (0x1E1F, 'V'), + (0x1E20, 'M', u'ḡ'), + (0x1E21, 'V'), + (0x1E22, 'M', u'ḣ'), + (0x1E23, 'V'), + (0x1E24, 'M', u'ḥ'), + (0x1E25, 'V'), + (0x1E26, 'M', u'ḧ'), + (0x1E27, 'V'), + (0x1E28, 'M', u'ḩ'), + (0x1E29, 'V'), + (0x1E2A, 'M', u'ḫ'), + (0x1E2B, 'V'), + (0x1E2C, 'M', u'ḭ'), + (0x1E2D, 'V'), + (0x1E2E, 'M', u'ḯ'), + (0x1E2F, 'V'), + (0x1E30, 'M', u'ḱ'), + (0x1E31, 'V'), + (0x1E32, 'M', u'ḳ'), + (0x1E33, 'V'), + (0x1E34, 'M', u'ḵ'), + (0x1E35, 'V'), + (0x1E36, 'M', u'ḷ'), + (0x1E37, 'V'), + (0x1E38, 'M', u'ḹ'), + (0x1E39, 'V'), + (0x1E3A, 'M', u'ḻ'), + (0x1E3B, 'V'), + (0x1E3C, 'M', u'ḽ'), + (0x1E3D, 'V'), + (0x1E3E, 'M', u'ḿ'), + (0x1E3F, 'V'), + (0x1E40, 'M', u'á¹'), + (0x1E41, 'V'), + (0x1E42, 'M', u'ṃ'), + (0x1E43, 'V'), + (0x1E44, 'M', u'á¹…'), + (0x1E45, 'V'), + (0x1E46, 'M', u'ṇ'), + (0x1E47, 'V'), + (0x1E48, 'M', u'ṉ'), + (0x1E49, 'V'), + (0x1E4A, 'M', u'ṋ'), + ] + +def _seg_17(): + return [ + (0x1E4B, 'V'), + (0x1E4C, 'M', u'á¹'), + (0x1E4D, 'V'), + (0x1E4E, 'M', u'á¹'), + (0x1E4F, 'V'), + (0x1E50, 'M', u'ṑ'), + (0x1E51, 'V'), + (0x1E52, 'M', u'ṓ'), + (0x1E53, 'V'), + (0x1E54, 'M', u'ṕ'), + (0x1E55, 'V'), + (0x1E56, 'M', u'á¹—'), + (0x1E57, 'V'), + (0x1E58, 'M', u'á¹™'), + (0x1E59, 'V'), + (0x1E5A, 'M', u'á¹›'), + (0x1E5B, 'V'), + (0x1E5C, 'M', u'á¹'), + (0x1E5D, 'V'), + (0x1E5E, 'M', u'ṟ'), + (0x1E5F, 'V'), + (0x1E60, 'M', u'ṡ'), + (0x1E61, 'V'), + (0x1E62, 'M', u'á¹£'), + (0x1E63, 'V'), + (0x1E64, 'M', u'á¹¥'), + (0x1E65, 'V'), + (0x1E66, 'M', u'á¹§'), + (0x1E67, 'V'), + (0x1E68, 'M', u'ṩ'), + (0x1E69, 'V'), + (0x1E6A, 'M', u'ṫ'), + (0x1E6B, 'V'), + (0x1E6C, 'M', u'á¹­'), + (0x1E6D, 'V'), + (0x1E6E, 'M', u'ṯ'), + (0x1E6F, 'V'), + (0x1E70, 'M', u'á¹±'), + (0x1E71, 'V'), + (0x1E72, 'M', u'á¹³'), + (0x1E73, 'V'), + (0x1E74, 'M', u'á¹µ'), + (0x1E75, 'V'), + (0x1E76, 'M', u'á¹·'), + (0x1E77, 'V'), + (0x1E78, 'M', u'á¹¹'), + (0x1E79, 'V'), + (0x1E7A, 'M', u'á¹»'), + (0x1E7B, 'V'), + (0x1E7C, 'M', u'á¹½'), + (0x1E7D, 'V'), + (0x1E7E, 'M', u'ṿ'), + (0x1E7F, 'V'), + (0x1E80, 'M', u'áº'), + (0x1E81, 'V'), + (0x1E82, 'M', u'ẃ'), + (0x1E83, 'V'), + (0x1E84, 'M', u'ẅ'), + (0x1E85, 'V'), + (0x1E86, 'M', u'ẇ'), + (0x1E87, 'V'), + (0x1E88, 'M', u'ẉ'), + (0x1E89, 'V'), + (0x1E8A, 'M', u'ẋ'), + (0x1E8B, 'V'), + (0x1E8C, 'M', u'áº'), + (0x1E8D, 'V'), + (0x1E8E, 'M', u'áº'), + (0x1E8F, 'V'), + (0x1E90, 'M', u'ẑ'), + (0x1E91, 'V'), + (0x1E92, 'M', u'ẓ'), + (0x1E93, 'V'), + (0x1E94, 'M', u'ẕ'), + (0x1E95, 'V'), + (0x1E9A, 'M', u'aʾ'), + (0x1E9B, 'M', u'ṡ'), + (0x1E9C, 'V'), + (0x1E9E, 'M', u'ss'), + (0x1E9F, 'V'), + (0x1EA0, 'M', u'ạ'), + (0x1EA1, 'V'), + (0x1EA2, 'M', u'ả'), + (0x1EA3, 'V'), + (0x1EA4, 'M', u'ấ'), + (0x1EA5, 'V'), + (0x1EA6, 'M', u'ầ'), + (0x1EA7, 'V'), + (0x1EA8, 'M', u'ẩ'), + (0x1EA9, 'V'), + (0x1EAA, 'M', u'ẫ'), + (0x1EAB, 'V'), + (0x1EAC, 'M', u'ậ'), + (0x1EAD, 'V'), + (0x1EAE, 'M', u'ắ'), + (0x1EAF, 'V'), + (0x1EB0, 'M', u'ằ'), + (0x1EB1, 'V'), + (0x1EB2, 'M', u'ẳ'), + (0x1EB3, 'V'), + ] + +def _seg_18(): + return [ + (0x1EB4, 'M', u'ẵ'), + (0x1EB5, 'V'), + (0x1EB6, 'M', u'ặ'), + (0x1EB7, 'V'), + (0x1EB8, 'M', u'ẹ'), + (0x1EB9, 'V'), + (0x1EBA, 'M', u'ẻ'), + (0x1EBB, 'V'), + (0x1EBC, 'M', u'ẽ'), + (0x1EBD, 'V'), + (0x1EBE, 'M', u'ế'), + (0x1EBF, 'V'), + (0x1EC0, 'M', u'á»'), + (0x1EC1, 'V'), + (0x1EC2, 'M', u'ể'), + (0x1EC3, 'V'), + (0x1EC4, 'M', u'á»…'), + (0x1EC5, 'V'), + (0x1EC6, 'M', u'ệ'), + (0x1EC7, 'V'), + (0x1EC8, 'M', u'ỉ'), + (0x1EC9, 'V'), + (0x1ECA, 'M', u'ị'), + (0x1ECB, 'V'), + (0x1ECC, 'M', u'á»'), + (0x1ECD, 'V'), + (0x1ECE, 'M', u'á»'), + (0x1ECF, 'V'), + (0x1ED0, 'M', u'ố'), + (0x1ED1, 'V'), + (0x1ED2, 'M', u'ồ'), + (0x1ED3, 'V'), + (0x1ED4, 'M', u'ổ'), + (0x1ED5, 'V'), + (0x1ED6, 'M', u'á»—'), + (0x1ED7, 'V'), + (0x1ED8, 'M', u'á»™'), + (0x1ED9, 'V'), + (0x1EDA, 'M', u'á»›'), + (0x1EDB, 'V'), + (0x1EDC, 'M', u'á»'), + (0x1EDD, 'V'), + (0x1EDE, 'M', u'ở'), + (0x1EDF, 'V'), + (0x1EE0, 'M', u'ỡ'), + (0x1EE1, 'V'), + (0x1EE2, 'M', u'ợ'), + (0x1EE3, 'V'), + (0x1EE4, 'M', u'ụ'), + (0x1EE5, 'V'), + (0x1EE6, 'M', u'á»§'), + (0x1EE7, 'V'), + (0x1EE8, 'M', u'ứ'), + (0x1EE9, 'V'), + (0x1EEA, 'M', u'ừ'), + (0x1EEB, 'V'), + (0x1EEC, 'M', u'á»­'), + (0x1EED, 'V'), + (0x1EEE, 'M', u'ữ'), + (0x1EEF, 'V'), + (0x1EF0, 'M', u'á»±'), + (0x1EF1, 'V'), + (0x1EF2, 'M', u'ỳ'), + (0x1EF3, 'V'), + (0x1EF4, 'M', u'ỵ'), + (0x1EF5, 'V'), + (0x1EF6, 'M', u'á»·'), + (0x1EF7, 'V'), + (0x1EF8, 'M', u'ỹ'), + (0x1EF9, 'V'), + (0x1EFA, 'M', u'á»»'), + (0x1EFB, 'V'), + (0x1EFC, 'M', u'ỽ'), + (0x1EFD, 'V'), + (0x1EFE, 'M', u'ỿ'), + (0x1EFF, 'V'), + (0x1F08, 'M', u'á¼€'), + (0x1F09, 'M', u'á¼'), + (0x1F0A, 'M', u'ἂ'), + (0x1F0B, 'M', u'ἃ'), + (0x1F0C, 'M', u'ἄ'), + (0x1F0D, 'M', u'á¼…'), + (0x1F0E, 'M', u'ἆ'), + (0x1F0F, 'M', u'ἇ'), + (0x1F10, 'V'), + (0x1F16, 'X'), + (0x1F18, 'M', u'á¼'), + (0x1F19, 'M', u'ἑ'), + (0x1F1A, 'M', u'á¼’'), + (0x1F1B, 'M', u'ἓ'), + (0x1F1C, 'M', u'á¼”'), + (0x1F1D, 'M', u'ἕ'), + (0x1F1E, 'X'), + (0x1F20, 'V'), + (0x1F28, 'M', u'á¼ '), + (0x1F29, 'M', u'ἡ'), + (0x1F2A, 'M', u'á¼¢'), + (0x1F2B, 'M', u'á¼£'), + (0x1F2C, 'M', u'ἤ'), + (0x1F2D, 'M', u'á¼¥'), + ] + +def _seg_19(): + return [ + (0x1F2E, 'M', u'ἦ'), + (0x1F2F, 'M', u'á¼§'), + (0x1F30, 'V'), + (0x1F38, 'M', u'á¼°'), + (0x1F39, 'M', u'á¼±'), + (0x1F3A, 'M', u'á¼²'), + (0x1F3B, 'M', u'á¼³'), + (0x1F3C, 'M', u'á¼´'), + (0x1F3D, 'M', u'á¼µ'), + (0x1F3E, 'M', u'á¼¶'), + (0x1F3F, 'M', u'á¼·'), + (0x1F40, 'V'), + (0x1F46, 'X'), + (0x1F48, 'M', u'á½€'), + (0x1F49, 'M', u'á½'), + (0x1F4A, 'M', u'ὂ'), + (0x1F4B, 'M', u'ὃ'), + (0x1F4C, 'M', u'ὄ'), + (0x1F4D, 'M', u'á½…'), + (0x1F4E, 'X'), + (0x1F50, 'V'), + (0x1F58, 'X'), + (0x1F59, 'M', u'ὑ'), + (0x1F5A, 'X'), + (0x1F5B, 'M', u'ὓ'), + (0x1F5C, 'X'), + (0x1F5D, 'M', u'ὕ'), + (0x1F5E, 'X'), + (0x1F5F, 'M', u'á½—'), + (0x1F60, 'V'), + (0x1F68, 'M', u'á½ '), + (0x1F69, 'M', u'ὡ'), + (0x1F6A, 'M', u'á½¢'), + (0x1F6B, 'M', u'á½£'), + (0x1F6C, 'M', u'ὤ'), + (0x1F6D, 'M', u'á½¥'), + (0x1F6E, 'M', u'ὦ'), + (0x1F6F, 'M', u'á½§'), + (0x1F70, 'V'), + (0x1F71, 'M', u'ά'), + (0x1F72, 'V'), + (0x1F73, 'M', u'έ'), + (0x1F74, 'V'), + (0x1F75, 'M', u'ή'), + (0x1F76, 'V'), + (0x1F77, 'M', u'ί'), + (0x1F78, 'V'), + (0x1F79, 'M', u'ÏŒ'), + (0x1F7A, 'V'), + (0x1F7B, 'M', u'Ï'), + (0x1F7C, 'V'), + (0x1F7D, 'M', u'ÏŽ'), + (0x1F7E, 'X'), + (0x1F80, 'M', u'ἀι'), + (0x1F81, 'M', u'á¼Î¹'), + (0x1F82, 'M', u'ἂι'), + (0x1F83, 'M', u'ἃι'), + (0x1F84, 'M', u'ἄι'), + (0x1F85, 'M', u'ἅι'), + (0x1F86, 'M', u'ἆι'), + (0x1F87, 'M', u'ἇι'), + (0x1F88, 'M', u'ἀι'), + (0x1F89, 'M', u'á¼Î¹'), + (0x1F8A, 'M', u'ἂι'), + (0x1F8B, 'M', u'ἃι'), + (0x1F8C, 'M', u'ἄι'), + (0x1F8D, 'M', u'ἅι'), + (0x1F8E, 'M', u'ἆι'), + (0x1F8F, 'M', u'ἇι'), + (0x1F90, 'M', u'ἠι'), + (0x1F91, 'M', u'ἡι'), + (0x1F92, 'M', u'ἢι'), + (0x1F93, 'M', u'ἣι'), + (0x1F94, 'M', u'ἤι'), + (0x1F95, 'M', u'ἥι'), + (0x1F96, 'M', u'ἦι'), + (0x1F97, 'M', u'ἧι'), + (0x1F98, 'M', u'ἠι'), + (0x1F99, 'M', u'ἡι'), + (0x1F9A, 'M', u'ἢι'), + (0x1F9B, 'M', u'ἣι'), + (0x1F9C, 'M', u'ἤι'), + (0x1F9D, 'M', u'ἥι'), + (0x1F9E, 'M', u'ἦι'), + (0x1F9F, 'M', u'ἧι'), + (0x1FA0, 'M', u'ὠι'), + (0x1FA1, 'M', u'ὡι'), + (0x1FA2, 'M', u'ὢι'), + (0x1FA3, 'M', u'ὣι'), + (0x1FA4, 'M', u'ὤι'), + (0x1FA5, 'M', u'ὥι'), + (0x1FA6, 'M', u'ὦι'), + (0x1FA7, 'M', u'ὧι'), + (0x1FA8, 'M', u'ὠι'), + (0x1FA9, 'M', u'ὡι'), + (0x1FAA, 'M', u'ὢι'), + (0x1FAB, 'M', u'ὣι'), + (0x1FAC, 'M', u'ὤι'), + (0x1FAD, 'M', u'ὥι'), + (0x1FAE, 'M', u'ὦι'), + ] + +def _seg_20(): + return [ + (0x1FAF, 'M', u'ὧι'), + (0x1FB0, 'V'), + (0x1FB2, 'M', u'ὰι'), + (0x1FB3, 'M', u'αι'), + (0x1FB4, 'M', u'άι'), + (0x1FB5, 'X'), + (0x1FB6, 'V'), + (0x1FB7, 'M', u'ᾶι'), + (0x1FB8, 'M', u'á¾°'), + (0x1FB9, 'M', u'á¾±'), + (0x1FBA, 'M', u'á½°'), + (0x1FBB, 'M', u'ά'), + (0x1FBC, 'M', u'αι'), + (0x1FBD, '3', u' Ì“'), + (0x1FBE, 'M', u'ι'), + (0x1FBF, '3', u' Ì“'), + (0x1FC0, '3', u' Í‚'), + (0x1FC1, '3', u' ̈͂'), + (0x1FC2, 'M', u'ὴι'), + (0x1FC3, 'M', u'ηι'), + (0x1FC4, 'M', u'ήι'), + (0x1FC5, 'X'), + (0x1FC6, 'V'), + (0x1FC7, 'M', u'ῆι'), + (0x1FC8, 'M', u'á½²'), + (0x1FC9, 'M', u'έ'), + (0x1FCA, 'M', u'á½´'), + (0x1FCB, 'M', u'ή'), + (0x1FCC, 'M', u'ηι'), + (0x1FCD, '3', u' ̓̀'), + (0x1FCE, '3', u' Ì“Ì'), + (0x1FCF, '3', u' ̓͂'), + (0x1FD0, 'V'), + (0x1FD3, 'M', u'Î'), + (0x1FD4, 'X'), + (0x1FD6, 'V'), + (0x1FD8, 'M', u'á¿'), + (0x1FD9, 'M', u'á¿‘'), + (0x1FDA, 'M', u'á½¶'), + (0x1FDB, 'M', u'ί'), + (0x1FDC, 'X'), + (0x1FDD, '3', u' ̔̀'), + (0x1FDE, '3', u' Ì”Ì'), + (0x1FDF, '3', u' ̔͂'), + (0x1FE0, 'V'), + (0x1FE3, 'M', u'ΰ'), + (0x1FE4, 'V'), + (0x1FE8, 'M', u'á¿ '), + (0x1FE9, 'M', u'á¿¡'), + (0x1FEA, 'M', u'ὺ'), + (0x1FEB, 'M', u'Ï'), + (0x1FEC, 'M', u'á¿¥'), + (0x1FED, '3', u' ̈̀'), + (0x1FEE, '3', u' ̈Ì'), + (0x1FEF, '3', u'`'), + (0x1FF0, 'X'), + (0x1FF2, 'M', u'ὼι'), + (0x1FF3, 'M', u'ωι'), + (0x1FF4, 'M', u'ώι'), + (0x1FF5, 'X'), + (0x1FF6, 'V'), + (0x1FF7, 'M', u'ῶι'), + (0x1FF8, 'M', u'ὸ'), + (0x1FF9, 'M', u'ÏŒ'), + (0x1FFA, 'M', u'á½¼'), + (0x1FFB, 'M', u'ÏŽ'), + (0x1FFC, 'M', u'ωι'), + (0x1FFD, '3', u' Ì'), + (0x1FFE, '3', u' Ì”'), + (0x1FFF, 'X'), + (0x2000, '3', u' '), + (0x200B, 'I'), + (0x200C, 'D', u''), + (0x200E, 'X'), + (0x2010, 'V'), + (0x2011, 'M', u'â€'), + (0x2012, 'V'), + (0x2017, '3', u' ̳'), + (0x2018, 'V'), + (0x2024, 'X'), + (0x2027, 'V'), + (0x2028, 'X'), + (0x202F, '3', u' '), + (0x2030, 'V'), + (0x2033, 'M', u'′′'), + (0x2034, 'M', u'′′′'), + (0x2035, 'V'), + (0x2036, 'M', u'‵‵'), + (0x2037, 'M', u'‵‵‵'), + (0x2038, 'V'), + (0x203C, '3', u'!!'), + (0x203D, 'V'), + (0x203E, '3', u' Ì…'), + (0x203F, 'V'), + (0x2047, '3', u'??'), + (0x2048, '3', u'?!'), + (0x2049, '3', u'!?'), + (0x204A, 'V'), + (0x2057, 'M', u'′′′′'), + (0x2058, 'V'), + ] + +def _seg_21(): + return [ + (0x205F, '3', u' '), + (0x2060, 'I'), + (0x2061, 'X'), + (0x2064, 'I'), + (0x2065, 'X'), + (0x2070, 'M', u'0'), + (0x2071, 'M', u'i'), + (0x2072, 'X'), + (0x2074, 'M', u'4'), + (0x2075, 'M', u'5'), + (0x2076, 'M', u'6'), + (0x2077, 'M', u'7'), + (0x2078, 'M', u'8'), + (0x2079, 'M', u'9'), + (0x207A, '3', u'+'), + (0x207B, 'M', u'−'), + (0x207C, '3', u'='), + (0x207D, '3', u'('), + (0x207E, '3', u')'), + (0x207F, 'M', u'n'), + (0x2080, 'M', u'0'), + (0x2081, 'M', u'1'), + (0x2082, 'M', u'2'), + (0x2083, 'M', u'3'), + (0x2084, 'M', u'4'), + (0x2085, 'M', u'5'), + (0x2086, 'M', u'6'), + (0x2087, 'M', u'7'), + (0x2088, 'M', u'8'), + (0x2089, 'M', u'9'), + (0x208A, '3', u'+'), + (0x208B, 'M', u'−'), + (0x208C, '3', u'='), + (0x208D, '3', u'('), + (0x208E, '3', u')'), + (0x208F, 'X'), + (0x2090, 'M', u'a'), + (0x2091, 'M', u'e'), + (0x2092, 'M', u'o'), + (0x2093, 'M', u'x'), + (0x2094, 'M', u'É™'), + (0x2095, 'M', u'h'), + (0x2096, 'M', u'k'), + (0x2097, 'M', u'l'), + (0x2098, 'M', u'm'), + (0x2099, 'M', u'n'), + (0x209A, 'M', u'p'), + (0x209B, 'M', u's'), + (0x209C, 'M', u't'), + (0x209D, 'X'), + (0x20A0, 'V'), + (0x20A8, 'M', u'rs'), + (0x20A9, 'V'), + (0x20BB, 'X'), + (0x20D0, 'V'), + (0x20F1, 'X'), + (0x2100, '3', u'a/c'), + (0x2101, '3', u'a/s'), + (0x2102, 'M', u'c'), + (0x2103, 'M', u'°c'), + (0x2104, 'V'), + (0x2105, '3', u'c/o'), + (0x2106, '3', u'c/u'), + (0x2107, 'M', u'É›'), + (0x2108, 'V'), + (0x2109, 'M', u'°f'), + (0x210A, 'M', u'g'), + (0x210B, 'M', u'h'), + (0x210F, 'M', u'ħ'), + (0x2110, 'M', u'i'), + (0x2112, 'M', u'l'), + (0x2114, 'V'), + (0x2115, 'M', u'n'), + (0x2116, 'M', u'no'), + (0x2117, 'V'), + (0x2119, 'M', u'p'), + (0x211A, 'M', u'q'), + (0x211B, 'M', u'r'), + (0x211E, 'V'), + (0x2120, 'M', u'sm'), + (0x2121, 'M', u'tel'), + (0x2122, 'M', u'tm'), + (0x2123, 'V'), + (0x2124, 'M', u'z'), + (0x2125, 'V'), + (0x2126, 'M', u'ω'), + (0x2127, 'V'), + (0x2128, 'M', u'z'), + (0x2129, 'V'), + (0x212A, 'M', u'k'), + (0x212B, 'M', u'Ã¥'), + (0x212C, 'M', u'b'), + (0x212D, 'M', u'c'), + (0x212E, 'V'), + (0x212F, 'M', u'e'), + (0x2131, 'M', u'f'), + (0x2132, 'X'), + (0x2133, 'M', u'm'), + (0x2134, 'M', u'o'), + (0x2135, 'M', u'×'), + ] + +def _seg_22(): + return [ + (0x2136, 'M', u'ב'), + (0x2137, 'M', u'×’'), + (0x2138, 'M', u'ד'), + (0x2139, 'M', u'i'), + (0x213A, 'V'), + (0x213B, 'M', u'fax'), + (0x213C, 'M', u'Ï€'), + (0x213D, 'M', u'γ'), + (0x213F, 'M', u'Ï€'), + (0x2140, 'M', u'∑'), + (0x2141, 'V'), + (0x2145, 'M', u'd'), + (0x2147, 'M', u'e'), + (0x2148, 'M', u'i'), + (0x2149, 'M', u'j'), + (0x214A, 'V'), + (0x2150, 'M', u'1â„7'), + (0x2151, 'M', u'1â„9'), + (0x2152, 'M', u'1â„10'), + (0x2153, 'M', u'1â„3'), + (0x2154, 'M', u'2â„3'), + (0x2155, 'M', u'1â„5'), + (0x2156, 'M', u'2â„5'), + (0x2157, 'M', u'3â„5'), + (0x2158, 'M', u'4â„5'), + (0x2159, 'M', u'1â„6'), + (0x215A, 'M', u'5â„6'), + (0x215B, 'M', u'1â„8'), + (0x215C, 'M', u'3â„8'), + (0x215D, 'M', u'5â„8'), + (0x215E, 'M', u'7â„8'), + (0x215F, 'M', u'1â„'), + (0x2160, 'M', u'i'), + (0x2161, 'M', u'ii'), + (0x2162, 'M', u'iii'), + (0x2163, 'M', u'iv'), + (0x2164, 'M', u'v'), + (0x2165, 'M', u'vi'), + (0x2166, 'M', u'vii'), + (0x2167, 'M', u'viii'), + (0x2168, 'M', u'ix'), + (0x2169, 'M', u'x'), + (0x216A, 'M', u'xi'), + (0x216B, 'M', u'xii'), + (0x216C, 'M', u'l'), + (0x216D, 'M', u'c'), + (0x216E, 'M', u'd'), + (0x216F, 'M', u'm'), + (0x2170, 'M', u'i'), + (0x2171, 'M', u'ii'), + (0x2172, 'M', u'iii'), + (0x2173, 'M', u'iv'), + (0x2174, 'M', u'v'), + (0x2175, 'M', u'vi'), + (0x2176, 'M', u'vii'), + (0x2177, 'M', u'viii'), + (0x2178, 'M', u'ix'), + (0x2179, 'M', u'x'), + (0x217A, 'M', u'xi'), + (0x217B, 'M', u'xii'), + (0x217C, 'M', u'l'), + (0x217D, 'M', u'c'), + (0x217E, 'M', u'd'), + (0x217F, 'M', u'm'), + (0x2180, 'V'), + (0x2183, 'X'), + (0x2184, 'V'), + (0x2189, 'M', u'0â„3'), + (0x218A, 'X'), + (0x2190, 'V'), + (0x222C, 'M', u'∫∫'), + (0x222D, 'M', u'∫∫∫'), + (0x222E, 'V'), + (0x222F, 'M', u'∮∮'), + (0x2230, 'M', u'∮∮∮'), + (0x2231, 'V'), + (0x2260, '3'), + (0x2261, 'V'), + (0x226E, '3'), + (0x2270, 'V'), + (0x2329, 'M', u'〈'), + (0x232A, 'M', u'〉'), + (0x232B, 'V'), + (0x23F4, 'X'), + (0x2400, 'V'), + (0x2427, 'X'), + (0x2440, 'V'), + (0x244B, 'X'), + (0x2460, 'M', u'1'), + (0x2461, 'M', u'2'), + (0x2462, 'M', u'3'), + (0x2463, 'M', u'4'), + (0x2464, 'M', u'5'), + (0x2465, 'M', u'6'), + (0x2466, 'M', u'7'), + (0x2467, 'M', u'8'), + (0x2468, 'M', u'9'), + (0x2469, 'M', u'10'), + (0x246A, 'M', u'11'), + (0x246B, 'M', u'12'), + ] + +def _seg_23(): + return [ + (0x246C, 'M', u'13'), + (0x246D, 'M', u'14'), + (0x246E, 'M', u'15'), + (0x246F, 'M', u'16'), + (0x2470, 'M', u'17'), + (0x2471, 'M', u'18'), + (0x2472, 'M', u'19'), + (0x2473, 'M', u'20'), + (0x2474, '3', u'(1)'), + (0x2475, '3', u'(2)'), + (0x2476, '3', u'(3)'), + (0x2477, '3', u'(4)'), + (0x2478, '3', u'(5)'), + (0x2479, '3', u'(6)'), + (0x247A, '3', u'(7)'), + (0x247B, '3', u'(8)'), + (0x247C, '3', u'(9)'), + (0x247D, '3', u'(10)'), + (0x247E, '3', u'(11)'), + (0x247F, '3', u'(12)'), + (0x2480, '3', u'(13)'), + (0x2481, '3', u'(14)'), + (0x2482, '3', u'(15)'), + (0x2483, '3', u'(16)'), + (0x2484, '3', u'(17)'), + (0x2485, '3', u'(18)'), + (0x2486, '3', u'(19)'), + (0x2487, '3', u'(20)'), + (0x2488, 'X'), + (0x249C, '3', u'(a)'), + (0x249D, '3', u'(b)'), + (0x249E, '3', u'(c)'), + (0x249F, '3', u'(d)'), + (0x24A0, '3', u'(e)'), + (0x24A1, '3', u'(f)'), + (0x24A2, '3', u'(g)'), + (0x24A3, '3', u'(h)'), + (0x24A4, '3', u'(i)'), + (0x24A5, '3', u'(j)'), + (0x24A6, '3', u'(k)'), + (0x24A7, '3', u'(l)'), + (0x24A8, '3', u'(m)'), + (0x24A9, '3', u'(n)'), + (0x24AA, '3', u'(o)'), + (0x24AB, '3', u'(p)'), + (0x24AC, '3', u'(q)'), + (0x24AD, '3', u'(r)'), + (0x24AE, '3', u'(s)'), + (0x24AF, '3', u'(t)'), + (0x24B0, '3', u'(u)'), + (0x24B1, '3', u'(v)'), + (0x24B2, '3', u'(w)'), + (0x24B3, '3', u'(x)'), + (0x24B4, '3', u'(y)'), + (0x24B5, '3', u'(z)'), + (0x24B6, 'M', u'a'), + (0x24B7, 'M', u'b'), + (0x24B8, 'M', u'c'), + (0x24B9, 'M', u'd'), + (0x24BA, 'M', u'e'), + (0x24BB, 'M', u'f'), + (0x24BC, 'M', u'g'), + (0x24BD, 'M', u'h'), + (0x24BE, 'M', u'i'), + (0x24BF, 'M', u'j'), + (0x24C0, 'M', u'k'), + (0x24C1, 'M', u'l'), + (0x24C2, 'M', u'm'), + (0x24C3, 'M', u'n'), + (0x24C4, 'M', u'o'), + (0x24C5, 'M', u'p'), + (0x24C6, 'M', u'q'), + (0x24C7, 'M', u'r'), + (0x24C8, 'M', u's'), + (0x24C9, 'M', u't'), + (0x24CA, 'M', u'u'), + (0x24CB, 'M', u'v'), + (0x24CC, 'M', u'w'), + (0x24CD, 'M', u'x'), + (0x24CE, 'M', u'y'), + (0x24CF, 'M', u'z'), + (0x24D0, 'M', u'a'), + (0x24D1, 'M', u'b'), + (0x24D2, 'M', u'c'), + (0x24D3, 'M', u'd'), + (0x24D4, 'M', u'e'), + (0x24D5, 'M', u'f'), + (0x24D6, 'M', u'g'), + (0x24D7, 'M', u'h'), + (0x24D8, 'M', u'i'), + (0x24D9, 'M', u'j'), + (0x24DA, 'M', u'k'), + (0x24DB, 'M', u'l'), + (0x24DC, 'M', u'm'), + (0x24DD, 'M', u'n'), + (0x24DE, 'M', u'o'), + (0x24DF, 'M', u'p'), + (0x24E0, 'M', u'q'), + (0x24E1, 'M', u'r'), + (0x24E2, 'M', u's'), + ] + +def _seg_24(): + return [ + (0x24E3, 'M', u't'), + (0x24E4, 'M', u'u'), + (0x24E5, 'M', u'v'), + (0x24E6, 'M', u'w'), + (0x24E7, 'M', u'x'), + (0x24E8, 'M', u'y'), + (0x24E9, 'M', u'z'), + (0x24EA, 'M', u'0'), + (0x24EB, 'V'), + (0x2700, 'X'), + (0x2701, 'V'), + (0x2A0C, 'M', u'∫∫∫∫'), + (0x2A0D, 'V'), + (0x2A74, '3', u'::='), + (0x2A75, '3', u'=='), + (0x2A76, '3', u'==='), + (0x2A77, 'V'), + (0x2ADC, 'M', u'â«Ì¸'), + (0x2ADD, 'V'), + (0x2B4D, 'X'), + (0x2B50, 'V'), + (0x2B5A, 'X'), + (0x2C00, 'M', u'â°°'), + (0x2C01, 'M', u'â°±'), + (0x2C02, 'M', u'â°²'), + (0x2C03, 'M', u'â°³'), + (0x2C04, 'M', u'â°´'), + (0x2C05, 'M', u'â°µ'), + (0x2C06, 'M', u'â°¶'), + (0x2C07, 'M', u'â°·'), + (0x2C08, 'M', u'â°¸'), + (0x2C09, 'M', u'â°¹'), + (0x2C0A, 'M', u'â°º'), + (0x2C0B, 'M', u'â°»'), + (0x2C0C, 'M', u'â°¼'), + (0x2C0D, 'M', u'â°½'), + (0x2C0E, 'M', u'â°¾'), + (0x2C0F, 'M', u'â°¿'), + (0x2C10, 'M', u'â±€'), + (0x2C11, 'M', u'â±'), + (0x2C12, 'M', u'ⱂ'), + (0x2C13, 'M', u'ⱃ'), + (0x2C14, 'M', u'ⱄ'), + (0x2C15, 'M', u'â±…'), + (0x2C16, 'M', u'ⱆ'), + (0x2C17, 'M', u'ⱇ'), + (0x2C18, 'M', u'ⱈ'), + (0x2C19, 'M', u'ⱉ'), + (0x2C1A, 'M', u'ⱊ'), + (0x2C1B, 'M', u'ⱋ'), + (0x2C1C, 'M', u'ⱌ'), + (0x2C1D, 'M', u'â±'), + (0x2C1E, 'M', u'ⱎ'), + (0x2C1F, 'M', u'â±'), + (0x2C20, 'M', u'â±'), + (0x2C21, 'M', u'ⱑ'), + (0x2C22, 'M', u'â±’'), + (0x2C23, 'M', u'ⱓ'), + (0x2C24, 'M', u'â±”'), + (0x2C25, 'M', u'ⱕ'), + (0x2C26, 'M', u'â±–'), + (0x2C27, 'M', u'â±—'), + (0x2C28, 'M', u'ⱘ'), + (0x2C29, 'M', u'â±™'), + (0x2C2A, 'M', u'ⱚ'), + (0x2C2B, 'M', u'â±›'), + (0x2C2C, 'M', u'ⱜ'), + (0x2C2D, 'M', u'â±'), + (0x2C2E, 'M', u'ⱞ'), + (0x2C2F, 'X'), + (0x2C30, 'V'), + (0x2C5F, 'X'), + (0x2C60, 'M', u'ⱡ'), + (0x2C61, 'V'), + (0x2C62, 'M', u'É«'), + (0x2C63, 'M', u'áµ½'), + (0x2C64, 'M', u'ɽ'), + (0x2C65, 'V'), + (0x2C67, 'M', u'ⱨ'), + (0x2C68, 'V'), + (0x2C69, 'M', u'ⱪ'), + (0x2C6A, 'V'), + (0x2C6B, 'M', u'ⱬ'), + (0x2C6C, 'V'), + (0x2C6D, 'M', u'É‘'), + (0x2C6E, 'M', u'ɱ'), + (0x2C6F, 'M', u'É'), + (0x2C70, 'M', u'É’'), + (0x2C71, 'V'), + (0x2C72, 'M', u'â±³'), + (0x2C73, 'V'), + (0x2C75, 'M', u'â±¶'), + (0x2C76, 'V'), + (0x2C7C, 'M', u'j'), + (0x2C7D, 'M', u'v'), + (0x2C7E, 'M', u'È¿'), + (0x2C7F, 'M', u'É€'), + (0x2C80, 'M', u'â²'), + (0x2C81, 'V'), + (0x2C82, 'M', u'ⲃ'), + ] + +def _seg_25(): + return [ + (0x2C83, 'V'), + (0x2C84, 'M', u'â²…'), + (0x2C85, 'V'), + (0x2C86, 'M', u'ⲇ'), + (0x2C87, 'V'), + (0x2C88, 'M', u'ⲉ'), + (0x2C89, 'V'), + (0x2C8A, 'M', u'ⲋ'), + (0x2C8B, 'V'), + (0x2C8C, 'M', u'â²'), + (0x2C8D, 'V'), + (0x2C8E, 'M', u'â²'), + (0x2C8F, 'V'), + (0x2C90, 'M', u'ⲑ'), + (0x2C91, 'V'), + (0x2C92, 'M', u'ⲓ'), + (0x2C93, 'V'), + (0x2C94, 'M', u'ⲕ'), + (0x2C95, 'V'), + (0x2C96, 'M', u'â²—'), + (0x2C97, 'V'), + (0x2C98, 'M', u'â²™'), + (0x2C99, 'V'), + (0x2C9A, 'M', u'â²›'), + (0x2C9B, 'V'), + (0x2C9C, 'M', u'â²'), + (0x2C9D, 'V'), + (0x2C9E, 'M', u'ⲟ'), + (0x2C9F, 'V'), + (0x2CA0, 'M', u'ⲡ'), + (0x2CA1, 'V'), + (0x2CA2, 'M', u'â²£'), + (0x2CA3, 'V'), + (0x2CA4, 'M', u'â²¥'), + (0x2CA5, 'V'), + (0x2CA6, 'M', u'â²§'), + (0x2CA7, 'V'), + (0x2CA8, 'M', u'ⲩ'), + (0x2CA9, 'V'), + (0x2CAA, 'M', u'ⲫ'), + (0x2CAB, 'V'), + (0x2CAC, 'M', u'â²­'), + (0x2CAD, 'V'), + (0x2CAE, 'M', u'ⲯ'), + (0x2CAF, 'V'), + (0x2CB0, 'M', u'â²±'), + (0x2CB1, 'V'), + (0x2CB2, 'M', u'â²³'), + (0x2CB3, 'V'), + (0x2CB4, 'M', u'â²µ'), + (0x2CB5, 'V'), + (0x2CB6, 'M', u'â²·'), + (0x2CB7, 'V'), + (0x2CB8, 'M', u'â²¹'), + (0x2CB9, 'V'), + (0x2CBA, 'M', u'â²»'), + (0x2CBB, 'V'), + (0x2CBC, 'M', u'â²½'), + (0x2CBD, 'V'), + (0x2CBE, 'M', u'ⲿ'), + (0x2CBF, 'V'), + (0x2CC0, 'M', u'â³'), + (0x2CC1, 'V'), + (0x2CC2, 'M', u'ⳃ'), + (0x2CC3, 'V'), + (0x2CC4, 'M', u'â³…'), + (0x2CC5, 'V'), + (0x2CC6, 'M', u'ⳇ'), + (0x2CC7, 'V'), + (0x2CC8, 'M', u'ⳉ'), + (0x2CC9, 'V'), + (0x2CCA, 'M', u'ⳋ'), + (0x2CCB, 'V'), + (0x2CCC, 'M', u'â³'), + (0x2CCD, 'V'), + (0x2CCE, 'M', u'â³'), + (0x2CCF, 'V'), + (0x2CD0, 'M', u'ⳑ'), + (0x2CD1, 'V'), + (0x2CD2, 'M', u'ⳓ'), + (0x2CD3, 'V'), + (0x2CD4, 'M', u'ⳕ'), + (0x2CD5, 'V'), + (0x2CD6, 'M', u'â³—'), + (0x2CD7, 'V'), + (0x2CD8, 'M', u'â³™'), + (0x2CD9, 'V'), + (0x2CDA, 'M', u'â³›'), + (0x2CDB, 'V'), + (0x2CDC, 'M', u'â³'), + (0x2CDD, 'V'), + (0x2CDE, 'M', u'ⳟ'), + (0x2CDF, 'V'), + (0x2CE0, 'M', u'ⳡ'), + (0x2CE1, 'V'), + (0x2CE2, 'M', u'â³£'), + (0x2CE3, 'V'), + (0x2CEB, 'M', u'ⳬ'), + (0x2CEC, 'V'), + (0x2CED, 'M', u'â³®'), + ] + +def _seg_26(): + return [ + (0x2CEE, 'V'), + (0x2CF2, 'M', u'â³³'), + (0x2CF3, 'V'), + (0x2CF4, 'X'), + (0x2CF9, 'V'), + (0x2D26, 'X'), + (0x2D27, 'V'), + (0x2D28, 'X'), + (0x2D2D, 'V'), + (0x2D2E, 'X'), + (0x2D30, 'V'), + (0x2D68, 'X'), + (0x2D6F, 'M', u'ⵡ'), + (0x2D70, 'V'), + (0x2D71, 'X'), + (0x2D7F, 'V'), + (0x2D97, 'X'), + (0x2DA0, 'V'), + (0x2DA7, 'X'), + (0x2DA8, 'V'), + (0x2DAF, 'X'), + (0x2DB0, 'V'), + (0x2DB7, 'X'), + (0x2DB8, 'V'), + (0x2DBF, 'X'), + (0x2DC0, 'V'), + (0x2DC7, 'X'), + (0x2DC8, 'V'), + (0x2DCF, 'X'), + (0x2DD0, 'V'), + (0x2DD7, 'X'), + (0x2DD8, 'V'), + (0x2DDF, 'X'), + (0x2DE0, 'V'), + (0x2E3C, 'X'), + (0x2E80, 'V'), + (0x2E9A, 'X'), + (0x2E9B, 'V'), + (0x2E9F, 'M', u'æ¯'), + (0x2EA0, 'V'), + (0x2EF3, 'M', u'龟'), + (0x2EF4, 'X'), + (0x2F00, 'M', u'一'), + (0x2F01, 'M', u'丨'), + (0x2F02, 'M', u'丶'), + (0x2F03, 'M', u'丿'), + (0x2F04, 'M', u'ä¹™'), + (0x2F05, 'M', u'亅'), + (0x2F06, 'M', u'二'), + (0x2F07, 'M', u'亠'), + (0x2F08, 'M', u'人'), + (0x2F09, 'M', u'å„¿'), + (0x2F0A, 'M', u'å…¥'), + (0x2F0B, 'M', u'å…«'), + (0x2F0C, 'M', u'冂'), + (0x2F0D, 'M', u'冖'), + (0x2F0E, 'M', u'冫'), + (0x2F0F, 'M', u'几'), + (0x2F10, 'M', u'凵'), + (0x2F11, 'M', u'刀'), + (0x2F12, 'M', u'力'), + (0x2F13, 'M', u'勹'), + (0x2F14, 'M', u'匕'), + (0x2F15, 'M', u'匚'), + (0x2F16, 'M', u'匸'), + (0x2F17, 'M', u'å'), + (0x2F18, 'M', u'åœ'), + (0x2F19, 'M', u'å©'), + (0x2F1A, 'M', u'厂'), + (0x2F1B, 'M', u'厶'), + (0x2F1C, 'M', u'åˆ'), + (0x2F1D, 'M', u'å£'), + (0x2F1E, 'M', u'å›—'), + (0x2F1F, 'M', u'土'), + (0x2F20, 'M', u'士'), + (0x2F21, 'M', u'夂'), + (0x2F22, 'M', u'夊'), + (0x2F23, 'M', u'夕'), + (0x2F24, 'M', u'大'), + (0x2F25, 'M', u'女'), + (0x2F26, 'M', u'å­'), + (0x2F27, 'M', u'宀'), + (0x2F28, 'M', u'寸'), + (0x2F29, 'M', u'å°'), + (0x2F2A, 'M', u'å°¢'), + (0x2F2B, 'M', u'å°¸'), + (0x2F2C, 'M', u'å±®'), + (0x2F2D, 'M', u'å±±'), + (0x2F2E, 'M', u'å·›'), + (0x2F2F, 'M', u'å·¥'), + (0x2F30, 'M', u'å·±'), + (0x2F31, 'M', u'å·¾'), + (0x2F32, 'M', u'å¹²'), + (0x2F33, 'M', u'幺'), + (0x2F34, 'M', u'广'), + (0x2F35, 'M', u'å»´'), + (0x2F36, 'M', u'廾'), + (0x2F37, 'M', u'弋'), + (0x2F38, 'M', u'弓'), + (0x2F39, 'M', u'å½'), + ] + +def _seg_27(): + return [ + (0x2F3A, 'M', u'彡'), + (0x2F3B, 'M', u'å½³'), + (0x2F3C, 'M', u'心'), + (0x2F3D, 'M', u'戈'), + (0x2F3E, 'M', u'戶'), + (0x2F3F, 'M', u'手'), + (0x2F40, 'M', u'支'), + (0x2F41, 'M', u'æ”´'), + (0x2F42, 'M', u'æ–‡'), + (0x2F43, 'M', u'æ–—'), + (0x2F44, 'M', u'æ–¤'), + (0x2F45, 'M', u'æ–¹'), + (0x2F46, 'M', u'æ— '), + (0x2F47, 'M', u'æ—¥'), + (0x2F48, 'M', u'æ›°'), + (0x2F49, 'M', u'月'), + (0x2F4A, 'M', u'木'), + (0x2F4B, 'M', u'欠'), + (0x2F4C, 'M', u'æ­¢'), + (0x2F4D, 'M', u'æ­¹'), + (0x2F4E, 'M', u'殳'), + (0x2F4F, 'M', u'毋'), + (0x2F50, 'M', u'比'), + (0x2F51, 'M', u'毛'), + (0x2F52, 'M', u'æ°'), + (0x2F53, 'M', u'æ°”'), + (0x2F54, 'M', u'æ°´'), + (0x2F55, 'M', u'ç«'), + (0x2F56, 'M', u'爪'), + (0x2F57, 'M', u'父'), + (0x2F58, 'M', u'爻'), + (0x2F59, 'M', u'爿'), + (0x2F5A, 'M', u'片'), + (0x2F5B, 'M', u'牙'), + (0x2F5C, 'M', u'牛'), + (0x2F5D, 'M', u'犬'), + (0x2F5E, 'M', u'玄'), + (0x2F5F, 'M', u'玉'), + (0x2F60, 'M', u'瓜'), + (0x2F61, 'M', u'瓦'), + (0x2F62, 'M', u'甘'), + (0x2F63, 'M', u'生'), + (0x2F64, 'M', u'用'), + (0x2F65, 'M', u'ç”°'), + (0x2F66, 'M', u'ç–‹'), + (0x2F67, 'M', u'ç–’'), + (0x2F68, 'M', u'ç™¶'), + (0x2F69, 'M', u'白'), + (0x2F6A, 'M', u'çš®'), + (0x2F6B, 'M', u'çš¿'), + (0x2F6C, 'M', u'ç›®'), + (0x2F6D, 'M', u'矛'), + (0x2F6E, 'M', u'矢'), + (0x2F6F, 'M', u'石'), + (0x2F70, 'M', u'示'), + (0x2F71, 'M', u'禸'), + (0x2F72, 'M', u'禾'), + (0x2F73, 'M', u'ç©´'), + (0x2F74, 'M', u'ç«‹'), + (0x2F75, 'M', u'竹'), + (0x2F76, 'M', u'ç±³'), + (0x2F77, 'M', u'糸'), + (0x2F78, 'M', u'ç¼¶'), + (0x2F79, 'M', u'网'), + (0x2F7A, 'M', u'羊'), + (0x2F7B, 'M', u'ç¾½'), + (0x2F7C, 'M', u'è€'), + (0x2F7D, 'M', u'而'), + (0x2F7E, 'M', u'耒'), + (0x2F7F, 'M', u'耳'), + (0x2F80, 'M', u'è¿'), + (0x2F81, 'M', u'肉'), + (0x2F82, 'M', u'臣'), + (0x2F83, 'M', u'自'), + (0x2F84, 'M', u'至'), + (0x2F85, 'M', u'臼'), + (0x2F86, 'M', u'舌'), + (0x2F87, 'M', u'舛'), + (0x2F88, 'M', u'舟'), + (0x2F89, 'M', u'艮'), + (0x2F8A, 'M', u'色'), + (0x2F8B, 'M', u'艸'), + (0x2F8C, 'M', u'è™'), + (0x2F8D, 'M', u'虫'), + (0x2F8E, 'M', u'è¡€'), + (0x2F8F, 'M', u'行'), + (0x2F90, 'M', u'è¡£'), + (0x2F91, 'M', u'襾'), + (0x2F92, 'M', u'見'), + (0x2F93, 'M', u'è§’'), + (0x2F94, 'M', u'言'), + (0x2F95, 'M', u'è°·'), + (0x2F96, 'M', u'豆'), + (0x2F97, 'M', u'豕'), + (0x2F98, 'M', u'豸'), + (0x2F99, 'M', u'è²'), + (0x2F9A, 'M', u'赤'), + (0x2F9B, 'M', u'èµ°'), + (0x2F9C, 'M', u'è¶³'), + (0x2F9D, 'M', u'身'), + ] + +def _seg_28(): + return [ + (0x2F9E, 'M', u'車'), + (0x2F9F, 'M', u'è¾›'), + (0x2FA0, 'M', u'è¾°'), + (0x2FA1, 'M', u'è¾µ'), + (0x2FA2, 'M', u'é‚‘'), + (0x2FA3, 'M', u'é…‰'), + (0x2FA4, 'M', u'釆'), + (0x2FA5, 'M', u'里'), + (0x2FA6, 'M', u'金'), + (0x2FA7, 'M', u'é•·'), + (0x2FA8, 'M', u'é–€'), + (0x2FA9, 'M', u'阜'), + (0x2FAA, 'M', u'éš¶'), + (0x2FAB, 'M', u'éš¹'), + (0x2FAC, 'M', u'雨'), + (0x2FAD, 'M', u'é‘'), + (0x2FAE, 'M', u'éž'), + (0x2FAF, 'M', u'é¢'), + (0x2FB0, 'M', u'é©'), + (0x2FB1, 'M', u'韋'), + (0x2FB2, 'M', u'韭'), + (0x2FB3, 'M', u'音'), + (0x2FB4, 'M', u'é '), + (0x2FB5, 'M', u'風'), + (0x2FB6, 'M', u'飛'), + (0x2FB7, 'M', u'食'), + (0x2FB8, 'M', u'首'), + (0x2FB9, 'M', u'香'), + (0x2FBA, 'M', u'馬'), + (0x2FBB, 'M', u'骨'), + (0x2FBC, 'M', u'高'), + (0x2FBD, 'M', u'髟'), + (0x2FBE, 'M', u'鬥'), + (0x2FBF, 'M', u'鬯'), + (0x2FC0, 'M', u'鬲'), + (0x2FC1, 'M', u'鬼'), + (0x2FC2, 'M', u'é­š'), + (0x2FC3, 'M', u'é³¥'), + (0x2FC4, 'M', u'é¹µ'), + (0x2FC5, 'M', u'鹿'), + (0x2FC6, 'M', u'麥'), + (0x2FC7, 'M', u'麻'), + (0x2FC8, 'M', u'黃'), + (0x2FC9, 'M', u'é»'), + (0x2FCA, 'M', u'黑'), + (0x2FCB, 'M', u'黹'), + (0x2FCC, 'M', u'黽'), + (0x2FCD, 'M', u'鼎'), + (0x2FCE, 'M', u'鼓'), + (0x2FCF, 'M', u'é¼ '), + (0x2FD0, 'M', u'é¼»'), + (0x2FD1, 'M', u'齊'), + (0x2FD2, 'M', u'é½’'), + (0x2FD3, 'M', u'é¾'), + (0x2FD4, 'M', u'龜'), + (0x2FD5, 'M', u'é¾ '), + (0x2FD6, 'X'), + (0x3000, '3', u' '), + (0x3001, 'V'), + (0x3002, 'M', u'.'), + (0x3003, 'V'), + (0x3036, 'M', u'〒'), + (0x3037, 'V'), + (0x3038, 'M', u'å'), + (0x3039, 'M', u'å„'), + (0x303A, 'M', u'å…'), + (0x303B, 'V'), + (0x3040, 'X'), + (0x3041, 'V'), + (0x3097, 'X'), + (0x3099, 'V'), + (0x309B, '3', u' ã‚™'), + (0x309C, '3', u' ゚'), + (0x309D, 'V'), + (0x309F, 'M', u'より'), + (0x30A0, 'V'), + (0x30FF, 'M', u'コト'), + (0x3100, 'X'), + (0x3105, 'V'), + (0x312E, 'X'), + (0x3131, 'M', u'á„€'), + (0x3132, 'M', u'á„'), + (0x3133, 'M', u'ᆪ'), + (0x3134, 'M', u'á„‚'), + (0x3135, 'M', u'ᆬ'), + (0x3136, 'M', u'ᆭ'), + (0x3137, 'M', u'ᄃ'), + (0x3138, 'M', u'á„„'), + (0x3139, 'M', u'á„…'), + (0x313A, 'M', u'ᆰ'), + (0x313B, 'M', u'ᆱ'), + (0x313C, 'M', u'ᆲ'), + (0x313D, 'M', u'ᆳ'), + (0x313E, 'M', u'ᆴ'), + (0x313F, 'M', u'ᆵ'), + (0x3140, 'M', u'ᄚ'), + (0x3141, 'M', u'ᄆ'), + (0x3142, 'M', u'ᄇ'), + (0x3143, 'M', u'ᄈ'), + (0x3144, 'M', u'á„¡'), + ] + +def _seg_29(): + return [ + (0x3145, 'M', u'ᄉ'), + (0x3146, 'M', u'ᄊ'), + (0x3147, 'M', u'á„‹'), + (0x3148, 'M', u'ᄌ'), + (0x3149, 'M', u'á„'), + (0x314A, 'M', u'ᄎ'), + (0x314B, 'M', u'á„'), + (0x314C, 'M', u'á„'), + (0x314D, 'M', u'á„‘'), + (0x314E, 'M', u'á„’'), + (0x314F, 'M', u'á…¡'), + (0x3150, 'M', u'á…¢'), + (0x3151, 'M', u'á…£'), + (0x3152, 'M', u'á…¤'), + (0x3153, 'M', u'á…¥'), + (0x3154, 'M', u'á…¦'), + (0x3155, 'M', u'á…§'), + (0x3156, 'M', u'á…¨'), + (0x3157, 'M', u'á…©'), + (0x3158, 'M', u'á…ª'), + (0x3159, 'M', u'á…«'), + (0x315A, 'M', u'á…¬'), + (0x315B, 'M', u'á…­'), + (0x315C, 'M', u'á…®'), + (0x315D, 'M', u'á…¯'), + (0x315E, 'M', u'á…°'), + (0x315F, 'M', u'á…±'), + (0x3160, 'M', u'á…²'), + (0x3161, 'M', u'á…³'), + (0x3162, 'M', u'á…´'), + (0x3163, 'M', u'á…µ'), + (0x3164, 'X'), + (0x3165, 'M', u'á„”'), + (0x3166, 'M', u'á„•'), + (0x3167, 'M', u'ᇇ'), + (0x3168, 'M', u'ᇈ'), + (0x3169, 'M', u'ᇌ'), + (0x316A, 'M', u'ᇎ'), + (0x316B, 'M', u'ᇓ'), + (0x316C, 'M', u'ᇗ'), + (0x316D, 'M', u'ᇙ'), + (0x316E, 'M', u'ᄜ'), + (0x316F, 'M', u'á‡'), + (0x3170, 'M', u'ᇟ'), + (0x3171, 'M', u'á„'), + (0x3172, 'M', u'ᄞ'), + (0x3173, 'M', u'á„ '), + (0x3174, 'M', u'á„¢'), + (0x3175, 'M', u'á„£'), + (0x3176, 'M', u'á„§'), + (0x3177, 'M', u'á„©'), + (0x3178, 'M', u'á„«'), + (0x3179, 'M', u'ᄬ'), + (0x317A, 'M', u'á„­'), + (0x317B, 'M', u'á„®'), + (0x317C, 'M', u'ᄯ'), + (0x317D, 'M', u'ᄲ'), + (0x317E, 'M', u'á„¶'), + (0x317F, 'M', u'á…€'), + (0x3180, 'M', u'á…‡'), + (0x3181, 'M', u'á…Œ'), + (0x3182, 'M', u'ᇱ'), + (0x3183, 'M', u'ᇲ'), + (0x3184, 'M', u'á…—'), + (0x3185, 'M', u'á…˜'), + (0x3186, 'M', u'á…™'), + (0x3187, 'M', u'ᆄ'), + (0x3188, 'M', u'ᆅ'), + (0x3189, 'M', u'ᆈ'), + (0x318A, 'M', u'ᆑ'), + (0x318B, 'M', u'ᆒ'), + (0x318C, 'M', u'ᆔ'), + (0x318D, 'M', u'ᆞ'), + (0x318E, 'M', u'ᆡ'), + (0x318F, 'X'), + (0x3190, 'V'), + (0x3192, 'M', u'一'), + (0x3193, 'M', u'二'), + (0x3194, 'M', u'三'), + (0x3195, 'M', u'å››'), + (0x3196, 'M', u'上'), + (0x3197, 'M', u'中'), + (0x3198, 'M', u'下'), + (0x3199, 'M', u'甲'), + (0x319A, 'M', u'ä¹™'), + (0x319B, 'M', u'丙'), + (0x319C, 'M', u'ä¸'), + (0x319D, 'M', u'天'), + (0x319E, 'M', u'地'), + (0x319F, 'M', u'人'), + (0x31A0, 'V'), + (0x31BB, 'X'), + (0x31C0, 'V'), + (0x31E4, 'X'), + (0x31F0, 'V'), + (0x3200, '3', u'(á„€)'), + (0x3201, '3', u'(á„‚)'), + (0x3202, '3', u'(ᄃ)'), + (0x3203, '3', u'(á„…)'), + (0x3204, '3', u'(ᄆ)'), + ] + +def _seg_30(): + return [ + (0x3205, '3', u'(ᄇ)'), + (0x3206, '3', u'(ᄉ)'), + (0x3207, '3', u'(á„‹)'), + (0x3208, '3', u'(ᄌ)'), + (0x3209, '3', u'(ᄎ)'), + (0x320A, '3', u'(á„)'), + (0x320B, '3', u'(á„)'), + (0x320C, '3', u'(á„‘)'), + (0x320D, '3', u'(á„’)'), + (0x320E, '3', u'(ê°€)'), + (0x320F, '3', u'(나)'), + (0x3210, '3', u'(다)'), + (0x3211, '3', u'(ë¼)'), + (0x3212, '3', u'(마)'), + (0x3213, '3', u'(ë°”)'), + (0x3214, '3', u'(사)'), + (0x3215, '3', u'(ì•„)'), + (0x3216, '3', u'(ìž)'), + (0x3217, '3', u'(ì°¨)'), + (0x3218, '3', u'(ì¹´)'), + (0x3219, '3', u'(타)'), + (0x321A, '3', u'(파)'), + (0x321B, '3', u'(하)'), + (0x321C, '3', u'(주)'), + (0x321D, '3', u'(오전)'), + (0x321E, '3', u'(오후)'), + (0x321F, 'X'), + (0x3220, '3', u'(一)'), + (0x3221, '3', u'(二)'), + (0x3222, '3', u'(三)'), + (0x3223, '3', u'(å››)'), + (0x3224, '3', u'(五)'), + (0x3225, '3', u'(å…­)'), + (0x3226, '3', u'(七)'), + (0x3227, '3', u'(å…«)'), + (0x3228, '3', u'(ä¹)'), + (0x3229, '3', u'(å)'), + (0x322A, '3', u'(月)'), + (0x322B, '3', u'(ç«)'), + (0x322C, '3', u'(æ°´)'), + (0x322D, '3', u'(木)'), + (0x322E, '3', u'(金)'), + (0x322F, '3', u'(土)'), + (0x3230, '3', u'(æ—¥)'), + (0x3231, '3', u'(æ ª)'), + (0x3232, '3', u'(有)'), + (0x3233, '3', u'(社)'), + (0x3234, '3', u'(å)'), + (0x3235, '3', u'(特)'), + (0x3236, '3', u'(財)'), + (0x3237, '3', u'(ç¥)'), + (0x3238, '3', u'(労)'), + (0x3239, '3', u'(代)'), + (0x323A, '3', u'(呼)'), + (0x323B, '3', u'(å­¦)'), + (0x323C, '3', u'(監)'), + (0x323D, '3', u'(ä¼)'), + (0x323E, '3', u'(資)'), + (0x323F, '3', u'(å”)'), + (0x3240, '3', u'(祭)'), + (0x3241, '3', u'(休)'), + (0x3242, '3', u'(自)'), + (0x3243, '3', u'(至)'), + (0x3244, 'M', u'å•'), + (0x3245, 'M', u'å¹¼'), + (0x3246, 'M', u'æ–‡'), + (0x3247, 'M', u'ç®'), + (0x3248, 'V'), + (0x3250, 'M', u'pte'), + (0x3251, 'M', u'21'), + (0x3252, 'M', u'22'), + (0x3253, 'M', u'23'), + (0x3254, 'M', u'24'), + (0x3255, 'M', u'25'), + (0x3256, 'M', u'26'), + (0x3257, 'M', u'27'), + (0x3258, 'M', u'28'), + (0x3259, 'M', u'29'), + (0x325A, 'M', u'30'), + (0x325B, 'M', u'31'), + (0x325C, 'M', u'32'), + (0x325D, 'M', u'33'), + (0x325E, 'M', u'34'), + (0x325F, 'M', u'35'), + (0x3260, 'M', u'á„€'), + (0x3261, 'M', u'á„‚'), + (0x3262, 'M', u'ᄃ'), + (0x3263, 'M', u'á„…'), + (0x3264, 'M', u'ᄆ'), + (0x3265, 'M', u'ᄇ'), + (0x3266, 'M', u'ᄉ'), + (0x3267, 'M', u'á„‹'), + (0x3268, 'M', u'ᄌ'), + (0x3269, 'M', u'ᄎ'), + (0x326A, 'M', u'á„'), + (0x326B, 'M', u'á„'), + (0x326C, 'M', u'á„‘'), + (0x326D, 'M', u'á„’'), + (0x326E, 'M', u'ê°€'), + (0x326F, 'M', u'나'), + ] + +def _seg_31(): + return [ + (0x3270, 'M', u'다'), + (0x3271, 'M', u'ë¼'), + (0x3272, 'M', u'마'), + (0x3273, 'M', u'ë°”'), + (0x3274, 'M', u'사'), + (0x3275, 'M', u'ì•„'), + (0x3276, 'M', u'ìž'), + (0x3277, 'M', u'ì°¨'), + (0x3278, 'M', u'ì¹´'), + (0x3279, 'M', u'타'), + (0x327A, 'M', u'파'), + (0x327B, 'M', u'하'), + (0x327C, 'M', u'참고'), + (0x327D, 'M', u'주ì˜'), + (0x327E, 'M', u'ìš°'), + (0x327F, 'V'), + (0x3280, 'M', u'一'), + (0x3281, 'M', u'二'), + (0x3282, 'M', u'三'), + (0x3283, 'M', u'å››'), + (0x3284, 'M', u'五'), + (0x3285, 'M', u'å…­'), + (0x3286, 'M', u'七'), + (0x3287, 'M', u'å…«'), + (0x3288, 'M', u'ä¹'), + (0x3289, 'M', u'å'), + (0x328A, 'M', u'月'), + (0x328B, 'M', u'ç«'), + (0x328C, 'M', u'æ°´'), + (0x328D, 'M', u'木'), + (0x328E, 'M', u'金'), + (0x328F, 'M', u'土'), + (0x3290, 'M', u'æ—¥'), + (0x3291, 'M', u'æ ª'), + (0x3292, 'M', u'有'), + (0x3293, 'M', u'社'), + (0x3294, 'M', u'å'), + (0x3295, 'M', u'特'), + (0x3296, 'M', u'財'), + (0x3297, 'M', u'ç¥'), + (0x3298, 'M', u'労'), + (0x3299, 'M', u'秘'), + (0x329A, 'M', u'ç”·'), + (0x329B, 'M', u'女'), + (0x329C, 'M', u'é©'), + (0x329D, 'M', u'優'), + (0x329E, 'M', u'å°'), + (0x329F, 'M', u'注'), + (0x32A0, 'M', u'é …'), + (0x32A1, 'M', u'休'), + (0x32A2, 'M', u'写'), + (0x32A3, 'M', u'æ­£'), + (0x32A4, 'M', u'上'), + (0x32A5, 'M', u'中'), + (0x32A6, 'M', u'下'), + (0x32A7, 'M', u'å·¦'), + (0x32A8, 'M', u'å³'), + (0x32A9, 'M', u'医'), + (0x32AA, 'M', u'å®—'), + (0x32AB, 'M', u'å­¦'), + (0x32AC, 'M', u'監'), + (0x32AD, 'M', u'ä¼'), + (0x32AE, 'M', u'資'), + (0x32AF, 'M', u'å”'), + (0x32B0, 'M', u'夜'), + (0x32B1, 'M', u'36'), + (0x32B2, 'M', u'37'), + (0x32B3, 'M', u'38'), + (0x32B4, 'M', u'39'), + (0x32B5, 'M', u'40'), + (0x32B6, 'M', u'41'), + (0x32B7, 'M', u'42'), + (0x32B8, 'M', u'43'), + (0x32B9, 'M', u'44'), + (0x32BA, 'M', u'45'), + (0x32BB, 'M', u'46'), + (0x32BC, 'M', u'47'), + (0x32BD, 'M', u'48'), + (0x32BE, 'M', u'49'), + (0x32BF, 'M', u'50'), + (0x32C0, 'M', u'1月'), + (0x32C1, 'M', u'2月'), + (0x32C2, 'M', u'3月'), + (0x32C3, 'M', u'4月'), + (0x32C4, 'M', u'5月'), + (0x32C5, 'M', u'6月'), + (0x32C6, 'M', u'7月'), + (0x32C7, 'M', u'8月'), + (0x32C8, 'M', u'9月'), + (0x32C9, 'M', u'10月'), + (0x32CA, 'M', u'11月'), + (0x32CB, 'M', u'12月'), + (0x32CC, 'M', u'hg'), + (0x32CD, 'M', u'erg'), + (0x32CE, 'M', u'ev'), + (0x32CF, 'M', u'ltd'), + (0x32D0, 'M', u'ã‚¢'), + (0x32D1, 'M', u'イ'), + (0x32D2, 'M', u'ウ'), + (0x32D3, 'M', u'エ'), + ] + +def _seg_32(): + return [ + (0x32D4, 'M', u'オ'), + (0x32D5, 'M', u'ã‚«'), + (0x32D6, 'M', u'ã‚­'), + (0x32D7, 'M', u'ク'), + (0x32D8, 'M', u'ケ'), + (0x32D9, 'M', u'コ'), + (0x32DA, 'M', u'サ'), + (0x32DB, 'M', u'ã‚·'), + (0x32DC, 'M', u'ス'), + (0x32DD, 'M', u'ã‚»'), + (0x32DE, 'M', u'ソ'), + (0x32DF, 'M', u'ã‚¿'), + (0x32E0, 'M', u'ãƒ'), + (0x32E1, 'M', u'ツ'), + (0x32E2, 'M', u'テ'), + (0x32E3, 'M', u'ト'), + (0x32E4, 'M', u'ナ'), + (0x32E5, 'M', u'ニ'), + (0x32E6, 'M', u'ヌ'), + (0x32E7, 'M', u'ãƒ'), + (0x32E8, 'M', u'ノ'), + (0x32E9, 'M', u'ãƒ'), + (0x32EA, 'M', u'ヒ'), + (0x32EB, 'M', u'フ'), + (0x32EC, 'M', u'ヘ'), + (0x32ED, 'M', u'ホ'), + (0x32EE, 'M', u'マ'), + (0x32EF, 'M', u'ミ'), + (0x32F0, 'M', u'ム'), + (0x32F1, 'M', u'メ'), + (0x32F2, 'M', u'モ'), + (0x32F3, 'M', u'ヤ'), + (0x32F4, 'M', u'ユ'), + (0x32F5, 'M', u'ヨ'), + (0x32F6, 'M', u'ラ'), + (0x32F7, 'M', u'リ'), + (0x32F8, 'M', u'ル'), + (0x32F9, 'M', u'レ'), + (0x32FA, 'M', u'ロ'), + (0x32FB, 'M', u'ワ'), + (0x32FC, 'M', u'ヰ'), + (0x32FD, 'M', u'ヱ'), + (0x32FE, 'M', u'ヲ'), + (0x32FF, 'X'), + (0x3300, 'M', u'アパート'), + (0x3301, 'M', u'アルファ'), + (0x3302, 'M', u'アンペア'), + (0x3303, 'M', u'アール'), + (0x3304, 'M', u'イニング'), + (0x3305, 'M', u'インãƒ'), + (0x3306, 'M', u'ウォン'), + (0x3307, 'M', u'エスクード'), + (0x3308, 'M', u'エーカー'), + (0x3309, 'M', u'オンス'), + (0x330A, 'M', u'オーム'), + (0x330B, 'M', u'カイリ'), + (0x330C, 'M', u'カラット'), + (0x330D, 'M', u'カロリー'), + (0x330E, 'M', u'ガロン'), + (0x330F, 'M', u'ガンマ'), + (0x3310, 'M', u'ギガ'), + (0x3311, 'M', u'ギニー'), + (0x3312, 'M', u'キュリー'), + (0x3313, 'M', u'ギルダー'), + (0x3314, 'M', u'キロ'), + (0x3315, 'M', u'キログラム'), + (0x3316, 'M', u'キロメートル'), + (0x3317, 'M', u'キロワット'), + (0x3318, 'M', u'グラム'), + (0x3319, 'M', u'グラムトン'), + (0x331A, 'M', u'クルゼイロ'), + (0x331B, 'M', u'クローãƒ'), + (0x331C, 'M', u'ケース'), + (0x331D, 'M', u'コルナ'), + (0x331E, 'M', u'コーãƒ'), + (0x331F, 'M', u'サイクル'), + (0x3320, 'M', u'サンãƒãƒ¼ãƒ '), + (0x3321, 'M', u'シリング'), + (0x3322, 'M', u'センãƒ'), + (0x3323, 'M', u'セント'), + (0x3324, 'M', u'ダース'), + (0x3325, 'M', u'デシ'), + (0x3326, 'M', u'ドル'), + (0x3327, 'M', u'トン'), + (0x3328, 'M', u'ナノ'), + (0x3329, 'M', u'ノット'), + (0x332A, 'M', u'ãƒã‚¤ãƒ„'), + (0x332B, 'M', u'パーセント'), + (0x332C, 'M', u'パーツ'), + (0x332D, 'M', u'ãƒãƒ¼ãƒ¬ãƒ«'), + (0x332E, 'M', u'ピアストル'), + (0x332F, 'M', u'ピクル'), + (0x3330, 'M', u'ピコ'), + (0x3331, 'M', u'ビル'), + (0x3332, 'M', u'ファラッド'), + (0x3333, 'M', u'フィート'), + (0x3334, 'M', u'ブッシェル'), + (0x3335, 'M', u'フラン'), + (0x3336, 'M', u'ヘクタール'), + (0x3337, 'M', u'ペソ'), + ] + +def _seg_33(): + return [ + (0x3338, 'M', u'ペニヒ'), + (0x3339, 'M', u'ヘルツ'), + (0x333A, 'M', u'ペンス'), + (0x333B, 'M', u'ページ'), + (0x333C, 'M', u'ベータ'), + (0x333D, 'M', u'ãƒã‚¤ãƒ³ãƒˆ'), + (0x333E, 'M', u'ボルト'), + (0x333F, 'M', u'ホン'), + (0x3340, 'M', u'ãƒãƒ³ãƒ‰'), + (0x3341, 'M', u'ホール'), + (0x3342, 'M', u'ホーン'), + (0x3343, 'M', u'マイクロ'), + (0x3344, 'M', u'マイル'), + (0x3345, 'M', u'マッãƒ'), + (0x3346, 'M', u'マルク'), + (0x3347, 'M', u'マンション'), + (0x3348, 'M', u'ミクロン'), + (0x3349, 'M', u'ミリ'), + (0x334A, 'M', u'ミリãƒãƒ¼ãƒ«'), + (0x334B, 'M', u'メガ'), + (0x334C, 'M', u'メガトン'), + (0x334D, 'M', u'メートル'), + (0x334E, 'M', u'ヤード'), + (0x334F, 'M', u'ヤール'), + (0x3350, 'M', u'ユアン'), + (0x3351, 'M', u'リットル'), + (0x3352, 'M', u'リラ'), + (0x3353, 'M', u'ルピー'), + (0x3354, 'M', u'ルーブル'), + (0x3355, 'M', u'レム'), + (0x3356, 'M', u'レントゲン'), + (0x3357, 'M', u'ワット'), + (0x3358, 'M', u'0点'), + (0x3359, 'M', u'1点'), + (0x335A, 'M', u'2点'), + (0x335B, 'M', u'3点'), + (0x335C, 'M', u'4点'), + (0x335D, 'M', u'5点'), + (0x335E, 'M', u'6点'), + (0x335F, 'M', u'7点'), + (0x3360, 'M', u'8点'), + (0x3361, 'M', u'9点'), + (0x3362, 'M', u'10点'), + (0x3363, 'M', u'11点'), + (0x3364, 'M', u'12点'), + (0x3365, 'M', u'13点'), + (0x3366, 'M', u'14点'), + (0x3367, 'M', u'15点'), + (0x3368, 'M', u'16点'), + (0x3369, 'M', u'17点'), + (0x336A, 'M', u'18点'), + (0x336B, 'M', u'19点'), + (0x336C, 'M', u'20点'), + (0x336D, 'M', u'21点'), + (0x336E, 'M', u'22点'), + (0x336F, 'M', u'23点'), + (0x3370, 'M', u'24点'), + (0x3371, 'M', u'hpa'), + (0x3372, 'M', u'da'), + (0x3373, 'M', u'au'), + (0x3374, 'M', u'bar'), + (0x3375, 'M', u'ov'), + (0x3376, 'M', u'pc'), + (0x3377, 'M', u'dm'), + (0x3378, 'M', u'dm2'), + (0x3379, 'M', u'dm3'), + (0x337A, 'M', u'iu'), + (0x337B, 'M', u'å¹³æˆ'), + (0x337C, 'M', u'昭和'), + (0x337D, 'M', u'大正'), + (0x337E, 'M', u'明治'), + (0x337F, 'M', u'æ ªå¼ä¼šç¤¾'), + (0x3380, 'M', u'pa'), + (0x3381, 'M', u'na'), + (0x3382, 'M', u'μa'), + (0x3383, 'M', u'ma'), + (0x3384, 'M', u'ka'), + (0x3385, 'M', u'kb'), + (0x3386, 'M', u'mb'), + (0x3387, 'M', u'gb'), + (0x3388, 'M', u'cal'), + (0x3389, 'M', u'kcal'), + (0x338A, 'M', u'pf'), + (0x338B, 'M', u'nf'), + (0x338C, 'M', u'μf'), + (0x338D, 'M', u'μg'), + (0x338E, 'M', u'mg'), + (0x338F, 'M', u'kg'), + (0x3390, 'M', u'hz'), + (0x3391, 'M', u'khz'), + (0x3392, 'M', u'mhz'), + (0x3393, 'M', u'ghz'), + (0x3394, 'M', u'thz'), + (0x3395, 'M', u'μl'), + (0x3396, 'M', u'ml'), + (0x3397, 'M', u'dl'), + (0x3398, 'M', u'kl'), + (0x3399, 'M', u'fm'), + (0x339A, 'M', u'nm'), + (0x339B, 'M', u'μm'), + ] + +def _seg_34(): + return [ + (0x339C, 'M', u'mm'), + (0x339D, 'M', u'cm'), + (0x339E, 'M', u'km'), + (0x339F, 'M', u'mm2'), + (0x33A0, 'M', u'cm2'), + (0x33A1, 'M', u'm2'), + (0x33A2, 'M', u'km2'), + (0x33A3, 'M', u'mm3'), + (0x33A4, 'M', u'cm3'), + (0x33A5, 'M', u'm3'), + (0x33A6, 'M', u'km3'), + (0x33A7, 'M', u'm∕s'), + (0x33A8, 'M', u'm∕s2'), + (0x33A9, 'M', u'pa'), + (0x33AA, 'M', u'kpa'), + (0x33AB, 'M', u'mpa'), + (0x33AC, 'M', u'gpa'), + (0x33AD, 'M', u'rad'), + (0x33AE, 'M', u'rad∕s'), + (0x33AF, 'M', u'rad∕s2'), + (0x33B0, 'M', u'ps'), + (0x33B1, 'M', u'ns'), + (0x33B2, 'M', u'μs'), + (0x33B3, 'M', u'ms'), + (0x33B4, 'M', u'pv'), + (0x33B5, 'M', u'nv'), + (0x33B6, 'M', u'μv'), + (0x33B7, 'M', u'mv'), + (0x33B8, 'M', u'kv'), + (0x33B9, 'M', u'mv'), + (0x33BA, 'M', u'pw'), + (0x33BB, 'M', u'nw'), + (0x33BC, 'M', u'μw'), + (0x33BD, 'M', u'mw'), + (0x33BE, 'M', u'kw'), + (0x33BF, 'M', u'mw'), + (0x33C0, 'M', u'kω'), + (0x33C1, 'M', u'mω'), + (0x33C2, 'X'), + (0x33C3, 'M', u'bq'), + (0x33C4, 'M', u'cc'), + (0x33C5, 'M', u'cd'), + (0x33C6, 'M', u'c∕kg'), + (0x33C7, 'X'), + (0x33C8, 'M', u'db'), + (0x33C9, 'M', u'gy'), + (0x33CA, 'M', u'ha'), + (0x33CB, 'M', u'hp'), + (0x33CC, 'M', u'in'), + (0x33CD, 'M', u'kk'), + (0x33CE, 'M', u'km'), + (0x33CF, 'M', u'kt'), + (0x33D0, 'M', u'lm'), + (0x33D1, 'M', u'ln'), + (0x33D2, 'M', u'log'), + (0x33D3, 'M', u'lx'), + (0x33D4, 'M', u'mb'), + (0x33D5, 'M', u'mil'), + (0x33D6, 'M', u'mol'), + (0x33D7, 'M', u'ph'), + (0x33D8, 'X'), + (0x33D9, 'M', u'ppm'), + (0x33DA, 'M', u'pr'), + (0x33DB, 'M', u'sr'), + (0x33DC, 'M', u'sv'), + (0x33DD, 'M', u'wb'), + (0x33DE, 'M', u'v∕m'), + (0x33DF, 'M', u'a∕m'), + (0x33E0, 'M', u'1æ—¥'), + (0x33E1, 'M', u'2æ—¥'), + (0x33E2, 'M', u'3æ—¥'), + (0x33E3, 'M', u'4æ—¥'), + (0x33E4, 'M', u'5æ—¥'), + (0x33E5, 'M', u'6æ—¥'), + (0x33E6, 'M', u'7æ—¥'), + (0x33E7, 'M', u'8æ—¥'), + (0x33E8, 'M', u'9æ—¥'), + (0x33E9, 'M', u'10æ—¥'), + (0x33EA, 'M', u'11æ—¥'), + (0x33EB, 'M', u'12æ—¥'), + (0x33EC, 'M', u'13æ—¥'), + (0x33ED, 'M', u'14æ—¥'), + (0x33EE, 'M', u'15æ—¥'), + (0x33EF, 'M', u'16æ—¥'), + (0x33F0, 'M', u'17æ—¥'), + (0x33F1, 'M', u'18æ—¥'), + (0x33F2, 'M', u'19æ—¥'), + (0x33F3, 'M', u'20æ—¥'), + (0x33F4, 'M', u'21æ—¥'), + (0x33F5, 'M', u'22æ—¥'), + (0x33F6, 'M', u'23æ—¥'), + (0x33F7, 'M', u'24æ—¥'), + (0x33F8, 'M', u'25æ—¥'), + (0x33F9, 'M', u'26æ—¥'), + (0x33FA, 'M', u'27æ—¥'), + (0x33FB, 'M', u'28æ—¥'), + (0x33FC, 'M', u'29æ—¥'), + (0x33FD, 'M', u'30æ—¥'), + (0x33FE, 'M', u'31æ—¥'), + (0x33FF, 'M', u'gal'), + ] + +def _seg_35(): + return [ + (0x3400, 'V'), + (0x4DB6, 'X'), + (0x4DC0, 'V'), + (0x9FCD, 'X'), + (0xA000, 'V'), + (0xA48D, 'X'), + (0xA490, 'V'), + (0xA4C7, 'X'), + (0xA4D0, 'V'), + (0xA62C, 'X'), + (0xA640, 'M', u'ê™'), + (0xA641, 'V'), + (0xA642, 'M', u'ꙃ'), + (0xA643, 'V'), + (0xA644, 'M', u'ê™…'), + (0xA645, 'V'), + (0xA646, 'M', u'ꙇ'), + (0xA647, 'V'), + (0xA648, 'M', u'ꙉ'), + (0xA649, 'V'), + (0xA64A, 'M', u'ꙋ'), + (0xA64B, 'V'), + (0xA64C, 'M', u'ê™'), + (0xA64D, 'V'), + (0xA64E, 'M', u'ê™'), + (0xA64F, 'V'), + (0xA650, 'M', u'ꙑ'), + (0xA651, 'V'), + (0xA652, 'M', u'ꙓ'), + (0xA653, 'V'), + (0xA654, 'M', u'ꙕ'), + (0xA655, 'V'), + (0xA656, 'M', u'ê™—'), + (0xA657, 'V'), + (0xA658, 'M', u'ê™™'), + (0xA659, 'V'), + (0xA65A, 'M', u'ê™›'), + (0xA65B, 'V'), + (0xA65C, 'M', u'ê™'), + (0xA65D, 'V'), + (0xA65E, 'M', u'ꙟ'), + (0xA65F, 'V'), + (0xA660, 'M', u'ꙡ'), + (0xA661, 'V'), + (0xA662, 'M', u'ꙣ'), + (0xA663, 'V'), + (0xA664, 'M', u'ꙥ'), + (0xA665, 'V'), + (0xA666, 'M', u'ê™§'), + (0xA667, 'V'), + (0xA668, 'M', u'ꙩ'), + (0xA669, 'V'), + (0xA66A, 'M', u'ꙫ'), + (0xA66B, 'V'), + (0xA66C, 'M', u'ê™­'), + (0xA66D, 'V'), + (0xA680, 'M', u'êš'), + (0xA681, 'V'), + (0xA682, 'M', u'ꚃ'), + (0xA683, 'V'), + (0xA684, 'M', u'êš…'), + (0xA685, 'V'), + (0xA686, 'M', u'ꚇ'), + (0xA687, 'V'), + (0xA688, 'M', u'ꚉ'), + (0xA689, 'V'), + (0xA68A, 'M', u'êš‹'), + (0xA68B, 'V'), + (0xA68C, 'M', u'êš'), + (0xA68D, 'V'), + (0xA68E, 'M', u'êš'), + (0xA68F, 'V'), + (0xA690, 'M', u'êš‘'), + (0xA691, 'V'), + (0xA692, 'M', u'êš“'), + (0xA693, 'V'), + (0xA694, 'M', u'êš•'), + (0xA695, 'V'), + (0xA696, 'M', u'êš—'), + (0xA697, 'V'), + (0xA698, 'X'), + (0xA69F, 'V'), + (0xA6F8, 'X'), + (0xA700, 'V'), + (0xA722, 'M', u'ꜣ'), + (0xA723, 'V'), + (0xA724, 'M', u'ꜥ'), + (0xA725, 'V'), + (0xA726, 'M', u'ꜧ'), + (0xA727, 'V'), + (0xA728, 'M', u'ꜩ'), + (0xA729, 'V'), + (0xA72A, 'M', u'ꜫ'), + (0xA72B, 'V'), + (0xA72C, 'M', u'ꜭ'), + (0xA72D, 'V'), + (0xA72E, 'M', u'ꜯ'), + (0xA72F, 'V'), + (0xA732, 'M', u'ꜳ'), + (0xA733, 'V'), + ] + +def _seg_36(): + return [ + (0xA734, 'M', u'ꜵ'), + (0xA735, 'V'), + (0xA736, 'M', u'ꜷ'), + (0xA737, 'V'), + (0xA738, 'M', u'ꜹ'), + (0xA739, 'V'), + (0xA73A, 'M', u'ꜻ'), + (0xA73B, 'V'), + (0xA73C, 'M', u'ꜽ'), + (0xA73D, 'V'), + (0xA73E, 'M', u'ꜿ'), + (0xA73F, 'V'), + (0xA740, 'M', u'ê'), + (0xA741, 'V'), + (0xA742, 'M', u'êƒ'), + (0xA743, 'V'), + (0xA744, 'M', u'ê…'), + (0xA745, 'V'), + (0xA746, 'M', u'ê‡'), + (0xA747, 'V'), + (0xA748, 'M', u'ê‰'), + (0xA749, 'V'), + (0xA74A, 'M', u'ê‹'), + (0xA74B, 'V'), + (0xA74C, 'M', u'ê'), + (0xA74D, 'V'), + (0xA74E, 'M', u'ê'), + (0xA74F, 'V'), + (0xA750, 'M', u'ê‘'), + (0xA751, 'V'), + (0xA752, 'M', u'ê“'), + (0xA753, 'V'), + (0xA754, 'M', u'ê•'), + (0xA755, 'V'), + (0xA756, 'M', u'ê—'), + (0xA757, 'V'), + (0xA758, 'M', u'ê™'), + (0xA759, 'V'), + (0xA75A, 'M', u'ê›'), + (0xA75B, 'V'), + (0xA75C, 'M', u'ê'), + (0xA75D, 'V'), + (0xA75E, 'M', u'êŸ'), + (0xA75F, 'V'), + (0xA760, 'M', u'ê¡'), + (0xA761, 'V'), + (0xA762, 'M', u'ê£'), + (0xA763, 'V'), + (0xA764, 'M', u'ê¥'), + (0xA765, 'V'), + (0xA766, 'M', u'ê§'), + (0xA767, 'V'), + (0xA768, 'M', u'ê©'), + (0xA769, 'V'), + (0xA76A, 'M', u'ê«'), + (0xA76B, 'V'), + (0xA76C, 'M', u'ê­'), + (0xA76D, 'V'), + (0xA76E, 'M', u'ê¯'), + (0xA76F, 'V'), + (0xA770, 'M', u'ê¯'), + (0xA771, 'V'), + (0xA779, 'M', u'êº'), + (0xA77A, 'V'), + (0xA77B, 'M', u'ê¼'), + (0xA77C, 'V'), + (0xA77D, 'M', u'áµ¹'), + (0xA77E, 'M', u'ê¿'), + (0xA77F, 'V'), + (0xA780, 'M', u'êž'), + (0xA781, 'V'), + (0xA782, 'M', u'ꞃ'), + (0xA783, 'V'), + (0xA784, 'M', u'êž…'), + (0xA785, 'V'), + (0xA786, 'M', u'ꞇ'), + (0xA787, 'V'), + (0xA78B, 'M', u'ꞌ'), + (0xA78C, 'V'), + (0xA78D, 'M', u'É¥'), + (0xA78E, 'V'), + (0xA78F, 'X'), + (0xA790, 'M', u'êž‘'), + (0xA791, 'V'), + (0xA792, 'M', u'êž“'), + (0xA793, 'V'), + (0xA794, 'X'), + (0xA7A0, 'M', u'êž¡'), + (0xA7A1, 'V'), + (0xA7A2, 'M', u'ꞣ'), + (0xA7A3, 'V'), + (0xA7A4, 'M', u'ꞥ'), + (0xA7A5, 'V'), + (0xA7A6, 'M', u'êž§'), + (0xA7A7, 'V'), + (0xA7A8, 'M', u'êž©'), + (0xA7A9, 'V'), + (0xA7AA, 'M', u'ɦ'), + (0xA7AB, 'X'), + (0xA7F8, 'M', u'ħ'), + ] + +def _seg_37(): + return [ + (0xA7F9, 'M', u'Å“'), + (0xA7FA, 'V'), + (0xA82C, 'X'), + (0xA830, 'V'), + (0xA83A, 'X'), + (0xA840, 'V'), + (0xA878, 'X'), + (0xA880, 'V'), + (0xA8C5, 'X'), + (0xA8CE, 'V'), + (0xA8DA, 'X'), + (0xA8E0, 'V'), + (0xA8FC, 'X'), + (0xA900, 'V'), + (0xA954, 'X'), + (0xA95F, 'V'), + (0xA97D, 'X'), + (0xA980, 'V'), + (0xA9CE, 'X'), + (0xA9CF, 'V'), + (0xA9DA, 'X'), + (0xA9DE, 'V'), + (0xA9E0, 'X'), + (0xAA00, 'V'), + (0xAA37, 'X'), + (0xAA40, 'V'), + (0xAA4E, 'X'), + (0xAA50, 'V'), + (0xAA5A, 'X'), + (0xAA5C, 'V'), + (0xAA7C, 'X'), + (0xAA80, 'V'), + (0xAAC3, 'X'), + (0xAADB, 'V'), + (0xAAF7, 'X'), + (0xAB01, 'V'), + (0xAB07, 'X'), + (0xAB09, 'V'), + (0xAB0F, 'X'), + (0xAB11, 'V'), + (0xAB17, 'X'), + (0xAB20, 'V'), + (0xAB27, 'X'), + (0xAB28, 'V'), + (0xAB2F, 'X'), + (0xABC0, 'V'), + (0xABEE, 'X'), + (0xABF0, 'V'), + (0xABFA, 'X'), + (0xAC00, 'V'), + (0xD7A4, 'X'), + (0xD7B0, 'V'), + (0xD7C7, 'X'), + (0xD7CB, 'V'), + (0xD7FC, 'X'), + (0xF900, 'M', u'豈'), + (0xF901, 'M', u'æ›´'), + (0xF902, 'M', u'車'), + (0xF903, 'M', u'賈'), + (0xF904, 'M', u'滑'), + (0xF905, 'M', u'串'), + (0xF906, 'M', u'å¥'), + (0xF907, 'M', u'龜'), + (0xF909, 'M', u'契'), + (0xF90A, 'M', u'金'), + (0xF90B, 'M', u'å–‡'), + (0xF90C, 'M', u'奈'), + (0xF90D, 'M', u'懶'), + (0xF90E, 'M', u'癩'), + (0xF90F, 'M', u'ç¾…'), + (0xF910, 'M', u'蘿'), + (0xF911, 'M', u'螺'), + (0xF912, 'M', u'裸'), + (0xF913, 'M', u'é‚'), + (0xF914, 'M', u'樂'), + (0xF915, 'M', u'æ´›'), + (0xF916, 'M', u'烙'), + (0xF917, 'M', u'çž'), + (0xF918, 'M', u'è½'), + (0xF919, 'M', u'é…ª'), + (0xF91A, 'M', u'é§±'), + (0xF91B, 'M', u'亂'), + (0xF91C, 'M', u'åµ'), + (0xF91D, 'M', u'欄'), + (0xF91E, 'M', u'爛'), + (0xF91F, 'M', u'蘭'), + (0xF920, 'M', u'鸞'), + (0xF921, 'M', u'åµ'), + (0xF922, 'M', u'æ¿«'), + (0xF923, 'M', u'è—'), + (0xF924, 'M', u'襤'), + (0xF925, 'M', u'拉'), + (0xF926, 'M', u'臘'), + (0xF927, 'M', u'è Ÿ'), + (0xF928, 'M', u'廊'), + (0xF929, 'M', u'朗'), + (0xF92A, 'M', u'浪'), + (0xF92B, 'M', u'狼'), + (0xF92C, 'M', u'郎'), + (0xF92D, 'M', u'來'), + ] + +def _seg_38(): + return [ + (0xF92E, 'M', u'冷'), + (0xF92F, 'M', u'勞'), + (0xF930, 'M', u'æ“„'), + (0xF931, 'M', u'æ«“'), + (0xF932, 'M', u'çˆ'), + (0xF933, 'M', u'ç›§'), + (0xF934, 'M', u'è€'), + (0xF935, 'M', u'蘆'), + (0xF936, 'M', u'虜'), + (0xF937, 'M', u'è·¯'), + (0xF938, 'M', u'露'), + (0xF939, 'M', u'é­¯'), + (0xF93A, 'M', u'é·º'), + (0xF93B, 'M', u'碌'), + (0xF93C, 'M', u'祿'), + (0xF93D, 'M', u'ç¶ '), + (0xF93E, 'M', u'è‰'), + (0xF93F, 'M', u'錄'), + (0xF940, 'M', u'鹿'), + (0xF941, 'M', u'è«–'), + (0xF942, 'M', u'壟'), + (0xF943, 'M', u'弄'), + (0xF944, 'M', u'ç± '), + (0xF945, 'M', u'è¾'), + (0xF946, 'M', u'牢'), + (0xF947, 'M', u'磊'), + (0xF948, 'M', u'賂'), + (0xF949, 'M', u'é›·'), + (0xF94A, 'M', u'壘'), + (0xF94B, 'M', u'å±¢'), + (0xF94C, 'M', u'樓'), + (0xF94D, 'M', u'æ·š'), + (0xF94E, 'M', u'æ¼'), + (0xF94F, 'M', u'ç´¯'), + (0xF950, 'M', u'縷'), + (0xF951, 'M', u'陋'), + (0xF952, 'M', u'å‹’'), + (0xF953, 'M', u'è‚‹'), + (0xF954, 'M', u'凜'), + (0xF955, 'M', u'凌'), + (0xF956, 'M', u'稜'), + (0xF957, 'M', u'ç¶¾'), + (0xF958, 'M', u'è±'), + (0xF959, 'M', u'陵'), + (0xF95A, 'M', u'讀'), + (0xF95B, 'M', u'æ‹'), + (0xF95C, 'M', u'樂'), + (0xF95D, 'M', u'諾'), + (0xF95E, 'M', u'丹'), + (0xF95F, 'M', u'寧'), + (0xF960, 'M', u'怒'), + (0xF961, 'M', u'率'), + (0xF962, 'M', u'ç•°'), + (0xF963, 'M', u'北'), + (0xF964, 'M', u'磻'), + (0xF965, 'M', u'便'), + (0xF966, 'M', u'復'), + (0xF967, 'M', u'ä¸'), + (0xF968, 'M', u'泌'), + (0xF969, 'M', u'數'), + (0xF96A, 'M', u'ç´¢'), + (0xF96B, 'M', u'åƒ'), + (0xF96C, 'M', u'塞'), + (0xF96D, 'M', u'çœ'), + (0xF96E, 'M', u'葉'), + (0xF96F, 'M', u'說'), + (0xF970, 'M', u'殺'), + (0xF971, 'M', u'è¾°'), + (0xF972, 'M', u'沈'), + (0xF973, 'M', u'拾'), + (0xF974, 'M', u'è‹¥'), + (0xF975, 'M', u'掠'), + (0xF976, 'M', u'ç•¥'), + (0xF977, 'M', u'亮'), + (0xF978, 'M', u'å…©'), + (0xF979, 'M', u'凉'), + (0xF97A, 'M', u'æ¢'), + (0xF97B, 'M', u'ç³§'), + (0xF97C, 'M', u'良'), + (0xF97D, 'M', u'è«’'), + (0xF97E, 'M', u'é‡'), + (0xF97F, 'M', u'勵'), + (0xF980, 'M', u'å‘‚'), + (0xF981, 'M', u'女'), + (0xF982, 'M', u'廬'), + (0xF983, 'M', u'æ—…'), + (0xF984, 'M', u'濾'), + (0xF985, 'M', u'礪'), + (0xF986, 'M', u'é–­'), + (0xF987, 'M', u'驪'), + (0xF988, 'M', u'麗'), + (0xF989, 'M', u'黎'), + (0xF98A, 'M', u'力'), + (0xF98B, 'M', u'曆'), + (0xF98C, 'M', u'æ­·'), + (0xF98D, 'M', u'è½¢'), + (0xF98E, 'M', u'å¹´'), + (0xF98F, 'M', u'æ†'), + (0xF990, 'M', u'戀'), + (0xF991, 'M', u'æ’š'), + ] + +def _seg_39(): + return [ + (0xF992, 'M', u'æ¼£'), + (0xF993, 'M', u'ç…‰'), + (0xF994, 'M', u'ç’‰'), + (0xF995, 'M', u'ç§Š'), + (0xF996, 'M', u'ç·´'), + (0xF997, 'M', u'è¯'), + (0xF998, 'M', u'輦'), + (0xF999, 'M', u'è“®'), + (0xF99A, 'M', u'連'), + (0xF99B, 'M', u'éŠ'), + (0xF99C, 'M', u'列'), + (0xF99D, 'M', u'劣'), + (0xF99E, 'M', u'å’½'), + (0xF99F, 'M', u'烈'), + (0xF9A0, 'M', u'裂'), + (0xF9A1, 'M', u'說'), + (0xF9A2, 'M', u'廉'), + (0xF9A3, 'M', u'念'), + (0xF9A4, 'M', u'æ»'), + (0xF9A5, 'M', u'æ®®'), + (0xF9A6, 'M', u'ç°¾'), + (0xF9A7, 'M', u'çµ'), + (0xF9A8, 'M', u'令'), + (0xF9A9, 'M', u'囹'), + (0xF9AA, 'M', u'寧'), + (0xF9AB, 'M', u'嶺'), + (0xF9AC, 'M', u'怜'), + (0xF9AD, 'M', u'玲'), + (0xF9AE, 'M', u'ç‘©'), + (0xF9AF, 'M', u'羚'), + (0xF9B0, 'M', u'è†'), + (0xF9B1, 'M', u'鈴'), + (0xF9B2, 'M', u'é›¶'), + (0xF9B3, 'M', u'éˆ'), + (0xF9B4, 'M', u'é ˜'), + (0xF9B5, 'M', u'例'), + (0xF9B6, 'M', u'禮'), + (0xF9B7, 'M', u'醴'), + (0xF9B8, 'M', u'隸'), + (0xF9B9, 'M', u'惡'), + (0xF9BA, 'M', u'了'), + (0xF9BB, 'M', u'僚'), + (0xF9BC, 'M', u'寮'), + (0xF9BD, 'M', u'å°¿'), + (0xF9BE, 'M', u'æ–™'), + (0xF9BF, 'M', u'樂'), + (0xF9C0, 'M', u'燎'), + (0xF9C1, 'M', u'療'), + (0xF9C2, 'M', u'蓼'), + (0xF9C3, 'M', u'é¼'), + (0xF9C4, 'M', u'é¾'), + (0xF9C5, 'M', u'暈'), + (0xF9C6, 'M', u'阮'), + (0xF9C7, 'M', u'劉'), + (0xF9C8, 'M', u'æ»'), + (0xF9C9, 'M', u'柳'), + (0xF9CA, 'M', u'æµ'), + (0xF9CB, 'M', u'溜'), + (0xF9CC, 'M', u'ç‰'), + (0xF9CD, 'M', u'ç•™'), + (0xF9CE, 'M', u'ç¡«'), + (0xF9CF, 'M', u'ç´'), + (0xF9D0, 'M', u'類'), + (0xF9D1, 'M', u'å…­'), + (0xF9D2, 'M', u'戮'), + (0xF9D3, 'M', u'陸'), + (0xF9D4, 'M', u'倫'), + (0xF9D5, 'M', u'å´™'), + (0xF9D6, 'M', u'æ·ª'), + (0xF9D7, 'M', u'輪'), + (0xF9D8, 'M', u'律'), + (0xF9D9, 'M', u'æ…„'), + (0xF9DA, 'M', u'æ —'), + (0xF9DB, 'M', u'率'), + (0xF9DC, 'M', u'隆'), + (0xF9DD, 'M', u'利'), + (0xF9DE, 'M', u'å'), + (0xF9DF, 'M', u'å±¥'), + (0xF9E0, 'M', u'易'), + (0xF9E1, 'M', u'æŽ'), + (0xF9E2, 'M', u'梨'), + (0xF9E3, 'M', u'æ³¥'), + (0xF9E4, 'M', u'ç†'), + (0xF9E5, 'M', u'ç—¢'), + (0xF9E6, 'M', u'ç½¹'), + (0xF9E7, 'M', u'è£'), + (0xF9E8, 'M', u'裡'), + (0xF9E9, 'M', u'里'), + (0xF9EA, 'M', u'離'), + (0xF9EB, 'M', u'匿'), + (0xF9EC, 'M', u'溺'), + (0xF9ED, 'M', u'å'), + (0xF9EE, 'M', u'ç‡'), + (0xF9EF, 'M', u'ç’˜'), + (0xF9F0, 'M', u'è—º'), + (0xF9F1, 'M', u'隣'), + (0xF9F2, 'M', u'é±—'), + (0xF9F3, 'M', u'麟'), + (0xF9F4, 'M', u'æž—'), + (0xF9F5, 'M', u'æ·‹'), + ] + +def _seg_40(): + return [ + (0xF9F6, 'M', u'臨'), + (0xF9F7, 'M', u'ç«‹'), + (0xF9F8, 'M', u'笠'), + (0xF9F9, 'M', u'ç²’'), + (0xF9FA, 'M', u'ç‹€'), + (0xF9FB, 'M', u'ç‚™'), + (0xF9FC, 'M', u'è­˜'), + (0xF9FD, 'M', u'什'), + (0xF9FE, 'M', u'茶'), + (0xF9FF, 'M', u'刺'), + (0xFA00, 'M', u'切'), + (0xFA01, 'M', u'度'), + (0xFA02, 'M', u'æ‹“'), + (0xFA03, 'M', u'ç³–'), + (0xFA04, 'M', u'å®…'), + (0xFA05, 'M', u'æ´ž'), + (0xFA06, 'M', u'æš´'), + (0xFA07, 'M', u'è¼»'), + (0xFA08, 'M', u'行'), + (0xFA09, 'M', u'é™'), + (0xFA0A, 'M', u'見'), + (0xFA0B, 'M', u'廓'), + (0xFA0C, 'M', u'å…€'), + (0xFA0D, 'M', u'å—€'), + (0xFA0E, 'V'), + (0xFA10, 'M', u'塚'), + (0xFA11, 'V'), + (0xFA12, 'M', u'æ™´'), + (0xFA13, 'V'), + (0xFA15, 'M', u'凞'), + (0xFA16, 'M', u'猪'), + (0xFA17, 'M', u'益'), + (0xFA18, 'M', u'礼'), + (0xFA19, 'M', u'神'), + (0xFA1A, 'M', u'祥'), + (0xFA1B, 'M', u'ç¦'), + (0xFA1C, 'M', u'é–'), + (0xFA1D, 'M', u'ç²¾'), + (0xFA1E, 'M', u'ç¾½'), + (0xFA1F, 'V'), + (0xFA20, 'M', u'蘒'), + (0xFA21, 'V'), + (0xFA22, 'M', u'諸'), + (0xFA23, 'V'), + (0xFA25, 'M', u'逸'), + (0xFA26, 'M', u'都'), + (0xFA27, 'V'), + (0xFA2A, 'M', u'飯'), + (0xFA2B, 'M', u'飼'), + (0xFA2C, 'M', u'館'), + (0xFA2D, 'M', u'é¶´'), + (0xFA2E, 'M', u'郞'), + (0xFA2F, 'M', u'éš·'), + (0xFA30, 'M', u'ä¾®'), + (0xFA31, 'M', u'僧'), + (0xFA32, 'M', u'å…'), + (0xFA33, 'M', u'勉'), + (0xFA34, 'M', u'勤'), + (0xFA35, 'M', u'å‘'), + (0xFA36, 'M', u'å–'), + (0xFA37, 'M', u'嘆'), + (0xFA38, 'M', u'器'), + (0xFA39, 'M', u'å¡€'), + (0xFA3A, 'M', u'墨'), + (0xFA3B, 'M', u'層'), + (0xFA3C, 'M', u'å±®'), + (0xFA3D, 'M', u'æ‚”'), + (0xFA3E, 'M', u'æ…¨'), + (0xFA3F, 'M', u'憎'), + (0xFA40, 'M', u'懲'), + (0xFA41, 'M', u'æ•'), + (0xFA42, 'M', u'æ—¢'), + (0xFA43, 'M', u'æš‘'), + (0xFA44, 'M', u'梅'), + (0xFA45, 'M', u'æµ·'), + (0xFA46, 'M', u'渚'), + (0xFA47, 'M', u'æ¼¢'), + (0xFA48, 'M', u'ç…®'), + (0xFA49, 'M', u'爫'), + (0xFA4A, 'M', u'ç¢'), + (0xFA4B, 'M', u'碑'), + (0xFA4C, 'M', u'社'), + (0xFA4D, 'M', u'祉'), + (0xFA4E, 'M', u'祈'), + (0xFA4F, 'M', u'ç¥'), + (0xFA50, 'M', u'祖'), + (0xFA51, 'M', u'ç¥'), + (0xFA52, 'M', u'ç¦'), + (0xFA53, 'M', u'禎'), + (0xFA54, 'M', u'ç©€'), + (0xFA55, 'M', u'çª'), + (0xFA56, 'M', u'節'), + (0xFA57, 'M', u'ç·´'), + (0xFA58, 'M', u'縉'), + (0xFA59, 'M', u'ç¹'), + (0xFA5A, 'M', u'ç½²'), + (0xFA5B, 'M', u'者'), + (0xFA5C, 'M', u'臭'), + (0xFA5D, 'M', u'艹'), + (0xFA5F, 'M', u'è‘—'), + ] + +def _seg_41(): + return [ + (0xFA60, 'M', u'è¤'), + (0xFA61, 'M', u'視'), + (0xFA62, 'M', u'è¬'), + (0xFA63, 'M', u'謹'), + (0xFA64, 'M', u'賓'), + (0xFA65, 'M', u'è´ˆ'), + (0xFA66, 'M', u'è¾¶'), + (0xFA67, 'M', u'逸'), + (0xFA68, 'M', u'難'), + (0xFA69, 'M', u'響'), + (0xFA6A, 'M', u'é »'), + (0xFA6B, 'M', u'æµ'), + (0xFA6C, 'M', u'𤋮'), + (0xFA6D, 'M', u'舘'), + (0xFA6E, 'X'), + (0xFA70, 'M', u'並'), + (0xFA71, 'M', u'况'), + (0xFA72, 'M', u'å…¨'), + (0xFA73, 'M', u'ä¾€'), + (0xFA74, 'M', u'å……'), + (0xFA75, 'M', u'冀'), + (0xFA76, 'M', u'勇'), + (0xFA77, 'M', u'勺'), + (0xFA78, 'M', u'å–'), + (0xFA79, 'M', u'å••'), + (0xFA7A, 'M', u'å–™'), + (0xFA7B, 'M', u'å—¢'), + (0xFA7C, 'M', u'塚'), + (0xFA7D, 'M', u'墳'), + (0xFA7E, 'M', u'奄'), + (0xFA7F, 'M', u'奔'), + (0xFA80, 'M', u'å©¢'), + (0xFA81, 'M', u'嬨'), + (0xFA82, 'M', u'å»’'), + (0xFA83, 'M', u'å»™'), + (0xFA84, 'M', u'彩'), + (0xFA85, 'M', u'å¾­'), + (0xFA86, 'M', u'惘'), + (0xFA87, 'M', u'æ…Ž'), + (0xFA88, 'M', u'愈'), + (0xFA89, 'M', u'憎'), + (0xFA8A, 'M', u'æ… '), + (0xFA8B, 'M', u'懲'), + (0xFA8C, 'M', u'戴'), + (0xFA8D, 'M', u'æ„'), + (0xFA8E, 'M', u'æœ'), + (0xFA8F, 'M', u'æ‘’'), + (0xFA90, 'M', u'æ•–'), + (0xFA91, 'M', u'æ™´'), + (0xFA92, 'M', u'朗'), + (0xFA93, 'M', u'望'), + (0xFA94, 'M', u'æ–'), + (0xFA95, 'M', u'æ­¹'), + (0xFA96, 'M', u'殺'), + (0xFA97, 'M', u'æµ'), + (0xFA98, 'M', u'æ»›'), + (0xFA99, 'M', u'滋'), + (0xFA9A, 'M', u'æ¼¢'), + (0xFA9B, 'M', u'瀞'), + (0xFA9C, 'M', u'ç…®'), + (0xFA9D, 'M', u'çž§'), + (0xFA9E, 'M', u'爵'), + (0xFA9F, 'M', u'犯'), + (0xFAA0, 'M', u'猪'), + (0xFAA1, 'M', u'瑱'), + (0xFAA2, 'M', u'甆'), + (0xFAA3, 'M', u'ç”»'), + (0xFAA4, 'M', u'ç˜'), + (0xFAA5, 'M', u'瘟'), + (0xFAA6, 'M', u'益'), + (0xFAA7, 'M', u'ç››'), + (0xFAA8, 'M', u'ç›´'), + (0xFAA9, 'M', u'çŠ'), + (0xFAAA, 'M', u'ç€'), + (0xFAAB, 'M', u'磌'), + (0xFAAC, 'M', u'窱'), + (0xFAAD, 'M', u'節'), + (0xFAAE, 'M', u'ç±»'), + (0xFAAF, 'M', u'çµ›'), + (0xFAB0, 'M', u'ç·´'), + (0xFAB1, 'M', u'ç¼¾'), + (0xFAB2, 'M', u'者'), + (0xFAB3, 'M', u'è’'), + (0xFAB4, 'M', u'è¯'), + (0xFAB5, 'M', u'è¹'), + (0xFAB6, 'M', u'è¥'), + (0xFAB7, 'M', u'覆'), + (0xFAB8, 'M', u'視'), + (0xFAB9, 'M', u'調'), + (0xFABA, 'M', u'諸'), + (0xFABB, 'M', u'è«‹'), + (0xFABC, 'M', u'è¬'), + (0xFABD, 'M', u'諾'), + (0xFABE, 'M', u'è«­'), + (0xFABF, 'M', u'謹'), + (0xFAC0, 'M', u'變'), + (0xFAC1, 'M', u'è´ˆ'), + (0xFAC2, 'M', u'輸'), + (0xFAC3, 'M', u'é²'), + (0xFAC4, 'M', u'醙'), + ] + +def _seg_42(): + return [ + (0xFAC5, 'M', u'鉶'), + (0xFAC6, 'M', u'陼'), + (0xFAC7, 'M', u'難'), + (0xFAC8, 'M', u'é–'), + (0xFAC9, 'M', u'韛'), + (0xFACA, 'M', u'響'), + (0xFACB, 'M', u'é ‹'), + (0xFACC, 'M', u'é »'), + (0xFACD, 'M', u'鬒'), + (0xFACE, 'M', u'龜'), + (0xFACF, 'M', u'𢡊'), + (0xFAD0, 'M', u'𢡄'), + (0xFAD1, 'M', u'ð£•'), + (0xFAD2, 'M', u'ã®'), + (0xFAD3, 'M', u'䀘'), + (0xFAD4, 'M', u'䀹'), + (0xFAD5, 'M', u'𥉉'), + (0xFAD6, 'M', u'ð¥³'), + (0xFAD7, 'M', u'𧻓'), + (0xFAD8, 'M', u'齃'), + (0xFAD9, 'M', u'龎'), + (0xFADA, 'X'), + (0xFB00, 'M', u'ff'), + (0xFB01, 'M', u'fi'), + (0xFB02, 'M', u'fl'), + (0xFB03, 'M', u'ffi'), + (0xFB04, 'M', u'ffl'), + (0xFB05, 'M', u'st'), + (0xFB07, 'X'), + (0xFB13, 'M', u'Õ´Õ¶'), + (0xFB14, 'M', u'Õ´Õ¥'), + (0xFB15, 'M', u'Õ´Õ«'), + (0xFB16, 'M', u'Õ¾Õ¶'), + (0xFB17, 'M', u'Õ´Õ­'), + (0xFB18, 'X'), + (0xFB1D, 'M', u'×™Ö´'), + (0xFB1E, 'V'), + (0xFB1F, 'M', u'ײַ'), + (0xFB20, 'M', u'×¢'), + (0xFB21, 'M', u'×'), + (0xFB22, 'M', u'ד'), + (0xFB23, 'M', u'×”'), + (0xFB24, 'M', u'×›'), + (0xFB25, 'M', u'ל'), + (0xFB26, 'M', u'×'), + (0xFB27, 'M', u'ר'), + (0xFB28, 'M', u'ת'), + (0xFB29, '3', u'+'), + (0xFB2A, 'M', u'ש×'), + (0xFB2B, 'M', u'שׂ'), + (0xFB2C, 'M', u'שּ×'), + (0xFB2D, 'M', u'שּׂ'), + (0xFB2E, 'M', u'×Ö·'), + (0xFB2F, 'M', u'×Ö¸'), + (0xFB30, 'M', u'×Ö¼'), + (0xFB31, 'M', u'בּ'), + (0xFB32, 'M', u'×’Ö¼'), + (0xFB33, 'M', u'דּ'), + (0xFB34, 'M', u'×”Ö¼'), + (0xFB35, 'M', u'וּ'), + (0xFB36, 'M', u'×–Ö¼'), + (0xFB37, 'X'), + (0xFB38, 'M', u'טּ'), + (0xFB39, 'M', u'×™Ö¼'), + (0xFB3A, 'M', u'ךּ'), + (0xFB3B, 'M', u'×›Ö¼'), + (0xFB3C, 'M', u'לּ'), + (0xFB3D, 'X'), + (0xFB3E, 'M', u'מּ'), + (0xFB3F, 'X'), + (0xFB40, 'M', u'× Ö¼'), + (0xFB41, 'M', u'סּ'), + (0xFB42, 'X'), + (0xFB43, 'M', u'×£Ö¼'), + (0xFB44, 'M', u'פּ'), + (0xFB45, 'X'), + (0xFB46, 'M', u'צּ'), + (0xFB47, 'M', u'×§Ö¼'), + (0xFB48, 'M', u'רּ'), + (0xFB49, 'M', u'שּ'), + (0xFB4A, 'M', u'תּ'), + (0xFB4B, 'M', u'וֹ'), + (0xFB4C, 'M', u'בֿ'), + (0xFB4D, 'M', u'×›Ö¿'), + (0xFB4E, 'M', u'פֿ'), + (0xFB4F, 'M', u'×ל'), + (0xFB50, 'M', u'Ù±'), + (0xFB52, 'M', u'Ù»'), + (0xFB56, 'M', u'Ù¾'), + (0xFB5A, 'M', u'Ú€'), + (0xFB5E, 'M', u'Ùº'), + (0xFB62, 'M', u'Ù¿'), + (0xFB66, 'M', u'Ù¹'), + (0xFB6A, 'M', u'Ú¤'), + (0xFB6E, 'M', u'Ú¦'), + (0xFB72, 'M', u'Ú„'), + (0xFB76, 'M', u'Úƒ'), + (0xFB7A, 'M', u'Ú†'), + (0xFB7E, 'M', u'Ú‡'), + (0xFB82, 'M', u'Ú'), + ] + +def _seg_43(): + return [ + (0xFB84, 'M', u'ÚŒ'), + (0xFB86, 'M', u'ÚŽ'), + (0xFB88, 'M', u'Úˆ'), + (0xFB8A, 'M', u'Ú˜'), + (0xFB8C, 'M', u'Ú‘'), + (0xFB8E, 'M', u'Ú©'), + (0xFB92, 'M', u'Ú¯'), + (0xFB96, 'M', u'Ú³'), + (0xFB9A, 'M', u'Ú±'), + (0xFB9E, 'M', u'Úº'), + (0xFBA0, 'M', u'Ú»'), + (0xFBA4, 'M', u'Û€'), + (0xFBA6, 'M', u'Û'), + (0xFBAA, 'M', u'Ú¾'), + (0xFBAE, 'M', u'Û’'), + (0xFBB0, 'M', u'Û“'), + (0xFBB2, 'V'), + (0xFBC2, 'X'), + (0xFBD3, 'M', u'Ú­'), + (0xFBD7, 'M', u'Û‡'), + (0xFBD9, 'M', u'Û†'), + (0xFBDB, 'M', u'Ûˆ'), + (0xFBDD, 'M', u'Û‡Ù´'), + (0xFBDE, 'M', u'Û‹'), + (0xFBE0, 'M', u'Û…'), + (0xFBE2, 'M', u'Û‰'), + (0xFBE4, 'M', u'Û'), + (0xFBE8, 'M', u'Ù‰'), + (0xFBEA, 'M', u'ئا'), + (0xFBEC, 'M', u'ئە'), + (0xFBEE, 'M', u'ئو'), + (0xFBF0, 'M', u'ئۇ'), + (0xFBF2, 'M', u'ئۆ'), + (0xFBF4, 'M', u'ئۈ'), + (0xFBF6, 'M', u'ئÛ'), + (0xFBF9, 'M', u'ئى'), + (0xFBFC, 'M', u'ÛŒ'), + (0xFC00, 'M', u'ئج'), + (0xFC01, 'M', u'ئح'), + (0xFC02, 'M', u'ئم'), + (0xFC03, 'M', u'ئى'), + (0xFC04, 'M', u'ئي'), + (0xFC05, 'M', u'بج'), + (0xFC06, 'M', u'بح'), + (0xFC07, 'M', u'بخ'), + (0xFC08, 'M', u'بم'), + (0xFC09, 'M', u'بى'), + (0xFC0A, 'M', u'بي'), + (0xFC0B, 'M', u'تج'), + (0xFC0C, 'M', u'تح'), + (0xFC0D, 'M', u'تخ'), + (0xFC0E, 'M', u'تم'), + (0xFC0F, 'M', u'تى'), + (0xFC10, 'M', u'تي'), + (0xFC11, 'M', u'ثج'), + (0xFC12, 'M', u'ثم'), + (0xFC13, 'M', u'ثى'), + (0xFC14, 'M', u'ثي'), + (0xFC15, 'M', u'جح'), + (0xFC16, 'M', u'جم'), + (0xFC17, 'M', u'حج'), + (0xFC18, 'M', u'حم'), + (0xFC19, 'M', u'خج'), + (0xFC1A, 'M', u'خح'), + (0xFC1B, 'M', u'خم'), + (0xFC1C, 'M', u'سج'), + (0xFC1D, 'M', u'سح'), + (0xFC1E, 'M', u'سخ'), + (0xFC1F, 'M', u'سم'), + (0xFC20, 'M', u'صح'), + (0xFC21, 'M', u'صم'), + (0xFC22, 'M', u'ضج'), + (0xFC23, 'M', u'ضح'), + (0xFC24, 'M', u'ضخ'), + (0xFC25, 'M', u'ضم'), + (0xFC26, 'M', u'طح'), + (0xFC27, 'M', u'طم'), + (0xFC28, 'M', u'ظم'), + (0xFC29, 'M', u'عج'), + (0xFC2A, 'M', u'عم'), + (0xFC2B, 'M', u'غج'), + (0xFC2C, 'M', u'غم'), + (0xFC2D, 'M', u'ÙØ¬'), + (0xFC2E, 'M', u'ÙØ­'), + (0xFC2F, 'M', u'ÙØ®'), + (0xFC30, 'M', u'ÙÙ…'), + (0xFC31, 'M', u'ÙÙ‰'), + (0xFC32, 'M', u'ÙÙŠ'), + (0xFC33, 'M', u'قح'), + (0xFC34, 'M', u'قم'), + (0xFC35, 'M', u'قى'), + (0xFC36, 'M', u'قي'), + (0xFC37, 'M', u'كا'), + (0xFC38, 'M', u'كج'), + (0xFC39, 'M', u'كح'), + (0xFC3A, 'M', u'كخ'), + (0xFC3B, 'M', u'كل'), + (0xFC3C, 'M', u'كم'), + (0xFC3D, 'M', u'كى'), + (0xFC3E, 'M', u'كي'), + ] + +def _seg_44(): + return [ + (0xFC3F, 'M', u'لج'), + (0xFC40, 'M', u'لح'), + (0xFC41, 'M', u'لخ'), + (0xFC42, 'M', u'لم'), + (0xFC43, 'M', u'لى'), + (0xFC44, 'M', u'لي'), + (0xFC45, 'M', u'مج'), + (0xFC46, 'M', u'مح'), + (0xFC47, 'M', u'مخ'), + (0xFC48, 'M', u'مم'), + (0xFC49, 'M', u'مى'), + (0xFC4A, 'M', u'مي'), + (0xFC4B, 'M', u'نج'), + (0xFC4C, 'M', u'نح'), + (0xFC4D, 'M', u'نخ'), + (0xFC4E, 'M', u'نم'), + (0xFC4F, 'M', u'نى'), + (0xFC50, 'M', u'ني'), + (0xFC51, 'M', u'هج'), + (0xFC52, 'M', u'هم'), + (0xFC53, 'M', u'هى'), + (0xFC54, 'M', u'هي'), + (0xFC55, 'M', u'يج'), + (0xFC56, 'M', u'يح'), + (0xFC57, 'M', u'يخ'), + (0xFC58, 'M', u'يم'), + (0xFC59, 'M', u'يى'), + (0xFC5A, 'M', u'يي'), + (0xFC5B, 'M', u'ذٰ'), + (0xFC5C, 'M', u'رٰ'), + (0xFC5D, 'M', u'ىٰ'), + (0xFC5E, '3', u' ٌّ'), + (0xFC5F, '3', u' ÙÙ‘'), + (0xFC60, '3', u' ÙŽÙ‘'), + (0xFC61, '3', u' ÙÙ‘'), + (0xFC62, '3', u' ÙÙ‘'), + (0xFC63, '3', u' ّٰ'), + (0xFC64, 'M', u'ئر'), + (0xFC65, 'M', u'ئز'), + (0xFC66, 'M', u'ئم'), + (0xFC67, 'M', u'ئن'), + (0xFC68, 'M', u'ئى'), + (0xFC69, 'M', u'ئي'), + (0xFC6A, 'M', u'بر'), + (0xFC6B, 'M', u'بز'), + (0xFC6C, 'M', u'بم'), + (0xFC6D, 'M', u'بن'), + (0xFC6E, 'M', u'بى'), + (0xFC6F, 'M', u'بي'), + (0xFC70, 'M', u'تر'), + (0xFC71, 'M', u'تز'), + (0xFC72, 'M', u'تم'), + (0xFC73, 'M', u'تن'), + (0xFC74, 'M', u'تى'), + (0xFC75, 'M', u'تي'), + (0xFC76, 'M', u'ثر'), + (0xFC77, 'M', u'ثز'), + (0xFC78, 'M', u'ثم'), + (0xFC79, 'M', u'ثن'), + (0xFC7A, 'M', u'ثى'), + (0xFC7B, 'M', u'ثي'), + (0xFC7C, 'M', u'ÙÙ‰'), + (0xFC7D, 'M', u'ÙÙŠ'), + (0xFC7E, 'M', u'قى'), + (0xFC7F, 'M', u'قي'), + (0xFC80, 'M', u'كا'), + (0xFC81, 'M', u'كل'), + (0xFC82, 'M', u'كم'), + (0xFC83, 'M', u'كى'), + (0xFC84, 'M', u'كي'), + (0xFC85, 'M', u'لم'), + (0xFC86, 'M', u'لى'), + (0xFC87, 'M', u'لي'), + (0xFC88, 'M', u'ما'), + (0xFC89, 'M', u'مم'), + (0xFC8A, 'M', u'نر'), + (0xFC8B, 'M', u'نز'), + (0xFC8C, 'M', u'نم'), + (0xFC8D, 'M', u'نن'), + (0xFC8E, 'M', u'نى'), + (0xFC8F, 'M', u'ني'), + (0xFC90, 'M', u'ىٰ'), + (0xFC91, 'M', u'ير'), + (0xFC92, 'M', u'يز'), + (0xFC93, 'M', u'يم'), + (0xFC94, 'M', u'ين'), + (0xFC95, 'M', u'يى'), + (0xFC96, 'M', u'يي'), + (0xFC97, 'M', u'ئج'), + (0xFC98, 'M', u'ئح'), + (0xFC99, 'M', u'ئخ'), + (0xFC9A, 'M', u'ئم'), + (0xFC9B, 'M', u'ئه'), + (0xFC9C, 'M', u'بج'), + (0xFC9D, 'M', u'بح'), + (0xFC9E, 'M', u'بخ'), + (0xFC9F, 'M', u'بم'), + (0xFCA0, 'M', u'به'), + (0xFCA1, 'M', u'تج'), + (0xFCA2, 'M', u'تح'), + ] + +def _seg_45(): + return [ + (0xFCA3, 'M', u'تخ'), + (0xFCA4, 'M', u'تم'), + (0xFCA5, 'M', u'ته'), + (0xFCA6, 'M', u'ثم'), + (0xFCA7, 'M', u'جح'), + (0xFCA8, 'M', u'جم'), + (0xFCA9, 'M', u'حج'), + (0xFCAA, 'M', u'حم'), + (0xFCAB, 'M', u'خج'), + (0xFCAC, 'M', u'خم'), + (0xFCAD, 'M', u'سج'), + (0xFCAE, 'M', u'سح'), + (0xFCAF, 'M', u'سخ'), + (0xFCB0, 'M', u'سم'), + (0xFCB1, 'M', u'صح'), + (0xFCB2, 'M', u'صخ'), + (0xFCB3, 'M', u'صم'), + (0xFCB4, 'M', u'ضج'), + (0xFCB5, 'M', u'ضح'), + (0xFCB6, 'M', u'ضخ'), + (0xFCB7, 'M', u'ضم'), + (0xFCB8, 'M', u'طح'), + (0xFCB9, 'M', u'ظم'), + (0xFCBA, 'M', u'عج'), + (0xFCBB, 'M', u'عم'), + (0xFCBC, 'M', u'غج'), + (0xFCBD, 'M', u'غم'), + (0xFCBE, 'M', u'ÙØ¬'), + (0xFCBF, 'M', u'ÙØ­'), + (0xFCC0, 'M', u'ÙØ®'), + (0xFCC1, 'M', u'ÙÙ…'), + (0xFCC2, 'M', u'قح'), + (0xFCC3, 'M', u'قم'), + (0xFCC4, 'M', u'كج'), + (0xFCC5, 'M', u'كح'), + (0xFCC6, 'M', u'كخ'), + (0xFCC7, 'M', u'كل'), + (0xFCC8, 'M', u'كم'), + (0xFCC9, 'M', u'لج'), + (0xFCCA, 'M', u'لح'), + (0xFCCB, 'M', u'لخ'), + (0xFCCC, 'M', u'لم'), + (0xFCCD, 'M', u'له'), + (0xFCCE, 'M', u'مج'), + (0xFCCF, 'M', u'مح'), + (0xFCD0, 'M', u'مخ'), + (0xFCD1, 'M', u'مم'), + (0xFCD2, 'M', u'نج'), + (0xFCD3, 'M', u'نح'), + (0xFCD4, 'M', u'نخ'), + (0xFCD5, 'M', u'نم'), + (0xFCD6, 'M', u'نه'), + (0xFCD7, 'M', u'هج'), + (0xFCD8, 'M', u'هم'), + (0xFCD9, 'M', u'هٰ'), + (0xFCDA, 'M', u'يج'), + (0xFCDB, 'M', u'يح'), + (0xFCDC, 'M', u'يخ'), + (0xFCDD, 'M', u'يم'), + (0xFCDE, 'M', u'يه'), + (0xFCDF, 'M', u'ئم'), + (0xFCE0, 'M', u'ئه'), + (0xFCE1, 'M', u'بم'), + (0xFCE2, 'M', u'به'), + (0xFCE3, 'M', u'تم'), + (0xFCE4, 'M', u'ته'), + (0xFCE5, 'M', u'ثم'), + (0xFCE6, 'M', u'ثه'), + (0xFCE7, 'M', u'سم'), + (0xFCE8, 'M', u'سه'), + (0xFCE9, 'M', u'شم'), + (0xFCEA, 'M', u'شه'), + (0xFCEB, 'M', u'كل'), + (0xFCEC, 'M', u'كم'), + (0xFCED, 'M', u'لم'), + (0xFCEE, 'M', u'نم'), + (0xFCEF, 'M', u'نه'), + (0xFCF0, 'M', u'يم'), + (0xFCF1, 'M', u'يه'), + (0xFCF2, 'M', u'Ù€ÙŽÙ‘'), + (0xFCF3, 'M', u'Ù€ÙÙ‘'), + (0xFCF4, 'M', u'Ù€ÙÙ‘'), + (0xFCF5, 'M', u'طى'), + (0xFCF6, 'M', u'طي'), + (0xFCF7, 'M', u'عى'), + (0xFCF8, 'M', u'عي'), + (0xFCF9, 'M', u'غى'), + (0xFCFA, 'M', u'غي'), + (0xFCFB, 'M', u'سى'), + (0xFCFC, 'M', u'سي'), + (0xFCFD, 'M', u'شى'), + (0xFCFE, 'M', u'شي'), + (0xFCFF, 'M', u'حى'), + (0xFD00, 'M', u'حي'), + (0xFD01, 'M', u'جى'), + (0xFD02, 'M', u'جي'), + (0xFD03, 'M', u'خى'), + (0xFD04, 'M', u'خي'), + (0xFD05, 'M', u'صى'), + (0xFD06, 'M', u'صي'), + ] + +def _seg_46(): + return [ + (0xFD07, 'M', u'ضى'), + (0xFD08, 'M', u'ضي'), + (0xFD09, 'M', u'شج'), + (0xFD0A, 'M', u'شح'), + (0xFD0B, 'M', u'شخ'), + (0xFD0C, 'M', u'شم'), + (0xFD0D, 'M', u'شر'), + (0xFD0E, 'M', u'سر'), + (0xFD0F, 'M', u'صر'), + (0xFD10, 'M', u'ضر'), + (0xFD11, 'M', u'طى'), + (0xFD12, 'M', u'طي'), + (0xFD13, 'M', u'عى'), + (0xFD14, 'M', u'عي'), + (0xFD15, 'M', u'غى'), + (0xFD16, 'M', u'غي'), + (0xFD17, 'M', u'سى'), + (0xFD18, 'M', u'سي'), + (0xFD19, 'M', u'شى'), + (0xFD1A, 'M', u'شي'), + (0xFD1B, 'M', u'حى'), + (0xFD1C, 'M', u'حي'), + (0xFD1D, 'M', u'جى'), + (0xFD1E, 'M', u'جي'), + (0xFD1F, 'M', u'خى'), + (0xFD20, 'M', u'خي'), + (0xFD21, 'M', u'صى'), + (0xFD22, 'M', u'صي'), + (0xFD23, 'M', u'ضى'), + (0xFD24, 'M', u'ضي'), + (0xFD25, 'M', u'شج'), + (0xFD26, 'M', u'شح'), + (0xFD27, 'M', u'شخ'), + (0xFD28, 'M', u'شم'), + (0xFD29, 'M', u'شر'), + (0xFD2A, 'M', u'سر'), + (0xFD2B, 'M', u'صر'), + (0xFD2C, 'M', u'ضر'), + (0xFD2D, 'M', u'شج'), + (0xFD2E, 'M', u'شح'), + (0xFD2F, 'M', u'شخ'), + (0xFD30, 'M', u'شم'), + (0xFD31, 'M', u'سه'), + (0xFD32, 'M', u'شه'), + (0xFD33, 'M', u'طم'), + (0xFD34, 'M', u'سج'), + (0xFD35, 'M', u'سح'), + (0xFD36, 'M', u'سخ'), + (0xFD37, 'M', u'شج'), + (0xFD38, 'M', u'شح'), + (0xFD39, 'M', u'شخ'), + (0xFD3A, 'M', u'طم'), + (0xFD3B, 'M', u'ظم'), + (0xFD3C, 'M', u'اً'), + (0xFD3E, 'V'), + (0xFD40, 'X'), + (0xFD50, 'M', u'تجم'), + (0xFD51, 'M', u'تحج'), + (0xFD53, 'M', u'تحم'), + (0xFD54, 'M', u'تخم'), + (0xFD55, 'M', u'تمج'), + (0xFD56, 'M', u'تمح'), + (0xFD57, 'M', u'تمخ'), + (0xFD58, 'M', u'جمح'), + (0xFD5A, 'M', u'حمي'), + (0xFD5B, 'M', u'حمى'), + (0xFD5C, 'M', u'سحج'), + (0xFD5D, 'M', u'سجح'), + (0xFD5E, 'M', u'سجى'), + (0xFD5F, 'M', u'سمح'), + (0xFD61, 'M', u'سمج'), + (0xFD62, 'M', u'سمم'), + (0xFD64, 'M', u'صحح'), + (0xFD66, 'M', u'صمم'), + (0xFD67, 'M', u'شحم'), + (0xFD69, 'M', u'شجي'), + (0xFD6A, 'M', u'شمخ'), + (0xFD6C, 'M', u'شمم'), + (0xFD6E, 'M', u'ضحى'), + (0xFD6F, 'M', u'ضخم'), + (0xFD71, 'M', u'طمح'), + (0xFD73, 'M', u'طمم'), + (0xFD74, 'M', u'طمي'), + (0xFD75, 'M', u'عجم'), + (0xFD76, 'M', u'عمم'), + (0xFD78, 'M', u'عمى'), + (0xFD79, 'M', u'غمم'), + (0xFD7A, 'M', u'غمي'), + (0xFD7B, 'M', u'غمى'), + (0xFD7C, 'M', u'ÙØ®Ù…'), + (0xFD7E, 'M', u'قمح'), + (0xFD7F, 'M', u'قمم'), + (0xFD80, 'M', u'لحم'), + (0xFD81, 'M', u'لحي'), + (0xFD82, 'M', u'لحى'), + (0xFD83, 'M', u'لجج'), + (0xFD85, 'M', u'لخم'), + (0xFD87, 'M', u'لمح'), + (0xFD89, 'M', u'محج'), + (0xFD8A, 'M', u'محم'), + ] + +def _seg_47(): + return [ + (0xFD8B, 'M', u'محي'), + (0xFD8C, 'M', u'مجح'), + (0xFD8D, 'M', u'مجم'), + (0xFD8E, 'M', u'مخج'), + (0xFD8F, 'M', u'مخم'), + (0xFD90, 'X'), + (0xFD92, 'M', u'مجخ'), + (0xFD93, 'M', u'همج'), + (0xFD94, 'M', u'همم'), + (0xFD95, 'M', u'نحم'), + (0xFD96, 'M', u'نحى'), + (0xFD97, 'M', u'نجم'), + (0xFD99, 'M', u'نجى'), + (0xFD9A, 'M', u'نمي'), + (0xFD9B, 'M', u'نمى'), + (0xFD9C, 'M', u'يمم'), + (0xFD9E, 'M', u'بخي'), + (0xFD9F, 'M', u'تجي'), + (0xFDA0, 'M', u'تجى'), + (0xFDA1, 'M', u'تخي'), + (0xFDA2, 'M', u'تخى'), + (0xFDA3, 'M', u'تمي'), + (0xFDA4, 'M', u'تمى'), + (0xFDA5, 'M', u'جمي'), + (0xFDA6, 'M', u'جحى'), + (0xFDA7, 'M', u'جمى'), + (0xFDA8, 'M', u'سخى'), + (0xFDA9, 'M', u'صحي'), + (0xFDAA, 'M', u'شحي'), + (0xFDAB, 'M', u'ضحي'), + (0xFDAC, 'M', u'لجي'), + (0xFDAD, 'M', u'لمي'), + (0xFDAE, 'M', u'يحي'), + (0xFDAF, 'M', u'يجي'), + (0xFDB0, 'M', u'يمي'), + (0xFDB1, 'M', u'ممي'), + (0xFDB2, 'M', u'قمي'), + (0xFDB3, 'M', u'نحي'), + (0xFDB4, 'M', u'قمح'), + (0xFDB5, 'M', u'لحم'), + (0xFDB6, 'M', u'عمي'), + (0xFDB7, 'M', u'كمي'), + (0xFDB8, 'M', u'نجح'), + (0xFDB9, 'M', u'مخي'), + (0xFDBA, 'M', u'لجم'), + (0xFDBB, 'M', u'كمم'), + (0xFDBC, 'M', u'لجم'), + (0xFDBD, 'M', u'نجح'), + (0xFDBE, 'M', u'جحي'), + (0xFDBF, 'M', u'حجي'), + (0xFDC0, 'M', u'مجي'), + (0xFDC1, 'M', u'Ùمي'), + (0xFDC2, 'M', u'بحي'), + (0xFDC3, 'M', u'كمم'), + (0xFDC4, 'M', u'عجم'), + (0xFDC5, 'M', u'صمم'), + (0xFDC6, 'M', u'سخي'), + (0xFDC7, 'M', u'نجي'), + (0xFDC8, 'X'), + (0xFDF0, 'M', u'صلے'), + (0xFDF1, 'M', u'قلے'), + (0xFDF2, 'M', u'الله'), + (0xFDF3, 'M', u'اكبر'), + (0xFDF4, 'M', u'محمد'), + (0xFDF5, 'M', u'صلعم'), + (0xFDF6, 'M', u'رسول'), + (0xFDF7, 'M', u'عليه'), + (0xFDF8, 'M', u'وسلم'), + (0xFDF9, 'M', u'صلى'), + (0xFDFA, '3', u'صلى الله عليه وسلم'), + (0xFDFB, '3', u'جل جلاله'), + (0xFDFC, 'M', u'ریال'), + (0xFDFD, 'V'), + (0xFDFE, 'X'), + (0xFE00, 'I'), + (0xFE10, '3', u','), + (0xFE11, 'M', u'ã€'), + (0xFE12, 'X'), + (0xFE13, '3', u':'), + (0xFE14, '3', u';'), + (0xFE15, '3', u'!'), + (0xFE16, '3', u'?'), + (0xFE17, 'M', u'〖'), + (0xFE18, 'M', u'〗'), + (0xFE19, 'X'), + (0xFE20, 'V'), + (0xFE27, 'X'), + (0xFE31, 'M', u'—'), + (0xFE32, 'M', u'–'), + (0xFE33, '3', u'_'), + (0xFE35, '3', u'('), + (0xFE36, '3', u')'), + (0xFE37, '3', u'{'), + (0xFE38, '3', u'}'), + (0xFE39, 'M', u'〔'), + (0xFE3A, 'M', u'〕'), + (0xFE3B, 'M', u'ã€'), + (0xFE3C, 'M', u'】'), + (0xFE3D, 'M', u'《'), + (0xFE3E, 'M', u'》'), + ] + +def _seg_48(): + return [ + (0xFE3F, 'M', u'〈'), + (0xFE40, 'M', u'〉'), + (0xFE41, 'M', u'「'), + (0xFE42, 'M', u'ã€'), + (0xFE43, 'M', u'『'), + (0xFE44, 'M', u'ã€'), + (0xFE45, 'V'), + (0xFE47, '3', u'['), + (0xFE48, '3', u']'), + (0xFE49, '3', u' Ì…'), + (0xFE4D, '3', u'_'), + (0xFE50, '3', u','), + (0xFE51, 'M', u'ã€'), + (0xFE52, 'X'), + (0xFE54, '3', u';'), + (0xFE55, '3', u':'), + (0xFE56, '3', u'?'), + (0xFE57, '3', u'!'), + (0xFE58, 'M', u'—'), + (0xFE59, '3', u'('), + (0xFE5A, '3', u')'), + (0xFE5B, '3', u'{'), + (0xFE5C, '3', u'}'), + (0xFE5D, 'M', u'〔'), + (0xFE5E, 'M', u'〕'), + (0xFE5F, '3', u'#'), + (0xFE60, '3', u'&'), + (0xFE61, '3', u'*'), + (0xFE62, '3', u'+'), + (0xFE63, 'M', u'-'), + (0xFE64, '3', u'<'), + (0xFE65, '3', u'>'), + (0xFE66, '3', u'='), + (0xFE67, 'X'), + (0xFE68, '3', u'\\'), + (0xFE69, '3', u'$'), + (0xFE6A, '3', u'%'), + (0xFE6B, '3', u'@'), + (0xFE6C, 'X'), + (0xFE70, '3', u' Ù‹'), + (0xFE71, 'M', u'ـً'), + (0xFE72, '3', u' ÙŒ'), + (0xFE73, 'V'), + (0xFE74, '3', u' Ù'), + (0xFE75, 'X'), + (0xFE76, '3', u' ÙŽ'), + (0xFE77, 'M', u'Ù€ÙŽ'), + (0xFE78, '3', u' Ù'), + (0xFE79, 'M', u'Ù€Ù'), + (0xFE7A, '3', u' Ù'), + (0xFE7B, 'M', u'Ù€Ù'), + (0xFE7C, '3', u' Ù‘'), + (0xFE7D, 'M', u'ـّ'), + (0xFE7E, '3', u' Ù’'), + (0xFE7F, 'M', u'ـْ'), + (0xFE80, 'M', u'Ø¡'), + (0xFE81, 'M', u'Ø¢'), + (0xFE83, 'M', u'Ø£'), + (0xFE85, 'M', u'ؤ'), + (0xFE87, 'M', u'Ø¥'), + (0xFE89, 'M', u'ئ'), + (0xFE8D, 'M', u'ا'), + (0xFE8F, 'M', u'ب'), + (0xFE93, 'M', u'Ø©'), + (0xFE95, 'M', u'ت'), + (0xFE99, 'M', u'Ø«'), + (0xFE9D, 'M', u'ج'), + (0xFEA1, 'M', u'Ø­'), + (0xFEA5, 'M', u'Ø®'), + (0xFEA9, 'M', u'د'), + (0xFEAB, 'M', u'ذ'), + (0xFEAD, 'M', u'ر'), + (0xFEAF, 'M', u'ز'), + (0xFEB1, 'M', u'س'), + (0xFEB5, 'M', u'Ø´'), + (0xFEB9, 'M', u'ص'), + (0xFEBD, 'M', u'ض'), + (0xFEC1, 'M', u'Ø·'), + (0xFEC5, 'M', u'ظ'), + (0xFEC9, 'M', u'ع'), + (0xFECD, 'M', u'غ'), + (0xFED1, 'M', u'Ù'), + (0xFED5, 'M', u'Ù‚'), + (0xFED9, 'M', u'Ùƒ'), + (0xFEDD, 'M', u'Ù„'), + (0xFEE1, 'M', u'Ù…'), + (0xFEE5, 'M', u'Ù†'), + (0xFEE9, 'M', u'Ù‡'), + (0xFEED, 'M', u'Ùˆ'), + (0xFEEF, 'M', u'Ù‰'), + (0xFEF1, 'M', u'ÙŠ'), + (0xFEF5, 'M', u'لآ'), + (0xFEF7, 'M', u'لأ'), + (0xFEF9, 'M', u'لإ'), + (0xFEFB, 'M', u'لا'), + (0xFEFD, 'X'), + (0xFEFF, 'I'), + (0xFF00, 'X'), + (0xFF01, '3', u'!'), + (0xFF02, '3', u'"'), + ] + +def _seg_49(): + return [ + (0xFF03, '3', u'#'), + (0xFF04, '3', u'$'), + (0xFF05, '3', u'%'), + (0xFF06, '3', u'&'), + (0xFF07, '3', u'\''), + (0xFF08, '3', u'('), + (0xFF09, '3', u')'), + (0xFF0A, '3', u'*'), + (0xFF0B, '3', u'+'), + (0xFF0C, '3', u','), + (0xFF0D, 'M', u'-'), + (0xFF0E, 'M', u'.'), + (0xFF0F, '3', u'/'), + (0xFF10, 'M', u'0'), + (0xFF11, 'M', u'1'), + (0xFF12, 'M', u'2'), + (0xFF13, 'M', u'3'), + (0xFF14, 'M', u'4'), + (0xFF15, 'M', u'5'), + (0xFF16, 'M', u'6'), + (0xFF17, 'M', u'7'), + (0xFF18, 'M', u'8'), + (0xFF19, 'M', u'9'), + (0xFF1A, '3', u':'), + (0xFF1B, '3', u';'), + (0xFF1C, '3', u'<'), + (0xFF1D, '3', u'='), + (0xFF1E, '3', u'>'), + (0xFF1F, '3', u'?'), + (0xFF20, '3', u'@'), + (0xFF21, 'M', u'a'), + (0xFF22, 'M', u'b'), + (0xFF23, 'M', u'c'), + (0xFF24, 'M', u'd'), + (0xFF25, 'M', u'e'), + (0xFF26, 'M', u'f'), + (0xFF27, 'M', u'g'), + (0xFF28, 'M', u'h'), + (0xFF29, 'M', u'i'), + (0xFF2A, 'M', u'j'), + (0xFF2B, 'M', u'k'), + (0xFF2C, 'M', u'l'), + (0xFF2D, 'M', u'm'), + (0xFF2E, 'M', u'n'), + (0xFF2F, 'M', u'o'), + (0xFF30, 'M', u'p'), + (0xFF31, 'M', u'q'), + (0xFF32, 'M', u'r'), + (0xFF33, 'M', u's'), + (0xFF34, 'M', u't'), + (0xFF35, 'M', u'u'), + (0xFF36, 'M', u'v'), + (0xFF37, 'M', u'w'), + (0xFF38, 'M', u'x'), + (0xFF39, 'M', u'y'), + (0xFF3A, 'M', u'z'), + (0xFF3B, '3', u'['), + (0xFF3C, '3', u'\\'), + (0xFF3D, '3', u']'), + (0xFF3E, '3', u'^'), + (0xFF3F, '3', u'_'), + (0xFF40, '3', u'`'), + (0xFF41, 'M', u'a'), + (0xFF42, 'M', u'b'), + (0xFF43, 'M', u'c'), + (0xFF44, 'M', u'd'), + (0xFF45, 'M', u'e'), + (0xFF46, 'M', u'f'), + (0xFF47, 'M', u'g'), + (0xFF48, 'M', u'h'), + (0xFF49, 'M', u'i'), + (0xFF4A, 'M', u'j'), + (0xFF4B, 'M', u'k'), + (0xFF4C, 'M', u'l'), + (0xFF4D, 'M', u'm'), + (0xFF4E, 'M', u'n'), + (0xFF4F, 'M', u'o'), + (0xFF50, 'M', u'p'), + (0xFF51, 'M', u'q'), + (0xFF52, 'M', u'r'), + (0xFF53, 'M', u's'), + (0xFF54, 'M', u't'), + (0xFF55, 'M', u'u'), + (0xFF56, 'M', u'v'), + (0xFF57, 'M', u'w'), + (0xFF58, 'M', u'x'), + (0xFF59, 'M', u'y'), + (0xFF5A, 'M', u'z'), + (0xFF5B, '3', u'{'), + (0xFF5C, '3', u'|'), + (0xFF5D, '3', u'}'), + (0xFF5E, '3', u'~'), + (0xFF5F, 'M', u'⦅'), + (0xFF60, 'M', u'⦆'), + (0xFF61, 'M', u'.'), + (0xFF62, 'M', u'「'), + (0xFF63, 'M', u'ã€'), + (0xFF64, 'M', u'ã€'), + (0xFF65, 'M', u'・'), + (0xFF66, 'M', u'ヲ'), + ] + +def _seg_50(): + return [ + (0xFF67, 'M', u'ã‚¡'), + (0xFF68, 'M', u'ã‚£'), + (0xFF69, 'M', u'ã‚¥'), + (0xFF6A, 'M', u'ã‚§'), + (0xFF6B, 'M', u'ã‚©'), + (0xFF6C, 'M', u'ャ'), + (0xFF6D, 'M', u'ュ'), + (0xFF6E, 'M', u'ョ'), + (0xFF6F, 'M', u'ッ'), + (0xFF70, 'M', u'ー'), + (0xFF71, 'M', u'ã‚¢'), + (0xFF72, 'M', u'イ'), + (0xFF73, 'M', u'ウ'), + (0xFF74, 'M', u'エ'), + (0xFF75, 'M', u'オ'), + (0xFF76, 'M', u'ã‚«'), + (0xFF77, 'M', u'ã‚­'), + (0xFF78, 'M', u'ク'), + (0xFF79, 'M', u'ケ'), + (0xFF7A, 'M', u'コ'), + (0xFF7B, 'M', u'サ'), + (0xFF7C, 'M', u'ã‚·'), + (0xFF7D, 'M', u'ス'), + (0xFF7E, 'M', u'ã‚»'), + (0xFF7F, 'M', u'ソ'), + (0xFF80, 'M', u'ã‚¿'), + (0xFF81, 'M', u'ãƒ'), + (0xFF82, 'M', u'ツ'), + (0xFF83, 'M', u'テ'), + (0xFF84, 'M', u'ト'), + (0xFF85, 'M', u'ナ'), + (0xFF86, 'M', u'ニ'), + (0xFF87, 'M', u'ヌ'), + (0xFF88, 'M', u'ãƒ'), + (0xFF89, 'M', u'ノ'), + (0xFF8A, 'M', u'ãƒ'), + (0xFF8B, 'M', u'ヒ'), + (0xFF8C, 'M', u'フ'), + (0xFF8D, 'M', u'ヘ'), + (0xFF8E, 'M', u'ホ'), + (0xFF8F, 'M', u'マ'), + (0xFF90, 'M', u'ミ'), + (0xFF91, 'M', u'ム'), + (0xFF92, 'M', u'メ'), + (0xFF93, 'M', u'モ'), + (0xFF94, 'M', u'ヤ'), + (0xFF95, 'M', u'ユ'), + (0xFF96, 'M', u'ヨ'), + (0xFF97, 'M', u'ラ'), + (0xFF98, 'M', u'リ'), + (0xFF99, 'M', u'ル'), + (0xFF9A, 'M', u'レ'), + (0xFF9B, 'M', u'ロ'), + (0xFF9C, 'M', u'ワ'), + (0xFF9D, 'M', u'ン'), + (0xFF9E, 'M', u'ã‚™'), + (0xFF9F, 'M', u'゚'), + (0xFFA0, 'X'), + (0xFFA1, 'M', u'á„€'), + (0xFFA2, 'M', u'á„'), + (0xFFA3, 'M', u'ᆪ'), + (0xFFA4, 'M', u'á„‚'), + (0xFFA5, 'M', u'ᆬ'), + (0xFFA6, 'M', u'ᆭ'), + (0xFFA7, 'M', u'ᄃ'), + (0xFFA8, 'M', u'á„„'), + (0xFFA9, 'M', u'á„…'), + (0xFFAA, 'M', u'ᆰ'), + (0xFFAB, 'M', u'ᆱ'), + (0xFFAC, 'M', u'ᆲ'), + (0xFFAD, 'M', u'ᆳ'), + (0xFFAE, 'M', u'ᆴ'), + (0xFFAF, 'M', u'ᆵ'), + (0xFFB0, 'M', u'ᄚ'), + (0xFFB1, 'M', u'ᄆ'), + (0xFFB2, 'M', u'ᄇ'), + (0xFFB3, 'M', u'ᄈ'), + (0xFFB4, 'M', u'á„¡'), + (0xFFB5, 'M', u'ᄉ'), + (0xFFB6, 'M', u'ᄊ'), + (0xFFB7, 'M', u'á„‹'), + (0xFFB8, 'M', u'ᄌ'), + (0xFFB9, 'M', u'á„'), + (0xFFBA, 'M', u'ᄎ'), + (0xFFBB, 'M', u'á„'), + (0xFFBC, 'M', u'á„'), + (0xFFBD, 'M', u'á„‘'), + (0xFFBE, 'M', u'á„’'), + (0xFFBF, 'X'), + (0xFFC2, 'M', u'á…¡'), + (0xFFC3, 'M', u'á…¢'), + (0xFFC4, 'M', u'á…£'), + (0xFFC5, 'M', u'á…¤'), + (0xFFC6, 'M', u'á…¥'), + (0xFFC7, 'M', u'á…¦'), + (0xFFC8, 'X'), + (0xFFCA, 'M', u'á…§'), + (0xFFCB, 'M', u'á…¨'), + (0xFFCC, 'M', u'á…©'), + (0xFFCD, 'M', u'á…ª'), + ] + +def _seg_51(): + return [ + (0xFFCE, 'M', u'á…«'), + (0xFFCF, 'M', u'á…¬'), + (0xFFD0, 'X'), + (0xFFD2, 'M', u'á…­'), + (0xFFD3, 'M', u'á…®'), + (0xFFD4, 'M', u'á…¯'), + (0xFFD5, 'M', u'á…°'), + (0xFFD6, 'M', u'á…±'), + (0xFFD7, 'M', u'á…²'), + (0xFFD8, 'X'), + (0xFFDA, 'M', u'á…³'), + (0xFFDB, 'M', u'á…´'), + (0xFFDC, 'M', u'á…µ'), + (0xFFDD, 'X'), + (0xFFE0, 'M', u'¢'), + (0xFFE1, 'M', u'£'), + (0xFFE2, 'M', u'¬'), + (0xFFE3, '3', u' Ì„'), + (0xFFE4, 'M', u'¦'), + (0xFFE5, 'M', u'Â¥'), + (0xFFE6, 'M', u'â‚©'), + (0xFFE7, 'X'), + (0xFFE8, 'M', u'│'), + (0xFFE9, 'M', u'â†'), + (0xFFEA, 'M', u'↑'), + (0xFFEB, 'M', u'→'), + (0xFFEC, 'M', u'↓'), + (0xFFED, 'M', u'â– '), + (0xFFEE, 'M', u'â—‹'), + (0xFFEF, 'X'), + (0x10000, 'V'), + (0x1000C, 'X'), + (0x1000D, 'V'), + (0x10027, 'X'), + (0x10028, 'V'), + (0x1003B, 'X'), + (0x1003C, 'V'), + (0x1003E, 'X'), + (0x1003F, 'V'), + (0x1004E, 'X'), + (0x10050, 'V'), + (0x1005E, 'X'), + (0x10080, 'V'), + (0x100FB, 'X'), + (0x10100, 'V'), + (0x10103, 'X'), + (0x10107, 'V'), + (0x10134, 'X'), + (0x10137, 'V'), + (0x1018B, 'X'), + (0x10190, 'V'), + (0x1019C, 'X'), + (0x101D0, 'V'), + (0x101FE, 'X'), + (0x10280, 'V'), + (0x1029D, 'X'), + (0x102A0, 'V'), + (0x102D1, 'X'), + (0x10300, 'V'), + (0x1031F, 'X'), + (0x10320, 'V'), + (0x10324, 'X'), + (0x10330, 'V'), + (0x1034B, 'X'), + (0x10380, 'V'), + (0x1039E, 'X'), + (0x1039F, 'V'), + (0x103C4, 'X'), + (0x103C8, 'V'), + (0x103D6, 'X'), + (0x10400, 'M', u'ð¨'), + (0x10401, 'M', u'ð©'), + (0x10402, 'M', u'ðª'), + (0x10403, 'M', u'ð«'), + (0x10404, 'M', u'ð¬'), + (0x10405, 'M', u'ð­'), + (0x10406, 'M', u'ð®'), + (0x10407, 'M', u'ð¯'), + (0x10408, 'M', u'ð°'), + (0x10409, 'M', u'ð±'), + (0x1040A, 'M', u'ð²'), + (0x1040B, 'M', u'ð³'), + (0x1040C, 'M', u'ð´'), + (0x1040D, 'M', u'ðµ'), + (0x1040E, 'M', u'ð¶'), + (0x1040F, 'M', u'ð·'), + (0x10410, 'M', u'ð¸'), + (0x10411, 'M', u'ð¹'), + (0x10412, 'M', u'ðº'), + (0x10413, 'M', u'ð»'), + (0x10414, 'M', u'ð¼'), + (0x10415, 'M', u'ð½'), + (0x10416, 'M', u'ð¾'), + (0x10417, 'M', u'ð¿'), + (0x10418, 'M', u'ð‘€'), + (0x10419, 'M', u'ð‘'), + (0x1041A, 'M', u'ð‘‚'), + (0x1041B, 'M', u'ð‘ƒ'), + (0x1041C, 'M', u'ð‘„'), + (0x1041D, 'M', u'ð‘…'), + ] + +def _seg_52(): + return [ + (0x1041E, 'M', u'ð‘†'), + (0x1041F, 'M', u'ð‘‡'), + (0x10420, 'M', u'ð‘ˆ'), + (0x10421, 'M', u'ð‘‰'), + (0x10422, 'M', u'ð‘Š'), + (0x10423, 'M', u'ð‘‹'), + (0x10424, 'M', u'ð‘Œ'), + (0x10425, 'M', u'ð‘'), + (0x10426, 'M', u'ð‘Ž'), + (0x10427, 'M', u'ð‘'), + (0x10428, 'V'), + (0x1049E, 'X'), + (0x104A0, 'V'), + (0x104AA, 'X'), + (0x10800, 'V'), + (0x10806, 'X'), + (0x10808, 'V'), + (0x10809, 'X'), + (0x1080A, 'V'), + (0x10836, 'X'), + (0x10837, 'V'), + (0x10839, 'X'), + (0x1083C, 'V'), + (0x1083D, 'X'), + (0x1083F, 'V'), + (0x10856, 'X'), + (0x10857, 'V'), + (0x10860, 'X'), + (0x10900, 'V'), + (0x1091C, 'X'), + (0x1091F, 'V'), + (0x1093A, 'X'), + (0x1093F, 'V'), + (0x10940, 'X'), + (0x10980, 'V'), + (0x109B8, 'X'), + (0x109BE, 'V'), + (0x109C0, 'X'), + (0x10A00, 'V'), + (0x10A04, 'X'), + (0x10A05, 'V'), + (0x10A07, 'X'), + (0x10A0C, 'V'), + (0x10A14, 'X'), + (0x10A15, 'V'), + (0x10A18, 'X'), + (0x10A19, 'V'), + (0x10A34, 'X'), + (0x10A38, 'V'), + (0x10A3B, 'X'), + (0x10A3F, 'V'), + (0x10A48, 'X'), + (0x10A50, 'V'), + (0x10A59, 'X'), + (0x10A60, 'V'), + (0x10A80, 'X'), + (0x10B00, 'V'), + (0x10B36, 'X'), + (0x10B39, 'V'), + (0x10B56, 'X'), + (0x10B58, 'V'), + (0x10B73, 'X'), + (0x10B78, 'V'), + (0x10B80, 'X'), + (0x10C00, 'V'), + (0x10C49, 'X'), + (0x10E60, 'V'), + (0x10E7F, 'X'), + (0x11000, 'V'), + (0x1104E, 'X'), + (0x11052, 'V'), + (0x11070, 'X'), + (0x11080, 'V'), + (0x110BD, 'X'), + (0x110BE, 'V'), + (0x110C2, 'X'), + (0x110D0, 'V'), + (0x110E9, 'X'), + (0x110F0, 'V'), + (0x110FA, 'X'), + (0x11100, 'V'), + (0x11135, 'X'), + (0x11136, 'V'), + (0x11144, 'X'), + (0x11180, 'V'), + (0x111C9, 'X'), + (0x111D0, 'V'), + (0x111DA, 'X'), + (0x11680, 'V'), + (0x116B8, 'X'), + (0x116C0, 'V'), + (0x116CA, 'X'), + (0x12000, 'V'), + (0x1236F, 'X'), + (0x12400, 'V'), + (0x12463, 'X'), + (0x12470, 'V'), + (0x12474, 'X'), + (0x13000, 'V'), + (0x1342F, 'X'), + ] + +def _seg_53(): + return [ + (0x16800, 'V'), + (0x16A39, 'X'), + (0x16F00, 'V'), + (0x16F45, 'X'), + (0x16F50, 'V'), + (0x16F7F, 'X'), + (0x16F8F, 'V'), + (0x16FA0, 'X'), + (0x1B000, 'V'), + (0x1B002, 'X'), + (0x1D000, 'V'), + (0x1D0F6, 'X'), + (0x1D100, 'V'), + (0x1D127, 'X'), + (0x1D129, 'V'), + (0x1D15E, 'M', u'ð…—ð…¥'), + (0x1D15F, 'M', u'ð…˜ð…¥'), + (0x1D160, 'M', u'ð…˜ð…¥ð…®'), + (0x1D161, 'M', u'ð…˜ð…¥ð…¯'), + (0x1D162, 'M', u'ð…˜ð…¥ð…°'), + (0x1D163, 'M', u'ð…˜ð…¥ð…±'), + (0x1D164, 'M', u'ð…˜ð…¥ð…²'), + (0x1D165, 'V'), + (0x1D173, 'X'), + (0x1D17B, 'V'), + (0x1D1BB, 'M', u'ð†¹ð…¥'), + (0x1D1BC, 'M', u'ð†ºð…¥'), + (0x1D1BD, 'M', u'ð†¹ð…¥ð…®'), + (0x1D1BE, 'M', u'ð†ºð…¥ð…®'), + (0x1D1BF, 'M', u'ð†¹ð…¥ð…¯'), + (0x1D1C0, 'M', u'ð†ºð…¥ð…¯'), + (0x1D1C1, 'V'), + (0x1D1DE, 'X'), + (0x1D200, 'V'), + (0x1D246, 'X'), + (0x1D300, 'V'), + (0x1D357, 'X'), + (0x1D360, 'V'), + (0x1D372, 'X'), + (0x1D400, 'M', u'a'), + (0x1D401, 'M', u'b'), + (0x1D402, 'M', u'c'), + (0x1D403, 'M', u'd'), + (0x1D404, 'M', u'e'), + (0x1D405, 'M', u'f'), + (0x1D406, 'M', u'g'), + (0x1D407, 'M', u'h'), + (0x1D408, 'M', u'i'), + (0x1D409, 'M', u'j'), + (0x1D40A, 'M', u'k'), + (0x1D40B, 'M', u'l'), + (0x1D40C, 'M', u'm'), + (0x1D40D, 'M', u'n'), + (0x1D40E, 'M', u'o'), + (0x1D40F, 'M', u'p'), + (0x1D410, 'M', u'q'), + (0x1D411, 'M', u'r'), + (0x1D412, 'M', u's'), + (0x1D413, 'M', u't'), + (0x1D414, 'M', u'u'), + (0x1D415, 'M', u'v'), + (0x1D416, 'M', u'w'), + (0x1D417, 'M', u'x'), + (0x1D418, 'M', u'y'), + (0x1D419, 'M', u'z'), + (0x1D41A, 'M', u'a'), + (0x1D41B, 'M', u'b'), + (0x1D41C, 'M', u'c'), + (0x1D41D, 'M', u'd'), + (0x1D41E, 'M', u'e'), + (0x1D41F, 'M', u'f'), + (0x1D420, 'M', u'g'), + (0x1D421, 'M', u'h'), + (0x1D422, 'M', u'i'), + (0x1D423, 'M', u'j'), + (0x1D424, 'M', u'k'), + (0x1D425, 'M', u'l'), + (0x1D426, 'M', u'm'), + (0x1D427, 'M', u'n'), + (0x1D428, 'M', u'o'), + (0x1D429, 'M', u'p'), + (0x1D42A, 'M', u'q'), + (0x1D42B, 'M', u'r'), + (0x1D42C, 'M', u's'), + (0x1D42D, 'M', u't'), + (0x1D42E, 'M', u'u'), + (0x1D42F, 'M', u'v'), + (0x1D430, 'M', u'w'), + (0x1D431, 'M', u'x'), + (0x1D432, 'M', u'y'), + (0x1D433, 'M', u'z'), + (0x1D434, 'M', u'a'), + (0x1D435, 'M', u'b'), + (0x1D436, 'M', u'c'), + (0x1D437, 'M', u'd'), + (0x1D438, 'M', u'e'), + (0x1D439, 'M', u'f'), + (0x1D43A, 'M', u'g'), + (0x1D43B, 'M', u'h'), + (0x1D43C, 'M', u'i'), + ] + +def _seg_54(): + return [ + (0x1D43D, 'M', u'j'), + (0x1D43E, 'M', u'k'), + (0x1D43F, 'M', u'l'), + (0x1D440, 'M', u'm'), + (0x1D441, 'M', u'n'), + (0x1D442, 'M', u'o'), + (0x1D443, 'M', u'p'), + (0x1D444, 'M', u'q'), + (0x1D445, 'M', u'r'), + (0x1D446, 'M', u's'), + (0x1D447, 'M', u't'), + (0x1D448, 'M', u'u'), + (0x1D449, 'M', u'v'), + (0x1D44A, 'M', u'w'), + (0x1D44B, 'M', u'x'), + (0x1D44C, 'M', u'y'), + (0x1D44D, 'M', u'z'), + (0x1D44E, 'M', u'a'), + (0x1D44F, 'M', u'b'), + (0x1D450, 'M', u'c'), + (0x1D451, 'M', u'd'), + (0x1D452, 'M', u'e'), + (0x1D453, 'M', u'f'), + (0x1D454, 'M', u'g'), + (0x1D455, 'X'), + (0x1D456, 'M', u'i'), + (0x1D457, 'M', u'j'), + (0x1D458, 'M', u'k'), + (0x1D459, 'M', u'l'), + (0x1D45A, 'M', u'm'), + (0x1D45B, 'M', u'n'), + (0x1D45C, 'M', u'o'), + (0x1D45D, 'M', u'p'), + (0x1D45E, 'M', u'q'), + (0x1D45F, 'M', u'r'), + (0x1D460, 'M', u's'), + (0x1D461, 'M', u't'), + (0x1D462, 'M', u'u'), + (0x1D463, 'M', u'v'), + (0x1D464, 'M', u'w'), + (0x1D465, 'M', u'x'), + (0x1D466, 'M', u'y'), + (0x1D467, 'M', u'z'), + (0x1D468, 'M', u'a'), + (0x1D469, 'M', u'b'), + (0x1D46A, 'M', u'c'), + (0x1D46B, 'M', u'd'), + (0x1D46C, 'M', u'e'), + (0x1D46D, 'M', u'f'), + (0x1D46E, 'M', u'g'), + (0x1D46F, 'M', u'h'), + (0x1D470, 'M', u'i'), + (0x1D471, 'M', u'j'), + (0x1D472, 'M', u'k'), + (0x1D473, 'M', u'l'), + (0x1D474, 'M', u'm'), + (0x1D475, 'M', u'n'), + (0x1D476, 'M', u'o'), + (0x1D477, 'M', u'p'), + (0x1D478, 'M', u'q'), + (0x1D479, 'M', u'r'), + (0x1D47A, 'M', u's'), + (0x1D47B, 'M', u't'), + (0x1D47C, 'M', u'u'), + (0x1D47D, 'M', u'v'), + (0x1D47E, 'M', u'w'), + (0x1D47F, 'M', u'x'), + (0x1D480, 'M', u'y'), + (0x1D481, 'M', u'z'), + (0x1D482, 'M', u'a'), + (0x1D483, 'M', u'b'), + (0x1D484, 'M', u'c'), + (0x1D485, 'M', u'd'), + (0x1D486, 'M', u'e'), + (0x1D487, 'M', u'f'), + (0x1D488, 'M', u'g'), + (0x1D489, 'M', u'h'), + (0x1D48A, 'M', u'i'), + (0x1D48B, 'M', u'j'), + (0x1D48C, 'M', u'k'), + (0x1D48D, 'M', u'l'), + (0x1D48E, 'M', u'm'), + (0x1D48F, 'M', u'n'), + (0x1D490, 'M', u'o'), + (0x1D491, 'M', u'p'), + (0x1D492, 'M', u'q'), + (0x1D493, 'M', u'r'), + (0x1D494, 'M', u's'), + (0x1D495, 'M', u't'), + (0x1D496, 'M', u'u'), + (0x1D497, 'M', u'v'), + (0x1D498, 'M', u'w'), + (0x1D499, 'M', u'x'), + (0x1D49A, 'M', u'y'), + (0x1D49B, 'M', u'z'), + (0x1D49C, 'M', u'a'), + (0x1D49D, 'X'), + (0x1D49E, 'M', u'c'), + (0x1D49F, 'M', u'd'), + (0x1D4A0, 'X'), + ] + +def _seg_55(): + return [ + (0x1D4A2, 'M', u'g'), + (0x1D4A3, 'X'), + (0x1D4A5, 'M', u'j'), + (0x1D4A6, 'M', u'k'), + (0x1D4A7, 'X'), + (0x1D4A9, 'M', u'n'), + (0x1D4AA, 'M', u'o'), + (0x1D4AB, 'M', u'p'), + (0x1D4AC, 'M', u'q'), + (0x1D4AD, 'X'), + (0x1D4AE, 'M', u's'), + (0x1D4AF, 'M', u't'), + (0x1D4B0, 'M', u'u'), + (0x1D4B1, 'M', u'v'), + (0x1D4B2, 'M', u'w'), + (0x1D4B3, 'M', u'x'), + (0x1D4B4, 'M', u'y'), + (0x1D4B5, 'M', u'z'), + (0x1D4B6, 'M', u'a'), + (0x1D4B7, 'M', u'b'), + (0x1D4B8, 'M', u'c'), + (0x1D4B9, 'M', u'd'), + (0x1D4BA, 'X'), + (0x1D4BB, 'M', u'f'), + (0x1D4BC, 'X'), + (0x1D4BD, 'M', u'h'), + (0x1D4BE, 'M', u'i'), + (0x1D4BF, 'M', u'j'), + (0x1D4C0, 'M', u'k'), + (0x1D4C1, 'M', u'l'), + (0x1D4C2, 'M', u'm'), + (0x1D4C3, 'M', u'n'), + (0x1D4C4, 'X'), + (0x1D4C5, 'M', u'p'), + (0x1D4C6, 'M', u'q'), + (0x1D4C7, 'M', u'r'), + (0x1D4C8, 'M', u's'), + (0x1D4C9, 'M', u't'), + (0x1D4CA, 'M', u'u'), + (0x1D4CB, 'M', u'v'), + (0x1D4CC, 'M', u'w'), + (0x1D4CD, 'M', u'x'), + (0x1D4CE, 'M', u'y'), + (0x1D4CF, 'M', u'z'), + (0x1D4D0, 'M', u'a'), + (0x1D4D1, 'M', u'b'), + (0x1D4D2, 'M', u'c'), + (0x1D4D3, 'M', u'd'), + (0x1D4D4, 'M', u'e'), + (0x1D4D5, 'M', u'f'), + (0x1D4D6, 'M', u'g'), + (0x1D4D7, 'M', u'h'), + (0x1D4D8, 'M', u'i'), + (0x1D4D9, 'M', u'j'), + (0x1D4DA, 'M', u'k'), + (0x1D4DB, 'M', u'l'), + (0x1D4DC, 'M', u'm'), + (0x1D4DD, 'M', u'n'), + (0x1D4DE, 'M', u'o'), + (0x1D4DF, 'M', u'p'), + (0x1D4E0, 'M', u'q'), + (0x1D4E1, 'M', u'r'), + (0x1D4E2, 'M', u's'), + (0x1D4E3, 'M', u't'), + (0x1D4E4, 'M', u'u'), + (0x1D4E5, 'M', u'v'), + (0x1D4E6, 'M', u'w'), + (0x1D4E7, 'M', u'x'), + (0x1D4E8, 'M', u'y'), + (0x1D4E9, 'M', u'z'), + (0x1D4EA, 'M', u'a'), + (0x1D4EB, 'M', u'b'), + (0x1D4EC, 'M', u'c'), + (0x1D4ED, 'M', u'd'), + (0x1D4EE, 'M', u'e'), + (0x1D4EF, 'M', u'f'), + (0x1D4F0, 'M', u'g'), + (0x1D4F1, 'M', u'h'), + (0x1D4F2, 'M', u'i'), + (0x1D4F3, 'M', u'j'), + (0x1D4F4, 'M', u'k'), + (0x1D4F5, 'M', u'l'), + (0x1D4F6, 'M', u'm'), + (0x1D4F7, 'M', u'n'), + (0x1D4F8, 'M', u'o'), + (0x1D4F9, 'M', u'p'), + (0x1D4FA, 'M', u'q'), + (0x1D4FB, 'M', u'r'), + (0x1D4FC, 'M', u's'), + (0x1D4FD, 'M', u't'), + (0x1D4FE, 'M', u'u'), + (0x1D4FF, 'M', u'v'), + (0x1D500, 'M', u'w'), + (0x1D501, 'M', u'x'), + (0x1D502, 'M', u'y'), + (0x1D503, 'M', u'z'), + (0x1D504, 'M', u'a'), + (0x1D505, 'M', u'b'), + (0x1D506, 'X'), + (0x1D507, 'M', u'd'), + ] + +def _seg_56(): + return [ + (0x1D508, 'M', u'e'), + (0x1D509, 'M', u'f'), + (0x1D50A, 'M', u'g'), + (0x1D50B, 'X'), + (0x1D50D, 'M', u'j'), + (0x1D50E, 'M', u'k'), + (0x1D50F, 'M', u'l'), + (0x1D510, 'M', u'm'), + (0x1D511, 'M', u'n'), + (0x1D512, 'M', u'o'), + (0x1D513, 'M', u'p'), + (0x1D514, 'M', u'q'), + (0x1D515, 'X'), + (0x1D516, 'M', u's'), + (0x1D517, 'M', u't'), + (0x1D518, 'M', u'u'), + (0x1D519, 'M', u'v'), + (0x1D51A, 'M', u'w'), + (0x1D51B, 'M', u'x'), + (0x1D51C, 'M', u'y'), + (0x1D51D, 'X'), + (0x1D51E, 'M', u'a'), + (0x1D51F, 'M', u'b'), + (0x1D520, 'M', u'c'), + (0x1D521, 'M', u'd'), + (0x1D522, 'M', u'e'), + (0x1D523, 'M', u'f'), + (0x1D524, 'M', u'g'), + (0x1D525, 'M', u'h'), + (0x1D526, 'M', u'i'), + (0x1D527, 'M', u'j'), + (0x1D528, 'M', u'k'), + (0x1D529, 'M', u'l'), + (0x1D52A, 'M', u'm'), + (0x1D52B, 'M', u'n'), + (0x1D52C, 'M', u'o'), + (0x1D52D, 'M', u'p'), + (0x1D52E, 'M', u'q'), + (0x1D52F, 'M', u'r'), + (0x1D530, 'M', u's'), + (0x1D531, 'M', u't'), + (0x1D532, 'M', u'u'), + (0x1D533, 'M', u'v'), + (0x1D534, 'M', u'w'), + (0x1D535, 'M', u'x'), + (0x1D536, 'M', u'y'), + (0x1D537, 'M', u'z'), + (0x1D538, 'M', u'a'), + (0x1D539, 'M', u'b'), + (0x1D53A, 'X'), + (0x1D53B, 'M', u'd'), + (0x1D53C, 'M', u'e'), + (0x1D53D, 'M', u'f'), + (0x1D53E, 'M', u'g'), + (0x1D53F, 'X'), + (0x1D540, 'M', u'i'), + (0x1D541, 'M', u'j'), + (0x1D542, 'M', u'k'), + (0x1D543, 'M', u'l'), + (0x1D544, 'M', u'm'), + (0x1D545, 'X'), + (0x1D546, 'M', u'o'), + (0x1D547, 'X'), + (0x1D54A, 'M', u's'), + (0x1D54B, 'M', u't'), + (0x1D54C, 'M', u'u'), + (0x1D54D, 'M', u'v'), + (0x1D54E, 'M', u'w'), + (0x1D54F, 'M', u'x'), + (0x1D550, 'M', u'y'), + (0x1D551, 'X'), + (0x1D552, 'M', u'a'), + (0x1D553, 'M', u'b'), + (0x1D554, 'M', u'c'), + (0x1D555, 'M', u'd'), + (0x1D556, 'M', u'e'), + (0x1D557, 'M', u'f'), + (0x1D558, 'M', u'g'), + (0x1D559, 'M', u'h'), + (0x1D55A, 'M', u'i'), + (0x1D55B, 'M', u'j'), + (0x1D55C, 'M', u'k'), + (0x1D55D, 'M', u'l'), + (0x1D55E, 'M', u'm'), + (0x1D55F, 'M', u'n'), + (0x1D560, 'M', u'o'), + (0x1D561, 'M', u'p'), + (0x1D562, 'M', u'q'), + (0x1D563, 'M', u'r'), + (0x1D564, 'M', u's'), + (0x1D565, 'M', u't'), + (0x1D566, 'M', u'u'), + (0x1D567, 'M', u'v'), + (0x1D568, 'M', u'w'), + (0x1D569, 'M', u'x'), + (0x1D56A, 'M', u'y'), + (0x1D56B, 'M', u'z'), + (0x1D56C, 'M', u'a'), + (0x1D56D, 'M', u'b'), + (0x1D56E, 'M', u'c'), + ] + +def _seg_57(): + return [ + (0x1D56F, 'M', u'd'), + (0x1D570, 'M', u'e'), + (0x1D571, 'M', u'f'), + (0x1D572, 'M', u'g'), + (0x1D573, 'M', u'h'), + (0x1D574, 'M', u'i'), + (0x1D575, 'M', u'j'), + (0x1D576, 'M', u'k'), + (0x1D577, 'M', u'l'), + (0x1D578, 'M', u'm'), + (0x1D579, 'M', u'n'), + (0x1D57A, 'M', u'o'), + (0x1D57B, 'M', u'p'), + (0x1D57C, 'M', u'q'), + (0x1D57D, 'M', u'r'), + (0x1D57E, 'M', u's'), + (0x1D57F, 'M', u't'), + (0x1D580, 'M', u'u'), + (0x1D581, 'M', u'v'), + (0x1D582, 'M', u'w'), + (0x1D583, 'M', u'x'), + (0x1D584, 'M', u'y'), + (0x1D585, 'M', u'z'), + (0x1D586, 'M', u'a'), + (0x1D587, 'M', u'b'), + (0x1D588, 'M', u'c'), + (0x1D589, 'M', u'd'), + (0x1D58A, 'M', u'e'), + (0x1D58B, 'M', u'f'), + (0x1D58C, 'M', u'g'), + (0x1D58D, 'M', u'h'), + (0x1D58E, 'M', u'i'), + (0x1D58F, 'M', u'j'), + (0x1D590, 'M', u'k'), + (0x1D591, 'M', u'l'), + (0x1D592, 'M', u'm'), + (0x1D593, 'M', u'n'), + (0x1D594, 'M', u'o'), + (0x1D595, 'M', u'p'), + (0x1D596, 'M', u'q'), + (0x1D597, 'M', u'r'), + (0x1D598, 'M', u's'), + (0x1D599, 'M', u't'), + (0x1D59A, 'M', u'u'), + (0x1D59B, 'M', u'v'), + (0x1D59C, 'M', u'w'), + (0x1D59D, 'M', u'x'), + (0x1D59E, 'M', u'y'), + (0x1D59F, 'M', u'z'), + (0x1D5A0, 'M', u'a'), + (0x1D5A1, 'M', u'b'), + (0x1D5A2, 'M', u'c'), + (0x1D5A3, 'M', u'd'), + (0x1D5A4, 'M', u'e'), + (0x1D5A5, 'M', u'f'), + (0x1D5A6, 'M', u'g'), + (0x1D5A7, 'M', u'h'), + (0x1D5A8, 'M', u'i'), + (0x1D5A9, 'M', u'j'), + (0x1D5AA, 'M', u'k'), + (0x1D5AB, 'M', u'l'), + (0x1D5AC, 'M', u'm'), + (0x1D5AD, 'M', u'n'), + (0x1D5AE, 'M', u'o'), + (0x1D5AF, 'M', u'p'), + (0x1D5B0, 'M', u'q'), + (0x1D5B1, 'M', u'r'), + (0x1D5B2, 'M', u's'), + (0x1D5B3, 'M', u't'), + (0x1D5B4, 'M', u'u'), + (0x1D5B5, 'M', u'v'), + (0x1D5B6, 'M', u'w'), + (0x1D5B7, 'M', u'x'), + (0x1D5B8, 'M', u'y'), + (0x1D5B9, 'M', u'z'), + (0x1D5BA, 'M', u'a'), + (0x1D5BB, 'M', u'b'), + (0x1D5BC, 'M', u'c'), + (0x1D5BD, 'M', u'd'), + (0x1D5BE, 'M', u'e'), + (0x1D5BF, 'M', u'f'), + (0x1D5C0, 'M', u'g'), + (0x1D5C1, 'M', u'h'), + (0x1D5C2, 'M', u'i'), + (0x1D5C3, 'M', u'j'), + (0x1D5C4, 'M', u'k'), + (0x1D5C5, 'M', u'l'), + (0x1D5C6, 'M', u'm'), + (0x1D5C7, 'M', u'n'), + (0x1D5C8, 'M', u'o'), + (0x1D5C9, 'M', u'p'), + (0x1D5CA, 'M', u'q'), + (0x1D5CB, 'M', u'r'), + (0x1D5CC, 'M', u's'), + (0x1D5CD, 'M', u't'), + (0x1D5CE, 'M', u'u'), + (0x1D5CF, 'M', u'v'), + (0x1D5D0, 'M', u'w'), + (0x1D5D1, 'M', u'x'), + (0x1D5D2, 'M', u'y'), + ] + +def _seg_58(): + return [ + (0x1D5D3, 'M', u'z'), + (0x1D5D4, 'M', u'a'), + (0x1D5D5, 'M', u'b'), + (0x1D5D6, 'M', u'c'), + (0x1D5D7, 'M', u'd'), + (0x1D5D8, 'M', u'e'), + (0x1D5D9, 'M', u'f'), + (0x1D5DA, 'M', u'g'), + (0x1D5DB, 'M', u'h'), + (0x1D5DC, 'M', u'i'), + (0x1D5DD, 'M', u'j'), + (0x1D5DE, 'M', u'k'), + (0x1D5DF, 'M', u'l'), + (0x1D5E0, 'M', u'm'), + (0x1D5E1, 'M', u'n'), + (0x1D5E2, 'M', u'o'), + (0x1D5E3, 'M', u'p'), + (0x1D5E4, 'M', u'q'), + (0x1D5E5, 'M', u'r'), + (0x1D5E6, 'M', u's'), + (0x1D5E7, 'M', u't'), + (0x1D5E8, 'M', u'u'), + (0x1D5E9, 'M', u'v'), + (0x1D5EA, 'M', u'w'), + (0x1D5EB, 'M', u'x'), + (0x1D5EC, 'M', u'y'), + (0x1D5ED, 'M', u'z'), + (0x1D5EE, 'M', u'a'), + (0x1D5EF, 'M', u'b'), + (0x1D5F0, 'M', u'c'), + (0x1D5F1, 'M', u'd'), + (0x1D5F2, 'M', u'e'), + (0x1D5F3, 'M', u'f'), + (0x1D5F4, 'M', u'g'), + (0x1D5F5, 'M', u'h'), + (0x1D5F6, 'M', u'i'), + (0x1D5F7, 'M', u'j'), + (0x1D5F8, 'M', u'k'), + (0x1D5F9, 'M', u'l'), + (0x1D5FA, 'M', u'm'), + (0x1D5FB, 'M', u'n'), + (0x1D5FC, 'M', u'o'), + (0x1D5FD, 'M', u'p'), + (0x1D5FE, 'M', u'q'), + (0x1D5FF, 'M', u'r'), + (0x1D600, 'M', u's'), + (0x1D601, 'M', u't'), + (0x1D602, 'M', u'u'), + (0x1D603, 'M', u'v'), + (0x1D604, 'M', u'w'), + (0x1D605, 'M', u'x'), + (0x1D606, 'M', u'y'), + (0x1D607, 'M', u'z'), + (0x1D608, 'M', u'a'), + (0x1D609, 'M', u'b'), + (0x1D60A, 'M', u'c'), + (0x1D60B, 'M', u'd'), + (0x1D60C, 'M', u'e'), + (0x1D60D, 'M', u'f'), + (0x1D60E, 'M', u'g'), + (0x1D60F, 'M', u'h'), + (0x1D610, 'M', u'i'), + (0x1D611, 'M', u'j'), + (0x1D612, 'M', u'k'), + (0x1D613, 'M', u'l'), + (0x1D614, 'M', u'm'), + (0x1D615, 'M', u'n'), + (0x1D616, 'M', u'o'), + (0x1D617, 'M', u'p'), + (0x1D618, 'M', u'q'), + (0x1D619, 'M', u'r'), + (0x1D61A, 'M', u's'), + (0x1D61B, 'M', u't'), + (0x1D61C, 'M', u'u'), + (0x1D61D, 'M', u'v'), + (0x1D61E, 'M', u'w'), + (0x1D61F, 'M', u'x'), + (0x1D620, 'M', u'y'), + (0x1D621, 'M', u'z'), + (0x1D622, 'M', u'a'), + (0x1D623, 'M', u'b'), + (0x1D624, 'M', u'c'), + (0x1D625, 'M', u'd'), + (0x1D626, 'M', u'e'), + (0x1D627, 'M', u'f'), + (0x1D628, 'M', u'g'), + (0x1D629, 'M', u'h'), + (0x1D62A, 'M', u'i'), + (0x1D62B, 'M', u'j'), + (0x1D62C, 'M', u'k'), + (0x1D62D, 'M', u'l'), + (0x1D62E, 'M', u'm'), + (0x1D62F, 'M', u'n'), + (0x1D630, 'M', u'o'), + (0x1D631, 'M', u'p'), + (0x1D632, 'M', u'q'), + (0x1D633, 'M', u'r'), + (0x1D634, 'M', u's'), + (0x1D635, 'M', u't'), + (0x1D636, 'M', u'u'), + ] + +def _seg_59(): + return [ + (0x1D637, 'M', u'v'), + (0x1D638, 'M', u'w'), + (0x1D639, 'M', u'x'), + (0x1D63A, 'M', u'y'), + (0x1D63B, 'M', u'z'), + (0x1D63C, 'M', u'a'), + (0x1D63D, 'M', u'b'), + (0x1D63E, 'M', u'c'), + (0x1D63F, 'M', u'd'), + (0x1D640, 'M', u'e'), + (0x1D641, 'M', u'f'), + (0x1D642, 'M', u'g'), + (0x1D643, 'M', u'h'), + (0x1D644, 'M', u'i'), + (0x1D645, 'M', u'j'), + (0x1D646, 'M', u'k'), + (0x1D647, 'M', u'l'), + (0x1D648, 'M', u'm'), + (0x1D649, 'M', u'n'), + (0x1D64A, 'M', u'o'), + (0x1D64B, 'M', u'p'), + (0x1D64C, 'M', u'q'), + (0x1D64D, 'M', u'r'), + (0x1D64E, 'M', u's'), + (0x1D64F, 'M', u't'), + (0x1D650, 'M', u'u'), + (0x1D651, 'M', u'v'), + (0x1D652, 'M', u'w'), + (0x1D653, 'M', u'x'), + (0x1D654, 'M', u'y'), + (0x1D655, 'M', u'z'), + (0x1D656, 'M', u'a'), + (0x1D657, 'M', u'b'), + (0x1D658, 'M', u'c'), + (0x1D659, 'M', u'd'), + (0x1D65A, 'M', u'e'), + (0x1D65B, 'M', u'f'), + (0x1D65C, 'M', u'g'), + (0x1D65D, 'M', u'h'), + (0x1D65E, 'M', u'i'), + (0x1D65F, 'M', u'j'), + (0x1D660, 'M', u'k'), + (0x1D661, 'M', u'l'), + (0x1D662, 'M', u'm'), + (0x1D663, 'M', u'n'), + (0x1D664, 'M', u'o'), + (0x1D665, 'M', u'p'), + (0x1D666, 'M', u'q'), + (0x1D667, 'M', u'r'), + (0x1D668, 'M', u's'), + (0x1D669, 'M', u't'), + (0x1D66A, 'M', u'u'), + (0x1D66B, 'M', u'v'), + (0x1D66C, 'M', u'w'), + (0x1D66D, 'M', u'x'), + (0x1D66E, 'M', u'y'), + (0x1D66F, 'M', u'z'), + (0x1D670, 'M', u'a'), + (0x1D671, 'M', u'b'), + (0x1D672, 'M', u'c'), + (0x1D673, 'M', u'd'), + (0x1D674, 'M', u'e'), + (0x1D675, 'M', u'f'), + (0x1D676, 'M', u'g'), + (0x1D677, 'M', u'h'), + (0x1D678, 'M', u'i'), + (0x1D679, 'M', u'j'), + (0x1D67A, 'M', u'k'), + (0x1D67B, 'M', u'l'), + (0x1D67C, 'M', u'm'), + (0x1D67D, 'M', u'n'), + (0x1D67E, 'M', u'o'), + (0x1D67F, 'M', u'p'), + (0x1D680, 'M', u'q'), + (0x1D681, 'M', u'r'), + (0x1D682, 'M', u's'), + (0x1D683, 'M', u't'), + (0x1D684, 'M', u'u'), + (0x1D685, 'M', u'v'), + (0x1D686, 'M', u'w'), + (0x1D687, 'M', u'x'), + (0x1D688, 'M', u'y'), + (0x1D689, 'M', u'z'), + (0x1D68A, 'M', u'a'), + (0x1D68B, 'M', u'b'), + (0x1D68C, 'M', u'c'), + (0x1D68D, 'M', u'd'), + (0x1D68E, 'M', u'e'), + (0x1D68F, 'M', u'f'), + (0x1D690, 'M', u'g'), + (0x1D691, 'M', u'h'), + (0x1D692, 'M', u'i'), + (0x1D693, 'M', u'j'), + (0x1D694, 'M', u'k'), + (0x1D695, 'M', u'l'), + (0x1D696, 'M', u'm'), + (0x1D697, 'M', u'n'), + (0x1D698, 'M', u'o'), + (0x1D699, 'M', u'p'), + (0x1D69A, 'M', u'q'), + ] + +def _seg_60(): + return [ + (0x1D69B, 'M', u'r'), + (0x1D69C, 'M', u's'), + (0x1D69D, 'M', u't'), + (0x1D69E, 'M', u'u'), + (0x1D69F, 'M', u'v'), + (0x1D6A0, 'M', u'w'), + (0x1D6A1, 'M', u'x'), + (0x1D6A2, 'M', u'y'), + (0x1D6A3, 'M', u'z'), + (0x1D6A4, 'M', u'ı'), + (0x1D6A5, 'M', u'È·'), + (0x1D6A6, 'X'), + (0x1D6A8, 'M', u'α'), + (0x1D6A9, 'M', u'β'), + (0x1D6AA, 'M', u'γ'), + (0x1D6AB, 'M', u'δ'), + (0x1D6AC, 'M', u'ε'), + (0x1D6AD, 'M', u'ζ'), + (0x1D6AE, 'M', u'η'), + (0x1D6AF, 'M', u'θ'), + (0x1D6B0, 'M', u'ι'), + (0x1D6B1, 'M', u'κ'), + (0x1D6B2, 'M', u'λ'), + (0x1D6B3, 'M', u'μ'), + (0x1D6B4, 'M', u'ν'), + (0x1D6B5, 'M', u'ξ'), + (0x1D6B6, 'M', u'ο'), + (0x1D6B7, 'M', u'Ï€'), + (0x1D6B8, 'M', u'Ï'), + (0x1D6B9, 'M', u'θ'), + (0x1D6BA, 'M', u'σ'), + (0x1D6BB, 'M', u'Ï„'), + (0x1D6BC, 'M', u'Ï…'), + (0x1D6BD, 'M', u'φ'), + (0x1D6BE, 'M', u'χ'), + (0x1D6BF, 'M', u'ψ'), + (0x1D6C0, 'M', u'ω'), + (0x1D6C1, 'M', u'∇'), + (0x1D6C2, 'M', u'α'), + (0x1D6C3, 'M', u'β'), + (0x1D6C4, 'M', u'γ'), + (0x1D6C5, 'M', u'δ'), + (0x1D6C6, 'M', u'ε'), + (0x1D6C7, 'M', u'ζ'), + (0x1D6C8, 'M', u'η'), + (0x1D6C9, 'M', u'θ'), + (0x1D6CA, 'M', u'ι'), + (0x1D6CB, 'M', u'κ'), + (0x1D6CC, 'M', u'λ'), + (0x1D6CD, 'M', u'μ'), + (0x1D6CE, 'M', u'ν'), + (0x1D6CF, 'M', u'ξ'), + (0x1D6D0, 'M', u'ο'), + (0x1D6D1, 'M', u'Ï€'), + (0x1D6D2, 'M', u'Ï'), + (0x1D6D3, 'M', u'σ'), + (0x1D6D5, 'M', u'Ï„'), + (0x1D6D6, 'M', u'Ï…'), + (0x1D6D7, 'M', u'φ'), + (0x1D6D8, 'M', u'χ'), + (0x1D6D9, 'M', u'ψ'), + (0x1D6DA, 'M', u'ω'), + (0x1D6DB, 'M', u'∂'), + (0x1D6DC, 'M', u'ε'), + (0x1D6DD, 'M', u'θ'), + (0x1D6DE, 'M', u'κ'), + (0x1D6DF, 'M', u'φ'), + (0x1D6E0, 'M', u'Ï'), + (0x1D6E1, 'M', u'Ï€'), + (0x1D6E2, 'M', u'α'), + (0x1D6E3, 'M', u'β'), + (0x1D6E4, 'M', u'γ'), + (0x1D6E5, 'M', u'δ'), + (0x1D6E6, 'M', u'ε'), + (0x1D6E7, 'M', u'ζ'), + (0x1D6E8, 'M', u'η'), + (0x1D6E9, 'M', u'θ'), + (0x1D6EA, 'M', u'ι'), + (0x1D6EB, 'M', u'κ'), + (0x1D6EC, 'M', u'λ'), + (0x1D6ED, 'M', u'μ'), + (0x1D6EE, 'M', u'ν'), + (0x1D6EF, 'M', u'ξ'), + (0x1D6F0, 'M', u'ο'), + (0x1D6F1, 'M', u'Ï€'), + (0x1D6F2, 'M', u'Ï'), + (0x1D6F3, 'M', u'θ'), + (0x1D6F4, 'M', u'σ'), + (0x1D6F5, 'M', u'Ï„'), + (0x1D6F6, 'M', u'Ï…'), + (0x1D6F7, 'M', u'φ'), + (0x1D6F8, 'M', u'χ'), + (0x1D6F9, 'M', u'ψ'), + (0x1D6FA, 'M', u'ω'), + (0x1D6FB, 'M', u'∇'), + (0x1D6FC, 'M', u'α'), + (0x1D6FD, 'M', u'β'), + (0x1D6FE, 'M', u'γ'), + (0x1D6FF, 'M', u'δ'), + (0x1D700, 'M', u'ε'), + ] + +def _seg_61(): + return [ + (0x1D701, 'M', u'ζ'), + (0x1D702, 'M', u'η'), + (0x1D703, 'M', u'θ'), + (0x1D704, 'M', u'ι'), + (0x1D705, 'M', u'κ'), + (0x1D706, 'M', u'λ'), + (0x1D707, 'M', u'μ'), + (0x1D708, 'M', u'ν'), + (0x1D709, 'M', u'ξ'), + (0x1D70A, 'M', u'ο'), + (0x1D70B, 'M', u'Ï€'), + (0x1D70C, 'M', u'Ï'), + (0x1D70D, 'M', u'σ'), + (0x1D70F, 'M', u'Ï„'), + (0x1D710, 'M', u'Ï…'), + (0x1D711, 'M', u'φ'), + (0x1D712, 'M', u'χ'), + (0x1D713, 'M', u'ψ'), + (0x1D714, 'M', u'ω'), + (0x1D715, 'M', u'∂'), + (0x1D716, 'M', u'ε'), + (0x1D717, 'M', u'θ'), + (0x1D718, 'M', u'κ'), + (0x1D719, 'M', u'φ'), + (0x1D71A, 'M', u'Ï'), + (0x1D71B, 'M', u'Ï€'), + (0x1D71C, 'M', u'α'), + (0x1D71D, 'M', u'β'), + (0x1D71E, 'M', u'γ'), + (0x1D71F, 'M', u'δ'), + (0x1D720, 'M', u'ε'), + (0x1D721, 'M', u'ζ'), + (0x1D722, 'M', u'η'), + (0x1D723, 'M', u'θ'), + (0x1D724, 'M', u'ι'), + (0x1D725, 'M', u'κ'), + (0x1D726, 'M', u'λ'), + (0x1D727, 'M', u'μ'), + (0x1D728, 'M', u'ν'), + (0x1D729, 'M', u'ξ'), + (0x1D72A, 'M', u'ο'), + (0x1D72B, 'M', u'Ï€'), + (0x1D72C, 'M', u'Ï'), + (0x1D72D, 'M', u'θ'), + (0x1D72E, 'M', u'σ'), + (0x1D72F, 'M', u'Ï„'), + (0x1D730, 'M', u'Ï…'), + (0x1D731, 'M', u'φ'), + (0x1D732, 'M', u'χ'), + (0x1D733, 'M', u'ψ'), + (0x1D734, 'M', u'ω'), + (0x1D735, 'M', u'∇'), + (0x1D736, 'M', u'α'), + (0x1D737, 'M', u'β'), + (0x1D738, 'M', u'γ'), + (0x1D739, 'M', u'δ'), + (0x1D73A, 'M', u'ε'), + (0x1D73B, 'M', u'ζ'), + (0x1D73C, 'M', u'η'), + (0x1D73D, 'M', u'θ'), + (0x1D73E, 'M', u'ι'), + (0x1D73F, 'M', u'κ'), + (0x1D740, 'M', u'λ'), + (0x1D741, 'M', u'μ'), + (0x1D742, 'M', u'ν'), + (0x1D743, 'M', u'ξ'), + (0x1D744, 'M', u'ο'), + (0x1D745, 'M', u'Ï€'), + (0x1D746, 'M', u'Ï'), + (0x1D747, 'M', u'σ'), + (0x1D749, 'M', u'Ï„'), + (0x1D74A, 'M', u'Ï…'), + (0x1D74B, 'M', u'φ'), + (0x1D74C, 'M', u'χ'), + (0x1D74D, 'M', u'ψ'), + (0x1D74E, 'M', u'ω'), + (0x1D74F, 'M', u'∂'), + (0x1D750, 'M', u'ε'), + (0x1D751, 'M', u'θ'), + (0x1D752, 'M', u'κ'), + (0x1D753, 'M', u'φ'), + (0x1D754, 'M', u'Ï'), + (0x1D755, 'M', u'Ï€'), + (0x1D756, 'M', u'α'), + (0x1D757, 'M', u'β'), + (0x1D758, 'M', u'γ'), + (0x1D759, 'M', u'δ'), + (0x1D75A, 'M', u'ε'), + (0x1D75B, 'M', u'ζ'), + (0x1D75C, 'M', u'η'), + (0x1D75D, 'M', u'θ'), + (0x1D75E, 'M', u'ι'), + (0x1D75F, 'M', u'κ'), + (0x1D760, 'M', u'λ'), + (0x1D761, 'M', u'μ'), + (0x1D762, 'M', u'ν'), + (0x1D763, 'M', u'ξ'), + (0x1D764, 'M', u'ο'), + (0x1D765, 'M', u'Ï€'), + (0x1D766, 'M', u'Ï'), + ] + +def _seg_62(): + return [ + (0x1D767, 'M', u'θ'), + (0x1D768, 'M', u'σ'), + (0x1D769, 'M', u'Ï„'), + (0x1D76A, 'M', u'Ï…'), + (0x1D76B, 'M', u'φ'), + (0x1D76C, 'M', u'χ'), + (0x1D76D, 'M', u'ψ'), + (0x1D76E, 'M', u'ω'), + (0x1D76F, 'M', u'∇'), + (0x1D770, 'M', u'α'), + (0x1D771, 'M', u'β'), + (0x1D772, 'M', u'γ'), + (0x1D773, 'M', u'δ'), + (0x1D774, 'M', u'ε'), + (0x1D775, 'M', u'ζ'), + (0x1D776, 'M', u'η'), + (0x1D777, 'M', u'θ'), + (0x1D778, 'M', u'ι'), + (0x1D779, 'M', u'κ'), + (0x1D77A, 'M', u'λ'), + (0x1D77B, 'M', u'μ'), + (0x1D77C, 'M', u'ν'), + (0x1D77D, 'M', u'ξ'), + (0x1D77E, 'M', u'ο'), + (0x1D77F, 'M', u'Ï€'), + (0x1D780, 'M', u'Ï'), + (0x1D781, 'M', u'σ'), + (0x1D783, 'M', u'Ï„'), + (0x1D784, 'M', u'Ï…'), + (0x1D785, 'M', u'φ'), + (0x1D786, 'M', u'χ'), + (0x1D787, 'M', u'ψ'), + (0x1D788, 'M', u'ω'), + (0x1D789, 'M', u'∂'), + (0x1D78A, 'M', u'ε'), + (0x1D78B, 'M', u'θ'), + (0x1D78C, 'M', u'κ'), + (0x1D78D, 'M', u'φ'), + (0x1D78E, 'M', u'Ï'), + (0x1D78F, 'M', u'Ï€'), + (0x1D790, 'M', u'α'), + (0x1D791, 'M', u'β'), + (0x1D792, 'M', u'γ'), + (0x1D793, 'M', u'δ'), + (0x1D794, 'M', u'ε'), + (0x1D795, 'M', u'ζ'), + (0x1D796, 'M', u'η'), + (0x1D797, 'M', u'θ'), + (0x1D798, 'M', u'ι'), + (0x1D799, 'M', u'κ'), + (0x1D79A, 'M', u'λ'), + (0x1D79B, 'M', u'μ'), + (0x1D79C, 'M', u'ν'), + (0x1D79D, 'M', u'ξ'), + (0x1D79E, 'M', u'ο'), + (0x1D79F, 'M', u'Ï€'), + (0x1D7A0, 'M', u'Ï'), + (0x1D7A1, 'M', u'θ'), + (0x1D7A2, 'M', u'σ'), + (0x1D7A3, 'M', u'Ï„'), + (0x1D7A4, 'M', u'Ï…'), + (0x1D7A5, 'M', u'φ'), + (0x1D7A6, 'M', u'χ'), + (0x1D7A7, 'M', u'ψ'), + (0x1D7A8, 'M', u'ω'), + (0x1D7A9, 'M', u'∇'), + (0x1D7AA, 'M', u'α'), + (0x1D7AB, 'M', u'β'), + (0x1D7AC, 'M', u'γ'), + (0x1D7AD, 'M', u'δ'), + (0x1D7AE, 'M', u'ε'), + (0x1D7AF, 'M', u'ζ'), + (0x1D7B0, 'M', u'η'), + (0x1D7B1, 'M', u'θ'), + (0x1D7B2, 'M', u'ι'), + (0x1D7B3, 'M', u'κ'), + (0x1D7B4, 'M', u'λ'), + (0x1D7B5, 'M', u'μ'), + (0x1D7B6, 'M', u'ν'), + (0x1D7B7, 'M', u'ξ'), + (0x1D7B8, 'M', u'ο'), + (0x1D7B9, 'M', u'Ï€'), + (0x1D7BA, 'M', u'Ï'), + (0x1D7BB, 'M', u'σ'), + (0x1D7BD, 'M', u'Ï„'), + (0x1D7BE, 'M', u'Ï…'), + (0x1D7BF, 'M', u'φ'), + (0x1D7C0, 'M', u'χ'), + (0x1D7C1, 'M', u'ψ'), + (0x1D7C2, 'M', u'ω'), + (0x1D7C3, 'M', u'∂'), + (0x1D7C4, 'M', u'ε'), + (0x1D7C5, 'M', u'θ'), + (0x1D7C6, 'M', u'κ'), + (0x1D7C7, 'M', u'φ'), + (0x1D7C8, 'M', u'Ï'), + (0x1D7C9, 'M', u'Ï€'), + (0x1D7CA, 'M', u'Ï'), + (0x1D7CC, 'X'), + (0x1D7CE, 'M', u'0'), + ] + +def _seg_63(): + return [ + (0x1D7CF, 'M', u'1'), + (0x1D7D0, 'M', u'2'), + (0x1D7D1, 'M', u'3'), + (0x1D7D2, 'M', u'4'), + (0x1D7D3, 'M', u'5'), + (0x1D7D4, 'M', u'6'), + (0x1D7D5, 'M', u'7'), + (0x1D7D6, 'M', u'8'), + (0x1D7D7, 'M', u'9'), + (0x1D7D8, 'M', u'0'), + (0x1D7D9, 'M', u'1'), + (0x1D7DA, 'M', u'2'), + (0x1D7DB, 'M', u'3'), + (0x1D7DC, 'M', u'4'), + (0x1D7DD, 'M', u'5'), + (0x1D7DE, 'M', u'6'), + (0x1D7DF, 'M', u'7'), + (0x1D7E0, 'M', u'8'), + (0x1D7E1, 'M', u'9'), + (0x1D7E2, 'M', u'0'), + (0x1D7E3, 'M', u'1'), + (0x1D7E4, 'M', u'2'), + (0x1D7E5, 'M', u'3'), + (0x1D7E6, 'M', u'4'), + (0x1D7E7, 'M', u'5'), + (0x1D7E8, 'M', u'6'), + (0x1D7E9, 'M', u'7'), + (0x1D7EA, 'M', u'8'), + (0x1D7EB, 'M', u'9'), + (0x1D7EC, 'M', u'0'), + (0x1D7ED, 'M', u'1'), + (0x1D7EE, 'M', u'2'), + (0x1D7EF, 'M', u'3'), + (0x1D7F0, 'M', u'4'), + (0x1D7F1, 'M', u'5'), + (0x1D7F2, 'M', u'6'), + (0x1D7F3, 'M', u'7'), + (0x1D7F4, 'M', u'8'), + (0x1D7F5, 'M', u'9'), + (0x1D7F6, 'M', u'0'), + (0x1D7F7, 'M', u'1'), + (0x1D7F8, 'M', u'2'), + (0x1D7F9, 'M', u'3'), + (0x1D7FA, 'M', u'4'), + (0x1D7FB, 'M', u'5'), + (0x1D7FC, 'M', u'6'), + (0x1D7FD, 'M', u'7'), + (0x1D7FE, 'M', u'8'), + (0x1D7FF, 'M', u'9'), + (0x1D800, 'X'), + (0x1EE00, 'M', u'ا'), + (0x1EE01, 'M', u'ب'), + (0x1EE02, 'M', u'ج'), + (0x1EE03, 'M', u'د'), + (0x1EE04, 'X'), + (0x1EE05, 'M', u'Ùˆ'), + (0x1EE06, 'M', u'ز'), + (0x1EE07, 'M', u'Ø­'), + (0x1EE08, 'M', u'Ø·'), + (0x1EE09, 'M', u'ÙŠ'), + (0x1EE0A, 'M', u'Ùƒ'), + (0x1EE0B, 'M', u'Ù„'), + (0x1EE0C, 'M', u'Ù…'), + (0x1EE0D, 'M', u'Ù†'), + (0x1EE0E, 'M', u'س'), + (0x1EE0F, 'M', u'ع'), + (0x1EE10, 'M', u'Ù'), + (0x1EE11, 'M', u'ص'), + (0x1EE12, 'M', u'Ù‚'), + (0x1EE13, 'M', u'ر'), + (0x1EE14, 'M', u'Ø´'), + (0x1EE15, 'M', u'ت'), + (0x1EE16, 'M', u'Ø«'), + (0x1EE17, 'M', u'Ø®'), + (0x1EE18, 'M', u'ذ'), + (0x1EE19, 'M', u'ض'), + (0x1EE1A, 'M', u'ظ'), + (0x1EE1B, 'M', u'غ'), + (0x1EE1C, 'M', u'Ù®'), + (0x1EE1D, 'M', u'Úº'), + (0x1EE1E, 'M', u'Ú¡'), + (0x1EE1F, 'M', u'Ù¯'), + (0x1EE20, 'X'), + (0x1EE21, 'M', u'ب'), + (0x1EE22, 'M', u'ج'), + (0x1EE23, 'X'), + (0x1EE24, 'M', u'Ù‡'), + (0x1EE25, 'X'), + (0x1EE27, 'M', u'Ø­'), + (0x1EE28, 'X'), + (0x1EE29, 'M', u'ÙŠ'), + (0x1EE2A, 'M', u'Ùƒ'), + (0x1EE2B, 'M', u'Ù„'), + (0x1EE2C, 'M', u'Ù…'), + (0x1EE2D, 'M', u'Ù†'), + (0x1EE2E, 'M', u'س'), + (0x1EE2F, 'M', u'ع'), + (0x1EE30, 'M', u'Ù'), + (0x1EE31, 'M', u'ص'), + (0x1EE32, 'M', u'Ù‚'), + ] + +def _seg_64(): + return [ + (0x1EE33, 'X'), + (0x1EE34, 'M', u'Ø´'), + (0x1EE35, 'M', u'ت'), + (0x1EE36, 'M', u'Ø«'), + (0x1EE37, 'M', u'Ø®'), + (0x1EE38, 'X'), + (0x1EE39, 'M', u'ض'), + (0x1EE3A, 'X'), + (0x1EE3B, 'M', u'غ'), + (0x1EE3C, 'X'), + (0x1EE42, 'M', u'ج'), + (0x1EE43, 'X'), + (0x1EE47, 'M', u'Ø­'), + (0x1EE48, 'X'), + (0x1EE49, 'M', u'ÙŠ'), + (0x1EE4A, 'X'), + (0x1EE4B, 'M', u'Ù„'), + (0x1EE4C, 'X'), + (0x1EE4D, 'M', u'Ù†'), + (0x1EE4E, 'M', u'س'), + (0x1EE4F, 'M', u'ع'), + (0x1EE50, 'X'), + (0x1EE51, 'M', u'ص'), + (0x1EE52, 'M', u'Ù‚'), + (0x1EE53, 'X'), + (0x1EE54, 'M', u'Ø´'), + (0x1EE55, 'X'), + (0x1EE57, 'M', u'Ø®'), + (0x1EE58, 'X'), + (0x1EE59, 'M', u'ض'), + (0x1EE5A, 'X'), + (0x1EE5B, 'M', u'غ'), + (0x1EE5C, 'X'), + (0x1EE5D, 'M', u'Úº'), + (0x1EE5E, 'X'), + (0x1EE5F, 'M', u'Ù¯'), + (0x1EE60, 'X'), + (0x1EE61, 'M', u'ب'), + (0x1EE62, 'M', u'ج'), + (0x1EE63, 'X'), + (0x1EE64, 'M', u'Ù‡'), + (0x1EE65, 'X'), + (0x1EE67, 'M', u'Ø­'), + (0x1EE68, 'M', u'Ø·'), + (0x1EE69, 'M', u'ÙŠ'), + (0x1EE6A, 'M', u'Ùƒ'), + (0x1EE6B, 'X'), + (0x1EE6C, 'M', u'Ù…'), + (0x1EE6D, 'M', u'Ù†'), + (0x1EE6E, 'M', u'س'), + (0x1EE6F, 'M', u'ع'), + (0x1EE70, 'M', u'Ù'), + (0x1EE71, 'M', u'ص'), + (0x1EE72, 'M', u'Ù‚'), + (0x1EE73, 'X'), + (0x1EE74, 'M', u'Ø´'), + (0x1EE75, 'M', u'ت'), + (0x1EE76, 'M', u'Ø«'), + (0x1EE77, 'M', u'Ø®'), + (0x1EE78, 'X'), + (0x1EE79, 'M', u'ض'), + (0x1EE7A, 'M', u'ظ'), + (0x1EE7B, 'M', u'غ'), + (0x1EE7C, 'M', u'Ù®'), + (0x1EE7D, 'X'), + (0x1EE7E, 'M', u'Ú¡'), + (0x1EE7F, 'X'), + (0x1EE80, 'M', u'ا'), + (0x1EE81, 'M', u'ب'), + (0x1EE82, 'M', u'ج'), + (0x1EE83, 'M', u'د'), + (0x1EE84, 'M', u'Ù‡'), + (0x1EE85, 'M', u'Ùˆ'), + (0x1EE86, 'M', u'ز'), + (0x1EE87, 'M', u'Ø­'), + (0x1EE88, 'M', u'Ø·'), + (0x1EE89, 'M', u'ÙŠ'), + (0x1EE8A, 'X'), + (0x1EE8B, 'M', u'Ù„'), + (0x1EE8C, 'M', u'Ù…'), + (0x1EE8D, 'M', u'Ù†'), + (0x1EE8E, 'M', u'س'), + (0x1EE8F, 'M', u'ع'), + (0x1EE90, 'M', u'Ù'), + (0x1EE91, 'M', u'ص'), + (0x1EE92, 'M', u'Ù‚'), + (0x1EE93, 'M', u'ر'), + (0x1EE94, 'M', u'Ø´'), + (0x1EE95, 'M', u'ت'), + (0x1EE96, 'M', u'Ø«'), + (0x1EE97, 'M', u'Ø®'), + (0x1EE98, 'M', u'ذ'), + (0x1EE99, 'M', u'ض'), + (0x1EE9A, 'M', u'ظ'), + (0x1EE9B, 'M', u'غ'), + (0x1EE9C, 'X'), + (0x1EEA1, 'M', u'ب'), + (0x1EEA2, 'M', u'ج'), + (0x1EEA3, 'M', u'د'), + (0x1EEA4, 'X'), + ] + +def _seg_65(): + return [ + (0x1EEA5, 'M', u'Ùˆ'), + (0x1EEA6, 'M', u'ز'), + (0x1EEA7, 'M', u'Ø­'), + (0x1EEA8, 'M', u'Ø·'), + (0x1EEA9, 'M', u'ÙŠ'), + (0x1EEAA, 'X'), + (0x1EEAB, 'M', u'Ù„'), + (0x1EEAC, 'M', u'Ù…'), + (0x1EEAD, 'M', u'Ù†'), + (0x1EEAE, 'M', u'س'), + (0x1EEAF, 'M', u'ع'), + (0x1EEB0, 'M', u'Ù'), + (0x1EEB1, 'M', u'ص'), + (0x1EEB2, 'M', u'Ù‚'), + (0x1EEB3, 'M', u'ر'), + (0x1EEB4, 'M', u'Ø´'), + (0x1EEB5, 'M', u'ت'), + (0x1EEB6, 'M', u'Ø«'), + (0x1EEB7, 'M', u'Ø®'), + (0x1EEB8, 'M', u'ذ'), + (0x1EEB9, 'M', u'ض'), + (0x1EEBA, 'M', u'ظ'), + (0x1EEBB, 'M', u'غ'), + (0x1EEBC, 'X'), + (0x1EEF0, 'V'), + (0x1EEF2, 'X'), + (0x1F000, 'V'), + (0x1F02C, 'X'), + (0x1F030, 'V'), + (0x1F094, 'X'), + (0x1F0A0, 'V'), + (0x1F0AF, 'X'), + (0x1F0B1, 'V'), + (0x1F0BF, 'X'), + (0x1F0C1, 'V'), + (0x1F0D0, 'X'), + (0x1F0D1, 'V'), + (0x1F0E0, 'X'), + (0x1F101, '3', u'0,'), + (0x1F102, '3', u'1,'), + (0x1F103, '3', u'2,'), + (0x1F104, '3', u'3,'), + (0x1F105, '3', u'4,'), + (0x1F106, '3', u'5,'), + (0x1F107, '3', u'6,'), + (0x1F108, '3', u'7,'), + (0x1F109, '3', u'8,'), + (0x1F10A, '3', u'9,'), + (0x1F10B, 'X'), + (0x1F110, '3', u'(a)'), + (0x1F111, '3', u'(b)'), + (0x1F112, '3', u'(c)'), + (0x1F113, '3', u'(d)'), + (0x1F114, '3', u'(e)'), + (0x1F115, '3', u'(f)'), + (0x1F116, '3', u'(g)'), + (0x1F117, '3', u'(h)'), + (0x1F118, '3', u'(i)'), + (0x1F119, '3', u'(j)'), + (0x1F11A, '3', u'(k)'), + (0x1F11B, '3', u'(l)'), + (0x1F11C, '3', u'(m)'), + (0x1F11D, '3', u'(n)'), + (0x1F11E, '3', u'(o)'), + (0x1F11F, '3', u'(p)'), + (0x1F120, '3', u'(q)'), + (0x1F121, '3', u'(r)'), + (0x1F122, '3', u'(s)'), + (0x1F123, '3', u'(t)'), + (0x1F124, '3', u'(u)'), + (0x1F125, '3', u'(v)'), + (0x1F126, '3', u'(w)'), + (0x1F127, '3', u'(x)'), + (0x1F128, '3', u'(y)'), + (0x1F129, '3', u'(z)'), + (0x1F12A, 'M', u'〔s〕'), + (0x1F12B, 'M', u'c'), + (0x1F12C, 'M', u'r'), + (0x1F12D, 'M', u'cd'), + (0x1F12E, 'M', u'wz'), + (0x1F12F, 'X'), + (0x1F130, 'M', u'a'), + (0x1F131, 'M', u'b'), + (0x1F132, 'M', u'c'), + (0x1F133, 'M', u'd'), + (0x1F134, 'M', u'e'), + (0x1F135, 'M', u'f'), + (0x1F136, 'M', u'g'), + (0x1F137, 'M', u'h'), + (0x1F138, 'M', u'i'), + (0x1F139, 'M', u'j'), + (0x1F13A, 'M', u'k'), + (0x1F13B, 'M', u'l'), + (0x1F13C, 'M', u'm'), + (0x1F13D, 'M', u'n'), + (0x1F13E, 'M', u'o'), + (0x1F13F, 'M', u'p'), + (0x1F140, 'M', u'q'), + (0x1F141, 'M', u'r'), + (0x1F142, 'M', u's'), + ] + +def _seg_66(): + return [ + (0x1F143, 'M', u't'), + (0x1F144, 'M', u'u'), + (0x1F145, 'M', u'v'), + (0x1F146, 'M', u'w'), + (0x1F147, 'M', u'x'), + (0x1F148, 'M', u'y'), + (0x1F149, 'M', u'z'), + (0x1F14A, 'M', u'hv'), + (0x1F14B, 'M', u'mv'), + (0x1F14C, 'M', u'sd'), + (0x1F14D, 'M', u'ss'), + (0x1F14E, 'M', u'ppv'), + (0x1F14F, 'M', u'wc'), + (0x1F150, 'V'), + (0x1F16A, 'M', u'mc'), + (0x1F16B, 'M', u'md'), + (0x1F16C, 'X'), + (0x1F170, 'V'), + (0x1F190, 'M', u'dj'), + (0x1F191, 'V'), + (0x1F19B, 'X'), + (0x1F1E6, 'V'), + (0x1F200, 'M', u'ã»ã‹'), + (0x1F201, 'M', u'ココ'), + (0x1F202, 'M', u'サ'), + (0x1F203, 'X'), + (0x1F210, 'M', u'手'), + (0x1F211, 'M', u'å­—'), + (0x1F212, 'M', u'åŒ'), + (0x1F213, 'M', u'デ'), + (0x1F214, 'M', u'二'), + (0x1F215, 'M', u'多'), + (0x1F216, 'M', u'è§£'), + (0x1F217, 'M', u'天'), + (0x1F218, 'M', u'交'), + (0x1F219, 'M', u'映'), + (0x1F21A, 'M', u'ç„¡'), + (0x1F21B, 'M', u'æ–™'), + (0x1F21C, 'M', u'å‰'), + (0x1F21D, 'M', u'後'), + (0x1F21E, 'M', u'å†'), + (0x1F21F, 'M', u'æ–°'), + (0x1F220, 'M', u'åˆ'), + (0x1F221, 'M', u'終'), + (0x1F222, 'M', u'生'), + (0x1F223, 'M', u'販'), + (0x1F224, 'M', u'声'), + (0x1F225, 'M', u'å¹'), + (0x1F226, 'M', u'æ¼”'), + (0x1F227, 'M', u'投'), + (0x1F228, 'M', u'æ•'), + (0x1F229, 'M', u'一'), + (0x1F22A, 'M', u'三'), + (0x1F22B, 'M', u'éŠ'), + (0x1F22C, 'M', u'å·¦'), + (0x1F22D, 'M', u'中'), + (0x1F22E, 'M', u'å³'), + (0x1F22F, 'M', u'指'), + (0x1F230, 'M', u'èµ°'), + (0x1F231, 'M', u'打'), + (0x1F232, 'M', u'ç¦'), + (0x1F233, 'M', u'空'), + (0x1F234, 'M', u'åˆ'), + (0x1F235, 'M', u'満'), + (0x1F236, 'M', u'有'), + (0x1F237, 'M', u'月'), + (0x1F238, 'M', u'申'), + (0x1F239, 'M', u'割'), + (0x1F23A, 'M', u'å–¶'), + (0x1F23B, 'X'), + (0x1F240, 'M', u'〔本〕'), + (0x1F241, 'M', u'〔三〕'), + (0x1F242, 'M', u'〔二〕'), + (0x1F243, 'M', u'〔安〕'), + (0x1F244, 'M', u'〔点〕'), + (0x1F245, 'M', u'〔打〕'), + (0x1F246, 'M', u'〔盗〕'), + (0x1F247, 'M', u'〔å‹ã€•'), + (0x1F248, 'M', u'〔敗〕'), + (0x1F249, 'X'), + (0x1F250, 'M', u'å¾—'), + (0x1F251, 'M', u'å¯'), + (0x1F252, 'X'), + (0x1F300, 'V'), + (0x1F321, 'X'), + (0x1F330, 'V'), + (0x1F336, 'X'), + (0x1F337, 'V'), + (0x1F37D, 'X'), + (0x1F380, 'V'), + (0x1F394, 'X'), + (0x1F3A0, 'V'), + (0x1F3C5, 'X'), + (0x1F3C6, 'V'), + (0x1F3CB, 'X'), + (0x1F3E0, 'V'), + (0x1F3F1, 'X'), + (0x1F400, 'V'), + (0x1F43F, 'X'), + (0x1F440, 'V'), + ] + +def _seg_67(): + return [ + (0x1F441, 'X'), + (0x1F442, 'V'), + (0x1F4F8, 'X'), + (0x1F4F9, 'V'), + (0x1F4FD, 'X'), + (0x1F500, 'V'), + (0x1F53E, 'X'), + (0x1F540, 'V'), + (0x1F544, 'X'), + (0x1F550, 'V'), + (0x1F568, 'X'), + (0x1F5FB, 'V'), + (0x1F641, 'X'), + (0x1F645, 'V'), + (0x1F650, 'X'), + (0x1F680, 'V'), + (0x1F6C6, 'X'), + (0x1F700, 'V'), + (0x1F774, 'X'), + (0x20000, 'V'), + (0x2A6D7, 'X'), + (0x2A700, 'V'), + (0x2B735, 'X'), + (0x2B740, 'V'), + (0x2B81E, 'X'), + (0x2F800, 'M', u'丽'), + (0x2F801, 'M', u'丸'), + (0x2F802, 'M', u'ä¹'), + (0x2F803, 'M', u'ð „¢'), + (0x2F804, 'M', u'ä½ '), + (0x2F805, 'M', u'ä¾®'), + (0x2F806, 'M', u'ä¾»'), + (0x2F807, 'M', u'倂'), + (0x2F808, 'M', u'åº'), + (0x2F809, 'M', u'å‚™'), + (0x2F80A, 'M', u'僧'), + (0x2F80B, 'M', u'åƒ'), + (0x2F80C, 'M', u'ã’ž'), + (0x2F80D, 'M', u'𠘺'), + (0x2F80E, 'M', u'å…'), + (0x2F80F, 'M', u'å…”'), + (0x2F810, 'M', u'å…¤'), + (0x2F811, 'M', u'å…·'), + (0x2F812, 'M', u'𠔜'), + (0x2F813, 'M', u'ã’¹'), + (0x2F814, 'M', u'å…§'), + (0x2F815, 'M', u'å†'), + (0x2F816, 'M', u'ð •‹'), + (0x2F817, 'M', u'冗'), + (0x2F818, 'M', u'冤'), + (0x2F819, 'M', u'仌'), + (0x2F81A, 'M', u'冬'), + (0x2F81B, 'M', u'况'), + (0x2F81C, 'M', u'𩇟'), + (0x2F81D, 'M', u'凵'), + (0x2F81E, 'M', u'刃'), + (0x2F81F, 'M', u'㓟'), + (0x2F820, 'M', u'刻'), + (0x2F821, 'M', u'剆'), + (0x2F822, 'M', u'割'), + (0x2F823, 'M', u'剷'), + (0x2F824, 'M', u'㔕'), + (0x2F825, 'M', u'勇'), + (0x2F826, 'M', u'勉'), + (0x2F827, 'M', u'勤'), + (0x2F828, 'M', u'勺'), + (0x2F829, 'M', u'包'), + (0x2F82A, 'M', u'匆'), + (0x2F82B, 'M', u'北'), + (0x2F82C, 'M', u'å‰'), + (0x2F82D, 'M', u'å‘'), + (0x2F82E, 'M', u'åš'), + (0x2F82F, 'M', u'å³'), + (0x2F830, 'M', u'å½'), + (0x2F831, 'M', u'å¿'), + (0x2F834, 'M', u'𠨬'), + (0x2F835, 'M', u'ç°'), + (0x2F836, 'M', u'åŠ'), + (0x2F837, 'M', u'åŸ'), + (0x2F838, 'M', u'ð ­£'), + (0x2F839, 'M', u'å«'), + (0x2F83A, 'M', u'å±'), + (0x2F83B, 'M', u'å†'), + (0x2F83C, 'M', u'å’ž'), + (0x2F83D, 'M', u'å¸'), + (0x2F83E, 'M', u'呈'), + (0x2F83F, 'M', u'周'), + (0x2F840, 'M', u'å’¢'), + (0x2F841, 'M', u'å“¶'), + (0x2F842, 'M', u'å”'), + (0x2F843, 'M', u'å•“'), + (0x2F844, 'M', u'å•£'), + (0x2F845, 'M', u'å–„'), + (0x2F847, 'M', u'å–™'), + (0x2F848, 'M', u'å–«'), + (0x2F849, 'M', u'å–³'), + (0x2F84A, 'M', u'å—‚'), + (0x2F84B, 'M', u'圖'), + (0x2F84C, 'M', u'嘆'), + (0x2F84D, 'M', u'圗'), + ] + +def _seg_68(): + return [ + (0x2F84E, 'M', u'噑'), + (0x2F84F, 'M', u'å™´'), + (0x2F850, 'M', u'切'), + (0x2F851, 'M', u'壮'), + (0x2F852, 'M', u'城'), + (0x2F853, 'M', u'埴'), + (0x2F854, 'M', u'å '), + (0x2F855, 'M', u'åž‹'), + (0x2F856, 'M', u'å ²'), + (0x2F857, 'M', u'å ±'), + (0x2F858, 'M', u'墬'), + (0x2F859, 'M', u'𡓤'), + (0x2F85A, 'M', u'売'), + (0x2F85B, 'M', u'壷'), + (0x2F85C, 'M', u'夆'), + (0x2F85D, 'M', u'多'), + (0x2F85E, 'M', u'夢'), + (0x2F85F, 'M', u'奢'), + (0x2F860, 'M', u'𡚨'), + (0x2F861, 'M', u'𡛪'), + (0x2F862, 'M', u'姬'), + (0x2F863, 'M', u'娛'), + (0x2F864, 'M', u'娧'), + (0x2F865, 'M', u'姘'), + (0x2F866, 'M', u'婦'), + (0x2F867, 'M', u'ã›®'), + (0x2F868, 'X'), + (0x2F869, 'M', u'嬈'), + (0x2F86A, 'M', u'嬾'), + (0x2F86C, 'M', u'𡧈'), + (0x2F86D, 'M', u'寃'), + (0x2F86E, 'M', u'寘'), + (0x2F86F, 'M', u'寧'), + (0x2F870, 'M', u'寳'), + (0x2F871, 'M', u'𡬘'), + (0x2F872, 'M', u'寿'), + (0x2F873, 'M', u'å°†'), + (0x2F874, 'X'), + (0x2F875, 'M', u'å°¢'), + (0x2F876, 'M', u'ãž'), + (0x2F877, 'M', u'å± '), + (0x2F878, 'M', u'å±®'), + (0x2F879, 'M', u'å³€'), + (0x2F87A, 'M', u'å²'), + (0x2F87B, 'M', u'ð¡·¤'), + (0x2F87C, 'M', u'嵃'), + (0x2F87D, 'M', u'ð¡·¦'), + (0x2F87E, 'M', u'åµ®'), + (0x2F87F, 'M', u'嵫'), + (0x2F880, 'M', u'åµ¼'), + (0x2F881, 'M', u'å·¡'), + (0x2F882, 'M', u'å·¢'), + (0x2F883, 'M', u'ã ¯'), + (0x2F884, 'M', u'å·½'), + (0x2F885, 'M', u'帨'), + (0x2F886, 'M', u'帽'), + (0x2F887, 'M', u'幩'), + (0x2F888, 'M', u'ã¡¢'), + (0x2F889, 'M', u'𢆃'), + (0x2F88A, 'M', u'㡼'), + (0x2F88B, 'M', u'庰'), + (0x2F88C, 'M', u'庳'), + (0x2F88D, 'M', u'庶'), + (0x2F88E, 'M', u'廊'), + (0x2F88F, 'M', u'𪎒'), + (0x2F890, 'M', u'廾'), + (0x2F891, 'M', u'𢌱'), + (0x2F893, 'M', u'èˆ'), + (0x2F894, 'M', u'å¼¢'), + (0x2F896, 'M', u'㣇'), + (0x2F897, 'M', u'𣊸'), + (0x2F898, 'M', u'𦇚'), + (0x2F899, 'M', u'å½¢'), + (0x2F89A, 'M', u'彫'), + (0x2F89B, 'M', u'㣣'), + (0x2F89C, 'M', u'徚'), + (0x2F89D, 'M', u'å¿'), + (0x2F89E, 'M', u'å¿—'), + (0x2F89F, 'M', u'忹'), + (0x2F8A0, 'M', u'æ‚'), + (0x2F8A1, 'M', u'㤺'), + (0x2F8A2, 'M', u'㤜'), + (0x2F8A3, 'M', u'æ‚”'), + (0x2F8A4, 'M', u'𢛔'), + (0x2F8A5, 'M', u'惇'), + (0x2F8A6, 'M', u'æ…ˆ'), + (0x2F8A7, 'M', u'æ…Œ'), + (0x2F8A8, 'M', u'æ…Ž'), + (0x2F8A9, 'M', u'æ…Œ'), + (0x2F8AA, 'M', u'æ…º'), + (0x2F8AB, 'M', u'憎'), + (0x2F8AC, 'M', u'憲'), + (0x2F8AD, 'M', u'憤'), + (0x2F8AE, 'M', u'憯'), + (0x2F8AF, 'M', u'懞'), + (0x2F8B0, 'M', u'懲'), + (0x2F8B1, 'M', u'懶'), + (0x2F8B2, 'M', u'æˆ'), + (0x2F8B3, 'M', u'戛'), + (0x2F8B4, 'M', u'æ‰'), + ] + +def _seg_69(): + return [ + (0x2F8B5, 'M', u'抱'), + (0x2F8B6, 'M', u'æ‹”'), + (0x2F8B7, 'M', u'æ'), + (0x2F8B8, 'M', u'𢬌'), + (0x2F8B9, 'M', u'挽'), + (0x2F8BA, 'M', u'拼'), + (0x2F8BB, 'M', u'æ¨'), + (0x2F8BC, 'M', u'掃'), + (0x2F8BD, 'M', u'æ¤'), + (0x2F8BE, 'M', u'𢯱'), + (0x2F8BF, 'M', u'æ¢'), + (0x2F8C0, 'M', u'æ…'), + (0x2F8C1, 'M', u'掩'), + (0x2F8C2, 'M', u'㨮'), + (0x2F8C3, 'M', u'æ‘©'), + (0x2F8C4, 'M', u'摾'), + (0x2F8C5, 'M', u'æ’'), + (0x2F8C6, 'M', u'æ‘·'), + (0x2F8C7, 'M', u'㩬'), + (0x2F8C8, 'M', u'æ•'), + (0x2F8C9, 'M', u'敬'), + (0x2F8CA, 'M', u'𣀊'), + (0x2F8CB, 'M', u'æ—£'), + (0x2F8CC, 'M', u'書'), + (0x2F8CD, 'M', u'晉'), + (0x2F8CE, 'M', u'㬙'), + (0x2F8CF, 'M', u'æš‘'), + (0x2F8D0, 'M', u'㬈'), + (0x2F8D1, 'M', u'㫤'), + (0x2F8D2, 'M', u'冒'), + (0x2F8D3, 'M', u'冕'), + (0x2F8D4, 'M', u'最'), + (0x2F8D5, 'M', u'æšœ'), + (0x2F8D6, 'M', u'è‚­'), + (0x2F8D7, 'M', u'ä™'), + (0x2F8D8, 'M', u'朗'), + (0x2F8D9, 'M', u'望'), + (0x2F8DA, 'M', u'朡'), + (0x2F8DB, 'M', u'æž'), + (0x2F8DC, 'M', u'æ“'), + (0x2F8DD, 'M', u'ð£ƒ'), + (0x2F8DE, 'M', u'ã­‰'), + (0x2F8DF, 'M', u'柺'), + (0x2F8E0, 'M', u'æž…'), + (0x2F8E1, 'M', u'æ¡’'), + (0x2F8E2, 'M', u'梅'), + (0x2F8E3, 'M', u'𣑭'), + (0x2F8E4, 'M', u'梎'), + (0x2F8E5, 'M', u'æ Ÿ'), + (0x2F8E6, 'M', u'椔'), + (0x2F8E7, 'M', u'ã®'), + (0x2F8E8, 'M', u'楂'), + (0x2F8E9, 'M', u'榣'), + (0x2F8EA, 'M', u'槪'), + (0x2F8EB, 'M', u'檨'), + (0x2F8EC, 'M', u'𣚣'), + (0x2F8ED, 'M', u'æ«›'), + (0x2F8EE, 'M', u'ã°˜'), + (0x2F8EF, 'M', u'次'), + (0x2F8F0, 'M', u'𣢧'), + (0x2F8F1, 'M', u'æ­”'), + (0x2F8F2, 'M', u'㱎'), + (0x2F8F3, 'M', u'æ­²'), + (0x2F8F4, 'M', u'殟'), + (0x2F8F5, 'M', u'殺'), + (0x2F8F6, 'M', u'æ®»'), + (0x2F8F7, 'M', u'ð£ª'), + (0x2F8F8, 'M', u'ð¡´‹'), + (0x2F8F9, 'M', u'𣫺'), + (0x2F8FA, 'M', u'汎'), + (0x2F8FB, 'M', u'𣲼'), + (0x2F8FC, 'M', u'沿'), + (0x2F8FD, 'M', u'æ³'), + (0x2F8FE, 'M', u'æ±§'), + (0x2F8FF, 'M', u'æ´–'), + (0x2F900, 'M', u'æ´¾'), + (0x2F901, 'M', u'æµ·'), + (0x2F902, 'M', u'æµ'), + (0x2F903, 'M', u'浩'), + (0x2F904, 'M', u'浸'), + (0x2F905, 'M', u'æ¶…'), + (0x2F906, 'M', u'𣴞'), + (0x2F907, 'M', u'æ´´'), + (0x2F908, 'M', u'港'), + (0x2F909, 'M', u'æ¹®'), + (0x2F90A, 'M', u'ã´³'), + (0x2F90B, 'M', u'滋'), + (0x2F90C, 'M', u'滇'), + (0x2F90D, 'M', u'𣻑'), + (0x2F90E, 'M', u'æ·¹'), + (0x2F90F, 'M', u'æ½®'), + (0x2F910, 'M', u'𣽞'), + (0x2F911, 'M', u'𣾎'), + (0x2F912, 'M', u'濆'), + (0x2F913, 'M', u'瀹'), + (0x2F914, 'M', u'瀞'), + (0x2F915, 'M', u'瀛'), + (0x2F916, 'M', u'ã¶–'), + (0x2F917, 'M', u'çŠ'), + (0x2F918, 'M', u'ç½'), + ] + +def _seg_70(): + return [ + (0x2F919, 'M', u'ç·'), + (0x2F91A, 'M', u'ç‚­'), + (0x2F91B, 'M', u'𠔥'), + (0x2F91C, 'M', u'ç……'), + (0x2F91D, 'M', u'𤉣'), + (0x2F91E, 'M', u'熜'), + (0x2F91F, 'X'), + (0x2F920, 'M', u'爨'), + (0x2F921, 'M', u'爵'), + (0x2F922, 'M', u'ç‰'), + (0x2F923, 'M', u'𤘈'), + (0x2F924, 'M', u'犀'), + (0x2F925, 'M', u'犕'), + (0x2F926, 'M', u'𤜵'), + (0x2F927, 'M', u'𤠔'), + (0x2F928, 'M', u'çº'), + (0x2F929, 'M', u'王'), + (0x2F92A, 'M', u'㺬'), + (0x2F92B, 'M', u'玥'), + (0x2F92C, 'M', u'㺸'), + (0x2F92E, 'M', u'瑇'), + (0x2F92F, 'M', u'瑜'), + (0x2F930, 'M', u'瑱'), + (0x2F931, 'M', u'ç’…'), + (0x2F932, 'M', u'瓊'), + (0x2F933, 'M', u'ã¼›'), + (0x2F934, 'M', u'甤'), + (0x2F935, 'M', u'𤰶'), + (0x2F936, 'M', u'甾'), + (0x2F937, 'M', u'𤲒'), + (0x2F938, 'M', u'ç•°'), + (0x2F939, 'M', u'𢆟'), + (0x2F93A, 'M', u'ç˜'), + (0x2F93B, 'M', u'𤾡'), + (0x2F93C, 'M', u'𤾸'), + (0x2F93D, 'M', u'ð¥„'), + (0x2F93E, 'M', u'㿼'), + (0x2F93F, 'M', u'䀈'), + (0x2F940, 'M', u'ç›´'), + (0x2F941, 'M', u'𥃳'), + (0x2F942, 'M', u'𥃲'), + (0x2F943, 'M', u'𥄙'), + (0x2F944, 'M', u'𥄳'), + (0x2F945, 'M', u'眞'), + (0x2F946, 'M', u'真'), + (0x2F948, 'M', u'çŠ'), + (0x2F949, 'M', u'䀹'), + (0x2F94A, 'M', u'çž‹'), + (0x2F94B, 'M', u'ä†'), + (0x2F94C, 'M', u'ä‚–'), + (0x2F94D, 'M', u'ð¥'), + (0x2F94E, 'M', u'硎'), + (0x2F94F, 'M', u'碌'), + (0x2F950, 'M', u'磌'), + (0x2F951, 'M', u'䃣'), + (0x2F952, 'M', u'𥘦'), + (0x2F953, 'M', u'祖'), + (0x2F954, 'M', u'𥚚'), + (0x2F955, 'M', u'𥛅'), + (0x2F956, 'M', u'ç¦'), + (0x2F957, 'M', u'ç§«'), + (0x2F958, 'M', u'䄯'), + (0x2F959, 'M', u'ç©€'), + (0x2F95A, 'M', u'穊'), + (0x2F95B, 'M', u'ç©'), + (0x2F95C, 'M', u'𥥼'), + (0x2F95D, 'M', u'𥪧'), + (0x2F95F, 'X'), + (0x2F960, 'M', u'䈂'), + (0x2F961, 'M', u'𥮫'), + (0x2F962, 'M', u'篆'), + (0x2F963, 'M', u'築'), + (0x2F964, 'M', u'䈧'), + (0x2F965, 'M', u'𥲀'), + (0x2F966, 'M', u'ç³’'), + (0x2F967, 'M', u'䊠'), + (0x2F968, 'M', u'糨'), + (0x2F969, 'M', u'ç³£'), + (0x2F96A, 'M', u'ç´€'), + (0x2F96B, 'M', u'𥾆'), + (0x2F96C, 'M', u'çµ£'), + (0x2F96D, 'M', u'äŒ'), + (0x2F96E, 'M', u'ç·‡'), + (0x2F96F, 'M', u'縂'), + (0x2F970, 'M', u'ç¹…'), + (0x2F971, 'M', u'䌴'), + (0x2F972, 'M', u'𦈨'), + (0x2F973, 'M', u'𦉇'), + (0x2F974, 'M', u'ä™'), + (0x2F975, 'M', u'𦋙'), + (0x2F976, 'M', u'罺'), + (0x2F977, 'M', u'𦌾'), + (0x2F978, 'M', u'羕'), + (0x2F979, 'M', u'翺'), + (0x2F97A, 'M', u'者'), + (0x2F97B, 'M', u'𦓚'), + (0x2F97C, 'M', u'𦔣'), + (0x2F97D, 'M', u'è '), + (0x2F97E, 'M', u'𦖨'), + (0x2F97F, 'M', u'è°'), + ] + +def _seg_71(): + return [ + (0x2F980, 'M', u'ð£Ÿ'), + (0x2F981, 'M', u'ä•'), + (0x2F982, 'M', u'育'), + (0x2F983, 'M', u'脃'), + (0x2F984, 'M', u'ä‹'), + (0x2F985, 'M', u'脾'), + (0x2F986, 'M', u'媵'), + (0x2F987, 'M', u'𦞧'), + (0x2F988, 'M', u'𦞵'), + (0x2F989, 'M', u'𣎓'), + (0x2F98A, 'M', u'𣎜'), + (0x2F98B, 'M', u'èˆ'), + (0x2F98C, 'M', u'舄'), + (0x2F98D, 'M', u'辞'), + (0x2F98E, 'M', u'ä‘«'), + (0x2F98F, 'M', u'芑'), + (0x2F990, 'M', u'芋'), + (0x2F991, 'M', u'èŠ'), + (0x2F992, 'M', u'劳'), + (0x2F993, 'M', u'花'), + (0x2F994, 'M', u'芳'), + (0x2F995, 'M', u'芽'), + (0x2F996, 'M', u'苦'), + (0x2F997, 'M', u'𦬼'), + (0x2F998, 'M', u'è‹¥'), + (0x2F999, 'M', u'èŒ'), + (0x2F99A, 'M', u'è£'), + (0x2F99B, 'M', u'莭'), + (0x2F99C, 'M', u'茣'), + (0x2F99D, 'M', u'莽'), + (0x2F99E, 'M', u'è§'), + (0x2F99F, 'M', u'è‘—'), + (0x2F9A0, 'M', u'è“'), + (0x2F9A1, 'M', u'èŠ'), + (0x2F9A2, 'M', u'èŒ'), + (0x2F9A3, 'M', u'èœ'), + (0x2F9A4, 'M', u'𦰶'), + (0x2F9A5, 'M', u'𦵫'), + (0x2F9A6, 'M', u'𦳕'), + (0x2F9A7, 'M', u'䔫'), + (0x2F9A8, 'M', u'蓱'), + (0x2F9A9, 'M', u'蓳'), + (0x2F9AA, 'M', u'è”–'), + (0x2F9AB, 'M', u'ð§Š'), + (0x2F9AC, 'M', u'蕤'), + (0x2F9AD, 'M', u'𦼬'), + (0x2F9AE, 'M', u'ä•'), + (0x2F9AF, 'M', u'ä•¡'), + (0x2F9B0, 'M', u'𦾱'), + (0x2F9B1, 'M', u'𧃒'), + (0x2F9B2, 'M', u'ä•«'), + (0x2F9B3, 'M', u'è™'), + (0x2F9B4, 'M', u'虜'), + (0x2F9B5, 'M', u'è™§'), + (0x2F9B6, 'M', u'虩'), + (0x2F9B7, 'M', u'èš©'), + (0x2F9B8, 'M', u'蚈'), + (0x2F9B9, 'M', u'蜎'), + (0x2F9BA, 'M', u'蛢'), + (0x2F9BB, 'M', u'è¹'), + (0x2F9BC, 'M', u'蜨'), + (0x2F9BD, 'M', u'è«'), + (0x2F9BE, 'M', u'螆'), + (0x2F9BF, 'X'), + (0x2F9C0, 'M', u'蟡'), + (0x2F9C1, 'M', u'è '), + (0x2F9C2, 'M', u'ä—¹'), + (0x2F9C3, 'M', u'è¡ '), + (0x2F9C4, 'M', u'è¡£'), + (0x2F9C5, 'M', u'ð§™§'), + (0x2F9C6, 'M', u'裗'), + (0x2F9C7, 'M', u'裞'), + (0x2F9C8, 'M', u'䘵'), + (0x2F9C9, 'M', u'裺'), + (0x2F9CA, 'M', u'ã’»'), + (0x2F9CB, 'M', u'ð§¢®'), + (0x2F9CC, 'M', u'𧥦'), + (0x2F9CD, 'M', u'äš¾'), + (0x2F9CE, 'M', u'䛇'), + (0x2F9CF, 'M', u'誠'), + (0x2F9D0, 'M', u'è«­'), + (0x2F9D1, 'M', u'變'), + (0x2F9D2, 'M', u'豕'), + (0x2F9D3, 'M', u'𧲨'), + (0x2F9D4, 'M', u'貫'), + (0x2F9D5, 'M', u'è³'), + (0x2F9D6, 'M', u'è´›'), + (0x2F9D7, 'M', u'èµ·'), + (0x2F9D8, 'M', u'𧼯'), + (0x2F9D9, 'M', u'ð  „'), + (0x2F9DA, 'M', u'è·‹'), + (0x2F9DB, 'M', u'è¶¼'), + (0x2F9DC, 'M', u'è·°'), + (0x2F9DD, 'M', u'𠣞'), + (0x2F9DE, 'M', u'è»”'), + (0x2F9DF, 'M', u'輸'), + (0x2F9E0, 'M', u'𨗒'), + (0x2F9E1, 'M', u'𨗭'), + (0x2F9E2, 'M', u'é‚”'), + (0x2F9E3, 'M', u'郱'), + ] + +def _seg_72(): + return [ + (0x2F9E4, 'M', u'é„‘'), + (0x2F9E5, 'M', u'𨜮'), + (0x2F9E6, 'M', u'é„›'), + (0x2F9E7, 'M', u'鈸'), + (0x2F9E8, 'M', u'é‹—'), + (0x2F9E9, 'M', u'鋘'), + (0x2F9EA, 'M', u'鉼'), + (0x2F9EB, 'M', u'é¹'), + (0x2F9EC, 'M', u'é•'), + (0x2F9ED, 'M', u'𨯺'), + (0x2F9EE, 'M', u'é–‹'), + (0x2F9EF, 'M', u'䦕'), + (0x2F9F0, 'M', u'é–·'), + (0x2F9F1, 'M', u'𨵷'), + (0x2F9F2, 'M', u'䧦'), + (0x2F9F3, 'M', u'雃'), + (0x2F9F4, 'M', u'å¶²'), + (0x2F9F5, 'M', u'霣'), + (0x2F9F6, 'M', u'ð©……'), + (0x2F9F7, 'M', u'𩈚'), + (0x2F9F8, 'M', u'ä©®'), + (0x2F9F9, 'M', u'ä©¶'), + (0x2F9FA, 'M', u'韠'), + (0x2F9FB, 'M', u'ð©Š'), + (0x2F9FC, 'M', u'䪲'), + (0x2F9FD, 'M', u'ð©’–'), + (0x2F9FE, 'M', u'é ‹'), + (0x2FA00, 'M', u'é ©'), + (0x2FA01, 'M', u'ð©–¶'), + (0x2FA02, 'M', u'飢'), + (0x2FA03, 'M', u'䬳'), + (0x2FA04, 'M', u'餩'), + (0x2FA05, 'M', u'馧'), + (0x2FA06, 'M', u'é§‚'), + (0x2FA07, 'M', u'é§¾'), + (0x2FA08, 'M', u'䯎'), + (0x2FA09, 'M', u'𩬰'), + (0x2FA0A, 'M', u'鬒'), + (0x2FA0B, 'M', u'é±€'), + (0x2FA0C, 'M', u'é³½'), + (0x2FA0D, 'M', u'䳎'), + (0x2FA0E, 'M', u'ä³­'), + (0x2FA0F, 'M', u'éµ§'), + (0x2FA10, 'M', u'𪃎'), + (0x2FA11, 'M', u'䳸'), + (0x2FA12, 'M', u'𪄅'), + (0x2FA13, 'M', u'𪈎'), + (0x2FA14, 'M', u'𪊑'), + (0x2FA15, 'M', u'麻'), + (0x2FA16, 'M', u'äµ–'), + (0x2FA17, 'M', u'黹'), + (0x2FA18, 'M', u'黾'), + (0x2FA19, 'M', u'é¼…'), + (0x2FA1A, 'M', u'é¼'), + (0x2FA1B, 'M', u'é¼–'), + (0x2FA1C, 'M', u'é¼»'), + (0x2FA1D, 'M', u'𪘀'), + (0x2FA1E, 'X'), + (0xE0100, 'I'), + (0xE01F0, 'X'), + ] + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() +) diff --git a/pipenv/vendor/requests/packages/urllib3/__init__.py b/pipenv/vendor/requests/packages/urllib3/__init__.py new file mode 100644 index 00000000..ac3ff838 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/__init__.py @@ -0,0 +1,97 @@ +""" +urllib3 - Thread-safe connection pooling and re-using. +""" + +from __future__ import absolute_import +import warnings + +from .connectionpool import ( + HTTPConnectionPool, + HTTPSConnectionPool, + connection_from_url +) + +from . import exceptions +from .filepost import encode_multipart_formdata +from .poolmanager import PoolManager, ProxyManager, proxy_from_url +from .response import HTTPResponse +from .util.request import make_headers +from .util.url import get_host +from .util.timeout import Timeout +from .util.retry import Retry + + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' +__license__ = 'MIT' +__version__ = '1.20' + +__all__ = ( + 'HTTPConnectionPool', + 'HTTPSConnectionPool', + 'PoolManager', + 'ProxyManager', + 'HTTPResponse', + 'Retry', + 'Timeout', + 'add_stderr_logger', + 'connection_from_url', + 'disable_warnings', + 'encode_multipart_formdata', + 'get_host', + 'make_headers', + 'proxy_from_url', +) + +logging.getLogger(__name__).addHandler(NullHandler()) + + +def add_stderr_logger(level=logging.DEBUG): + """ + Helper for quickly adding a StreamHandler to the logger. Useful for + debugging. + + Returns the handler after adding it. + """ + # This method needs to be in this __init__.py to get the __name__ correct + # even if urllib3 is vendored within another package. + logger = logging.getLogger(__name__) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) + logger.addHandler(handler) + logger.setLevel(level) + logger.debug('Added a stderr logging handler to logger: %s', __name__) + return handler + + +# ... Clean up. +del NullHandler + + +# All warning filters *must* be appended unless you're really certain that they +# shouldn't be: otherwise, it's very hard for users to use most Python +# mechanisms to silence them. +# SecurityWarning's always go off by default. +warnings.simplefilter('always', exceptions.SecurityWarning, append=True) +# SubjectAltNameWarning's should go off once per host +warnings.simplefilter('default', exceptions.SubjectAltNameWarning, append=True) +# InsecurePlatformWarning's don't vary between requests, so we keep it default. +warnings.simplefilter('default', exceptions.InsecurePlatformWarning, + append=True) +# SNIMissingWarnings should go off only once. +warnings.simplefilter('default', exceptions.SNIMissingWarning, append=True) + + +def disable_warnings(category=exceptions.HTTPWarning): + """ + Helper for quickly disabling all urllib3 warnings. + """ + warnings.simplefilter('ignore', category) diff --git a/pipenv/vendor/requests/packages/urllib3/_collections.py b/pipenv/vendor/requests/packages/urllib3/_collections.py new file mode 100644 index 00000000..77cee017 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/_collections.py @@ -0,0 +1,324 @@ +from __future__ import absolute_import +from collections import Mapping, MutableMapping +try: + from threading import RLock +except ImportError: # Platform-specific: No threads available + class RLock: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +try: # Python 2.7+ + from collections import OrderedDict +except ImportError: + from .packages.ordered_dict import OrderedDict +from .packages.six import iterkeys, itervalues, PY3 + + +__all__ = ['RecentlyUsedContainer', 'HTTPHeaderDict'] + + +_Null = object() + + +class RecentlyUsedContainer(MutableMapping): + """ + Provides a thread-safe dict-like container which maintains up to + ``maxsize`` keys while throwing away the least-recently-used keys beyond + ``maxsize``. + + :param maxsize: + Maximum number of recent elements to retain. + + :param dispose_func: + Every time an item is evicted from the container, + ``dispose_func(value)`` is called. Callback which will get called + """ + + ContainerCls = OrderedDict + + def __init__(self, maxsize=10, dispose_func=None): + self._maxsize = maxsize + self.dispose_func = dispose_func + + self._container = self.ContainerCls() + self.lock = RLock() + + def __getitem__(self, key): + # Re-insert the item, moving it to the end of the eviction line. + with self.lock: + item = self._container.pop(key) + self._container[key] = item + return item + + def __setitem__(self, key, value): + evicted_value = _Null + with self.lock: + # Possibly evict the existing value of 'key' + evicted_value = self._container.get(key, _Null) + self._container[key] = value + + # If we didn't evict an existing value, we might have to evict the + # least recently used item from the beginning of the container. + if len(self._container) > self._maxsize: + _key, evicted_value = self._container.popitem(last=False) + + if self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) + + def __delitem__(self, key): + with self.lock: + value = self._container.pop(key) + + if self.dispose_func: + self.dispose_func(value) + + def __len__(self): + with self.lock: + return len(self._container) + + def __iter__(self): + raise NotImplementedError('Iteration over this class is unlikely to be threadsafe.') + + def clear(self): + with self.lock: + # Copy pointers to all values, then wipe the mapping + values = list(itervalues(self._container)) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self.lock: + return list(iterkeys(self._container)) + + +class HTTPHeaderDict(MutableMapping): + """ + :param headers: + An iterable of field-value pairs. Must not contain multiple field names + when compared case-insensitively. + + :param kwargs: + Additional field-value pairs to pass in to ``dict.update``. + + A ``dict`` like container for storing HTTP Headers. + + Field names are stored and compared case-insensitively in compliance with + RFC 7230. Iteration provides the first case-sensitive key seen for each + case-insensitive pair. + + Using ``__setitem__`` syntax overwrites fields that compare equal + case-insensitively in order to maintain ``dict``'s api. For fields that + compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` + in a loop. + + If multiple fields that are equal case-insensitively are passed to the + constructor or ``.update``, the behavior is undefined and some will be + lost. + + >>> headers = HTTPHeaderDict() + >>> headers.add('Set-Cookie', 'foo=bar') + >>> headers.add('set-cookie', 'baz=quxx') + >>> headers['content-length'] = '7' + >>> headers['SET-cookie'] + 'foo=bar, baz=quxx' + >>> headers['Content-Length'] + '7' + """ + + def __init__(self, headers=None, **kwargs): + super(HTTPHeaderDict, self).__init__() + self._container = OrderedDict() + if headers is not None: + if isinstance(headers, HTTPHeaderDict): + self._copy_from(headers) + else: + self.extend(headers) + if kwargs: + self.extend(kwargs) + + def __setitem__(self, key, val): + self._container[key.lower()] = (key, val) + return self._container[key.lower()] + + def __getitem__(self, key): + val = self._container[key.lower()] + return ', '.join(val[1:]) + + def __delitem__(self, key): + del self._container[key.lower()] + + def __contains__(self, key): + return key.lower() in self._container + + def __eq__(self, other): + if not isinstance(other, Mapping) and not hasattr(other, 'keys'): + return False + if not isinstance(other, type(self)): + other = type(self)(other) + return (dict((k.lower(), v) for k, v in self.itermerged()) == + dict((k.lower(), v) for k, v in other.itermerged())) + + def __ne__(self, other): + return not self.__eq__(other) + + if not PY3: # Python 2 + iterkeys = MutableMapping.iterkeys + itervalues = MutableMapping.itervalues + + __marker = object() + + def __len__(self): + return len(self._container) + + def __iter__(self): + # Only provide the originally cased names + for vals in self._container.values(): + yield vals[0] + + def pop(self, key, default=__marker): + '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + ''' + # Using the MutableMapping function directly fails due to the private marker. + # Using ordinary dict.pop would expose the internal structures. + # So let's reinvent the wheel. + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def discard(self, key): + try: + del self[key] + except KeyError: + pass + + def add(self, key, val): + """Adds a (name, value) pair, doesn't overwrite the value if it already + exists. + + >>> headers = HTTPHeaderDict(foo='bar') + >>> headers.add('Foo', 'baz') + >>> headers['foo'] + 'bar, baz' + """ + key_lower = key.lower() + new_vals = key, val + # Keep the common case aka no item present as fast as possible + vals = self._container.setdefault(key_lower, new_vals) + if new_vals is not vals: + # new_vals was not inserted, as there was a previous one + if isinstance(vals, list): + # If already several items got inserted, we have a list + vals.append(val) + else: + # vals should be a tuple then, i.e. only one item so far + # Need to convert the tuple to list for further extension + self._container[key_lower] = [vals[0], vals[1], val] + + def extend(self, *args, **kwargs): + """Generic import function for any type of header-like object. + Adapted version of MutableMapping.update in order to insert items + with self.add instead of self.__setitem__ + """ + if len(args) > 1: + raise TypeError("extend() takes at most 1 positional " + "arguments ({0} given)".format(len(args))) + other = args[0] if len(args) >= 1 else () + + if isinstance(other, HTTPHeaderDict): + for key, val in other.iteritems(): + self.add(key, val) + elif isinstance(other, Mapping): + for key in other: + self.add(key, other[key]) + elif hasattr(other, "keys"): + for key in other.keys(): + self.add(key, other[key]) + else: + for key, value in other: + self.add(key, value) + + for key, value in kwargs.items(): + self.add(key, value) + + def getlist(self, key): + """Returns a list of all the values for the named field. Returns an + empty list if the key doesn't exist.""" + try: + vals = self._container[key.lower()] + except KeyError: + return [] + else: + if isinstance(vals, tuple): + return [vals[1]] + else: + return vals[1:] + + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist + iget = getlist + + def __repr__(self): + return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) + + def _copy_from(self, other): + for key in other: + val = other.getlist(key) + if isinstance(val, list): + # Don't need to convert tuples + val = list(val) + self._container[key.lower()] = [key] + val + + def copy(self): + clone = type(self)() + clone._copy_from(self) + return clone + + def iteritems(self): + """Iterate over all header lines, including duplicate ones.""" + for key in self: + vals = self._container[key.lower()] + for val in vals[1:]: + yield vals[0], val + + def itermerged(self): + """Iterate over all headers, merging duplicate ones together.""" + for key in self: + val = self._container[key.lower()] + yield val[0], ', '.join(val[1:]) + + def items(self): + return list(self.iteritems()) + + @classmethod + def from_httplib(cls, message): # Python 2 + """Read headers from a Python 2 httplib message object.""" + # python2.7 does not expose a proper API for exporting multiheaders + # efficiently. This function re-reads raw lines from the message + # object and extracts the multiheaders properly. + headers = [] + + for line in message.headers: + if line.startswith((' ', '\t')): + key, value = headers[-1] + headers[-1] = (key, value + '\r\n' + line.rstrip()) + continue + + key, value = line.split(':', 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/pipenv/vendor/requests/packages/urllib3/connection.py b/pipenv/vendor/requests/packages/urllib3/connection.py new file mode 100644 index 00000000..9f06c395 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/connection.py @@ -0,0 +1,369 @@ +from __future__ import absolute_import +import datetime +import logging +import os +import sys +import socket +from socket import error as SocketError, timeout as SocketTimeout +import warnings +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 + +try: # Compiled with SSL? + import ssl + BaseSSLError = ssl.SSLError +except (ImportError, AttributeError): # Platform-specific: No SSL. + ssl = None + + class BaseSSLError(BaseException): + pass + + +try: # Python 3: + # Not a no-op, we're adding this to the namespace so it can be imported. + ConnectionError = ConnectionError +except NameError: # Python 2: + class ConnectionError(Exception): + pass + + +from .exceptions import ( + NewConnectionError, + ConnectTimeoutError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .packages.ssl_match_hostname import match_hostname, CertificateError + +from .util.ssl_ import ( + resolve_cert_reqs, + resolve_ssl_version, + assert_fingerprint, + create_urllib3_context, + ssl_wrap_socket +) + + +from .util import connection + +from ._collections import HTTPHeaderDict + +log = logging.getLogger(__name__) + +port_by_scheme = { + 'http': 80, + 'https': 443, +} + +# When updating RECENT_DATE, move it to +# within two years of the current date, and no +# earlier than 6 months ago. +RECENT_DATE = datetime.date(2016, 1, 1) + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + pass + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on httplib.HTTPConnection but provides an extra constructor + backwards-compatibility layer between older and newer Pythons. + + Additional keyword parameters are used to configure attributes of the connection. + Accepted parameters include: + + - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` + - ``source_address``: Set the source address for the current connection. + + .. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x + + - ``socket_options``: Set specific options on the underlying socket. If not specified, then + defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling + Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. + + For example, if you wish to enable TCP Keep Alive in addition to the defaults, + you might pass:: + + HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), + ] + + Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). + """ + + default_port = port_by_scheme['http'] + + #: Disable Nagle's algorithm by default. + #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` + default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] + + #: Whether this connection verifies the host's certificate. + is_verified = False + + def __init__(self, *args, **kw): + if six.PY3: # Python 3 + kw.pop('strict', None) + + # Pre-set source_address in case we have an older Python like 2.6. + self.source_address = kw.get('source_address') + + if sys.version_info < (2, 7): # Python 2.6 + # _HTTPConnection on Python 2.6 will balk at this keyword arg, but + # not newer versions. We can still use it when creating a + # connection though, so we pop it *after* we have saved it as + # self.source_address. + kw.pop('source_address', None) + + #: The socket options provided by the user. If no options are + #: provided, we use the default options. + self.socket_options = kw.pop('socket_options', self.default_socket_options) + + # Superclass also sets self.source_address in Python 2.7+. + _HTTPConnection.__init__(self, *args, **kw) + + def _new_conn(self): + """ Establish a socket connection and set nodelay settings on it. + + :return: New socket connection. + """ + extra_kw = {} + if self.source_address: + extra_kw['source_address'] = self.source_address + + if self.socket_options: + extra_kw['socket_options'] = self.socket_options + + try: + conn = connection.create_connection( + (self.host, self.port), self.timeout, **extra_kw) + + except SocketTimeout as e: + raise ConnectTimeoutError( + self, "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout)) + + except SocketError as e: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e) + + return conn + + def _prepare_conn(self, conn): + self.sock = conn + # the _tunnel_host attribute was added in python 2.6.3 (via + # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do + # not have them. + if getattr(self, '_tunnel_host', None): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + def request_chunked(self, method, url, body=None, headers=None): + """ + Alternative to the common request method, which sends the + body with chunked encoding and not as one block + """ + headers = HTTPHeaderDict(headers if headers is not None else {}) + skip_accept_encoding = 'accept-encoding' in headers + skip_host = 'host' in headers + self.putrequest( + method, + url, + skip_accept_encoding=skip_accept_encoding, + skip_host=skip_host + ) + for header, value in headers.items(): + self.putheader(header, value) + if 'transfer-encoding' not in headers: + self.putheader('Transfer-Encoding', 'chunked') + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (six.binary_type,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, six.binary_type): + chunk = chunk.encode('utf8') + len_str = hex(len(chunk))[2:] + self.send(len_str.encode('utf-8')) + self.send(b'\r\n') + self.send(chunk) + self.send(b'\r\n') + + # After the if clause, to always have a closed body + self.send(b'0\r\n\r\n') + + +class HTTPSConnection(HTTPConnection): + default_port = port_by_scheme['https'] + + ssl_version = None + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, **kw): + + HTTPConnection.__init__(self, host, port, strict=strict, + timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.ssl_context = ssl_context + + # Required property for Google AppEngine 1.9.0 which otherwise causes + # HTTPS requests to go out as HTTP. (See Issue #356) + self._protocol = 'https' + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(None), + cert_reqs=resolve_cert_reqs(None), + ) + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ssl_context=self.ssl_context, + ) + + +class VerifiedHTTPSConnection(HTTPSConnection): + """ + Based on httplib.HTTPSConnection but wraps the socket with + SSL certification. + """ + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ssl_version = None + assert_fingerprint = None + + def set_cert(self, key_file=None, cert_file=None, + cert_reqs=None, ca_certs=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided, we can try to guess. If the user gave + # us a cert database, we assume they want to use it: otherwise, if + # they gave us an SSL Context object we should use whatever is set for + # it. + if cert_reqs is None: + if ca_certs or ca_cert_dir: + cert_reqs = 'CERT_REQUIRED' + elif self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + self.ca_certs = ca_certs and os.path.expanduser(ca_certs) + self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) + + def connect(self): + # Add certificate verification + conn = self._new_conn() + + hostname = self.host + if getattr(self, '_tunnel_host', None): + # _tunnel_host was added in Python 2.6.3 + # (See: http://hg.python.org/cpython/rev/0f57b30a152f) + + self.sock = conn + # Calls self._set_hostport(), so self.host is + # self._tunnel_host below. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + # Override the host with the one we're requesting data from. + hostname = self._tunnel_host + + is_time_off = datetime.date.today() < RECENT_DATE + if is_time_off: + warnings.warn(( + 'System time is way off (before {0}). This will probably ' + 'lead to SSL verification errors').format(RECENT_DATE), + SystemTimeWarning + ) + + # Wrap socket using verification with the root certs in + # trusted_root_certs + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(self.ssl_version), + cert_reqs=resolve_cert_reqs(self.cert_reqs), + ) + + context = self.ssl_context + context.verify_mode = resolve_cert_reqs(self.cert_reqs) + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + server_hostname=hostname, + ssl_context=context) + + if self.assert_fingerprint: + assert_fingerprint(self.sock.getpeercert(binary_form=True), + self.assert_fingerprint) + elif context.verify_mode != ssl.CERT_NONE \ + and self.assert_hostname is not False: + cert = self.sock.getpeercert() + if not cert.get('subjectAltName', ()): + warnings.warn(( + 'Certificate for {0} has no `subjectAltName`, falling back to check for a ' + '`commonName` for now. This feature is being removed by major browsers and ' + 'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 ' + 'for details.)'.format(hostname)), + SubjectAltNameWarning + ) + _match_hostname(cert, self.assert_hostname or hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED or + self.assert_fingerprint is not None + ) + + +def _match_hostname(cert, asserted_hostname): + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.error( + 'Certificate did not match expected hostname: %s. ' + 'Certificate: %s', asserted_hostname, cert + ) + # Add cert to exception and reraise so client code can inspect + # the cert when catching the exception, if they want to + e._peer_cert = cert + raise + + +if ssl: + # Make a copy for testing. + UnverifiedHTTPSConnection = HTTPSConnection + HTTPSConnection = VerifiedHTTPSConnection +else: + HTTPSConnection = DummyConnection diff --git a/pipenv/vendor/requests/packages/urllib3/connectionpool.py b/pipenv/vendor/requests/packages/urllib3/connectionpool.py new file mode 100644 index 00000000..b4f1166a --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/connectionpool.py @@ -0,0 +1,899 @@ +from __future__ import absolute_import +import errno +import logging +import sys +import warnings + +from socket import error as SocketError, timeout as SocketTimeout +import socket + + +from .exceptions import ( + ClosedPoolError, + ProtocolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + LocationValueError, + MaxRetryError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, + InsecureRequestWarning, + NewConnectionError, +) +from .packages.ssl_match_hostname import CertificateError +from .packages import six +from .packages.six.moves import queue +from .connection import ( + port_by_scheme, + DummyConnection, + HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, + HTTPException, BaseSSLError, +) +from .request import RequestMethods +from .response import HTTPResponse + +from .util.connection import is_connection_dropped +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host, Url + + +if six.PY2: + # Queue is imported for side effects on MS Windows + import Queue as _unused_module_Queue # noqa: F401 + +xrange = six.moves.xrange + +log = logging.getLogger(__name__) + +_Default = object() + + +# Pool objects +class ConnectionPool(object): + """ + Base class for all connection pools, such as + :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. + """ + + scheme = None + QueueCls = queue.LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _ipv6_host(host).lower() + self.port = port + + def __str__(self): + return '%s(host=%r, port=%r)' % (type(self).__name__, + self.host, self.port) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + # Return False to re-raise any potential exceptions + return False + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + pass + + +# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 +_blocking_errnos = set([errno.EAGAIN, errno.EWOULDBLOCK]) + + +class HTTPConnectionPool(ConnectionPool, RequestMethods): + """ + Thread-safe connection pool for one host. + + :param host: + Host used for this HTTP Connection (e.g. "localhost"), passed into + :class:`httplib.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`httplib.HTTPConnection`. + + :param strict: + Causes BadStatusLine to be raised if the status line can't be parsed + as a valid HTTP/1.0 or 1.1 status line, passed into + :class:`httplib.HTTPConnection`. + + .. note:: + Only works in Python 2. This parameter is ignored in Python 3. + + :param timeout: + Socket timeout in seconds for each individual connection. This can + be a float or integer, which sets the timeout for the HTTP request, + or an instance of :class:`urllib3.util.Timeout` which gives you more + fine-grained control over request timeouts. After the constructor has + been parsed, this is always a `urllib3.util.Timeout` object. + + :param maxsize: + Number of connections to save that can be reused. More than 1 is useful + in multithreaded situations. If ``block`` is set to False, more + connections will be created but they will not be saved once they've + been used. + + :param block: + If set to True, no more than ``maxsize`` connections will be used at + a time. When no free connections are available, the call will block + until a connection has been released. This is a useful side effect for + particular multithreaded situations where one does not want to use more + than maxsize connections per host to prevent flooding. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param retries: + Retry configuration to use by default with requests in this pool. + + :param _proxy: + Parsed proxy URL, should not be used directly, instead, see + :class:`urllib3.connectionpool.ProxyManager`" + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.connectionpool.ProxyManager`" + + :param \\**conn_kw: + Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, + :class:`urllib3.connection.HTTPSConnection` instances. + """ + + scheme = 'http' + ConnectionCls = HTTPConnection + ResponseCls = HTTPResponse + + def __init__(self, host, port=None, strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False, + headers=None, retries=None, + _proxy=None, _proxy_headers=None, + **conn_kw): + ConnectionPool.__init__(self, host, port) + RequestMethods.__init__(self, headers) + + self.strict = strict + + if not isinstance(timeout, Timeout): + timeout = Timeout.from_float(timeout) + + if retries is None: + retries = Retry.DEFAULT + + self.timeout = timeout + self.retries = retries + + self.pool = self.QueueCls(maxsize) + self.block = block + + self.proxy = _proxy + self.proxy_headers = _proxy_headers or {} + + # Fill the queue up so that doing get() on it will block properly + for _ in xrange(maxsize): + self.pool.put(None) + + # These are mostly for testing and debugging purposes. + self.num_connections = 0 + self.num_requests = 0 + self.conn_kw = conn_kw + + if self.proxy: + # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. + # We cannot know if the user has added default socket options, so we cannot replace the + # list. + self.conn_kw.setdefault('socket_options', []) + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTP connection (%d): %s", + self.num_connections, self.host) + + conn = self.ConnectionCls(host=self.host, port=self.port, + timeout=self.timeout.connect_timeout, + strict=self.strict, **self.conn_kw) + return conn + + def _get_conn(self, timeout=None): + """ + Get a connection. Will return a pooled connection if one is available. + + If no connections are available and :prop:`.block` is ``False``, then a + fresh connection is returned. + + :param timeout: + Seconds to wait before giving up and raising + :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and + :prop:`.block` is ``True``. + """ + conn = None + try: + conn = self.pool.get(block=self.block, timeout=timeout) + + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") + + except queue.Empty: + if self.block: + raise EmptyPoolError(self, + "Pool reached maximum size and no more " + "connections are allowed.") + pass # Oh well, we'll create a new connection then + + # If this is a persistent connection, check if it got disconnected + if conn and is_connection_dropped(conn): + log.debug("Resetting dropped connection: %s", self.host) + conn.close() + if getattr(conn, 'auto_open', 1) == 0: + # This is a proxied connection that has been mutated by + # httplib._tunnel() and cannot be reused (since it would + # attempt to bypass the proxy) + conn = None + + return conn or self._new_conn() + + def _put_conn(self, conn): + """ + Put a connection back into the pool. + + :param conn: + Connection object for the current host and port as returned by + :meth:`._new_conn` or :meth:`._get_conn`. + + If the pool is already full, the connection is closed and discarded + because we exceeded maxsize. If connections are discarded frequently, + then maxsize should be increased. + + If the pool is closed, then the connection will be closed and discarded. + """ + try: + self.pool.put(conn, block=False) + return # Everything is dandy, done. + except AttributeError: + # self.pool is None. + pass + except queue.Full: + # This should never happen if self.block == True + log.warning( + "Connection pool is full, discarding connection: %s", + self.host) + + # Connection never got put back into the pool, close it. + if conn: + conn.close() + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + pass + + def _prepare_proxy(self, conn): + # Nothing to do for HTTP connections. + pass + + def _get_timeout(self, timeout): + """ Helper that always returns a :class:`urllib3.util.Timeout` """ + if timeout is _Default: + return self.timeout.clone() + + if isinstance(timeout, Timeout): + return timeout.clone() + else: + # User passed us an int/float. This is for backwards compatibility, + # can be removed later + return Timeout.from_float(timeout) + + def _raise_timeout(self, err, url, timeout_value): + """Is the error actually a timeout? Will raise a ReadTimeout or pass""" + + if isinstance(err, SocketTimeout): + raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value) + + # See the above comment about EAGAIN in Python 3. In Python 2 we have + # to specifically catch it and throw the timeout error + if hasattr(err, 'errno') and err.errno in _blocking_errnos: + raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value) + + # Catch possible read timeouts thrown as SSL errors. If not the + # case, rethrow the original. We need to do this because of: + # http://bugs.python.org/issue10272 + if 'timed out' in str(err) or 'did not complete (read)' in str(err): # Python 2.6 + raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value) + + def _make_request(self, conn, method, url, timeout=_Default, chunked=False, + **httplib_request_kw): + """ + Perform a request on a given urllib connection object taken from our + pool. + + :param conn: + a connection from one of our connection pools + + :param timeout: + Socket timeout in seconds for the request. This can be a + float or integer, which will set the same timeout value for + the socket connect and the socket read, or an instance of + :class:`urllib3.util.Timeout`, which gives you more fine-grained + control over your timeouts. + """ + self.num_requests += 1 + + timeout_obj = self._get_timeout(timeout) + timeout_obj.start_connect() + conn.timeout = timeout_obj.connect_timeout + + # Trigger any extra validation we need to do. + try: + self._validate_conn(conn) + except (SocketTimeout, BaseSSLError) as e: + # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. + self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) + raise + + # conn.request() calls httplib.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # Reset the timeout for the recv() on the socket + read_timeout = timeout_obj.read_timeout + + # App Engine doesn't have a sock attr + if getattr(conn, 'sock', None): + # In Python 3 socket.py will catch EAGAIN and return None when you + # try and read into the file pointer created by http.client, which + # instead raises a BadStatusLine exception. Instead of catching + # the exception and assuming all BadStatusLine exceptions are read + # timeouts, check for a zero timeout before making the request. + if read_timeout == 0: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % read_timeout) + if read_timeout is Timeout.DEFAULT_TIMEOUT: + conn.sock.settimeout(socket.getdefaulttimeout()) + else: # None or a value + conn.sock.settimeout(read_timeout) + + # Receive the response from the server + try: + try: # Python 2.7, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: # Python 2.6 and older, Python 3 + try: + httplib_response = conn.getresponse() + except Exception as e: + # Remove the TypeError from the exception chain in Python 3; + # otherwise it looks like a programming error was the cause. + six.raise_from(e, None) + except (SocketTimeout, BaseSSLError, SocketError) as e: + self._raise_timeout(err=e, url=url, timeout_value=read_timeout) + raise + + # AppEngine doesn't have a version attr. + http_version = getattr(conn, '_http_vsn_str', 'HTTP/?') + log.debug("%s://%s:%s \"%s %s %s\" %s %s", self.scheme, self.host, self.port, + method, url, http_version, httplib_response.status, + httplib_response.length) + + try: + assert_header_parsing(httplib_response.msg) + except HeaderParsingError as hpe: # Platform-specific: Python 3 + log.warning( + 'Failed to parse headers (url=%s): %s', + self._absolute_url(url), hpe, exc_info=True) + + return httplib_response + + def _absolute_url(self, path): + return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + # Disable access to the pool + old_pool, self.pool = self.pool, None + + try: + while True: + conn = old_pool.get(block=False) + if conn: + conn.close() + + except queue.Empty: + pass # Done. + + def is_same_host(self, url): + """ + Check if the given ``url`` is a member of the same host as this + connection pool. + """ + if url.startswith('/'): + return True + + # TODO: Add optional support for socket.gethostbyname checking. + scheme, host, port = get_host(url) + + host = _ipv6_host(host).lower() + + # Use explicit default port for comparison when none is given + if self.port and not port: + port = port_by_scheme.get(scheme) + elif not self.port and port == port_by_scheme.get(scheme): + port = None + + return (scheme, host, port) == (self.scheme, self.host, self.port) + + def urlopen(self, method, url, body=None, headers=None, retries=None, + redirect=True, assert_same_host=True, timeout=_Default, + pool_timeout=None, release_conn=None, chunked=False, + body_pos=None, **response_kw): + """ + Get a connection from the pool and perform an HTTP request. This is the + lowest level call for making a request, so you'll need to specify all + the raw details. + + .. note:: + + More commonly, it's appropriate to use a convenience method provided + by :class:`.RequestMethods`, such as :meth:`request`. + + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + + :param body: + Data to send in the request body (useful for creating + POST requests, see HTTPConnectionPool.post_url for + more convenience). + + :param headers: + Dictionary of custom headers to send, such as User-Agent, + If-None-Match, etc. If None, pool headers are used. If provided, + these headers completely replace any pool-specific headers. + + :param retries: + Configure the number of retries to allow before raising a + :class:`~urllib3.exceptions.MaxRetryError` exception. + + Pass ``None`` to retry until you receive a response. Pass a + :class:`~urllib3.util.retry.Retry` object for fine-grained control + over different types of retries. + Pass an integer number to retry connection errors that many times, + but no other types of errors. Pass zero to never retry. + + If ``False``, then retries are disabled and any exception is raised + immediately. Also, instead of raising a MaxRetryError on redirects, + the redirect response will be returned. + + :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. + + :param redirect: + If True, automatically handle redirects (status codes 301, 302, + 303, 307, 308). Each redirect counts as a retry. Disabling retries + will disable redirect, too. + + :param assert_same_host: + If ``True``, will make sure that the host of the pool requests is + consistent else will raise HostChangedError. When False, you can + use the pool on an HTTP proxy and request foreign hosts. + + :param timeout: + If specified, overrides the default timeout for this one + request. It may be a float (in seconds) or an instance of + :class:`urllib3.util.Timeout`. + + :param pool_timeout: + If set and the pool is set to block=True, then this method will + block for ``pool_timeout`` seconds and raise EmptyPoolError if no + connection is available within the time period. + + :param release_conn: + If False, then the urlopen call will not release the connection + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of + ``response_kw.get('preload_content', True)``. + + :param chunked: + If True, urllib3 will send the body using chunked transfer + encoding. Otherwise, urllib3 will send the body using the standard + content-length form. Defaults to False. + + :param int body_pos: + Position to seek to in file-like body in the event of a retry or + redirect. Typically this won't need to be set because urllib3 will + auto-populate the value when needed. + + :param \\**response_kw: + Additional parameters are passed to + :meth:`urllib3.response.HTTPResponse.from_httplib` + """ + if headers is None: + headers = self.headers + + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if release_conn is None: + release_conn = response_kw.get('preload_content', True) + + # Check host + if assert_same_host and not self.is_same_host(url): + raise HostChangedError(self, url, retries) + + conn = None + + # Track whether `conn` needs to be released before + # returning/raising/recursing. Update this variable if necessary, and + # leave `release_conn` constant throughout the function. That way, if + # the function recurses, the original value of `release_conn` will be + # passed down into the recursive call, and its value will be respected. + # + # See issue #651 [1] for details. + # + # [1] + release_this_conn = release_conn + + # Merge the proxy headers. Only do this in HTTP. We have to copy the + # headers dict so we can safely change it without those changes being + # reflected in anyone else's copy. + if self.scheme == 'http': + headers = headers.copy() + headers.update(self.proxy_headers) + + # Must keep the exception bound to a separate variable or else Python 3 + # complains about UnboundLocalError. + err = None + + # Keep track of whether we cleanly exited the except block. This + # ensures we do proper cleanup in finally. + clean_exit = False + + # Rewind body position, if needed. Record current position + # for future rewinds in the event of a redirect/retry. + body_pos = set_file_position(body, body_pos) + + try: + # Request a connection from the queue. + timeout_obj = self._get_timeout(timeout) + conn = self._get_conn(timeout=pool_timeout) + + conn.timeout = timeout_obj.connect_timeout + + is_new_proxy_conn = self.proxy is not None and not getattr(conn, 'sock', None) + if is_new_proxy_conn: + self._prepare_proxy(conn) + + # Make the request on the httplib connection object. + httplib_response = self._make_request(conn, method, url, + timeout=timeout_obj, + body=body, headers=headers, + chunked=chunked) + + # If we're going to release the connection in ``finally:``, then + # the response doesn't need to know about the connection. Otherwise + # it will also try to release it and we'll have a double-release + # mess. + response_conn = conn if not release_conn else None + + # Pass method to Response for length checking + response_kw['request_method'] = method + + # Import httplib's response into our own wrapper object + response = self.ResponseCls.from_httplib(httplib_response, + pool=self, + connection=response_conn, + retries=retries, + **response_kw) + + # Everything went great! + clean_exit = True + + except queue.Empty: + # Timed out by queue. + raise EmptyPoolError(self, "No pool connections are available.") + + except (BaseSSLError, CertificateError) as e: + # Close the connection. If a connection is reused on which there + # was a Certificate error, the next request will certainly raise + # another Certificate error. + clean_exit = False + raise SSLError(e) + + except SSLError: + # Treat SSLError separately from BaseSSLError to preserve + # traceback. + clean_exit = False + raise + + except (TimeoutError, HTTPException, SocketError, ProtocolError) as e: + # Discard the connection for these exceptions. It will be + # be replaced during the next _get_conn() call. + clean_exit = False + + if isinstance(e, (SocketError, NewConnectionError)) and self.proxy: + e = ProxyError('Cannot connect to proxy.', e) + elif isinstance(e, (SocketError, HTTPException)): + e = ProtocolError('Connection aborted.', e) + + retries = retries.increment(method, url, error=e, _pool=self, + _stacktrace=sys.exc_info()[2]) + retries.sleep() + + # Keep track of the error for the retry warning. + err = e + + finally: + if not clean_exit: + # We hit some kind of exception, handled or otherwise. We need + # to throw the connection away unless explicitly told not to. + # Close the connection, set the variable to None, and make sure + # we put the None back in the pool to avoid leaking it. + conn = conn and conn.close() + release_this_conn = True + + if release_this_conn: + # Put the connection back to be reused. If the connection is + # expired then it will be None, which will get replaced with a + # fresh connection during _get_conn. + self._put_conn(conn) + + if not conn: + # Try again + log.warning("Retrying (%r) after connection " + "broken by '%r': %s", retries, err, url) + return self.urlopen(method, url, body, headers, retries, + redirect, assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, body_pos=body_pos, + **response_kw) + + # Handle redirect? + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: + method = 'GET' + + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + # Release the connection for this response, since we're not + # returning it to be released manually. + response.release_conn() + raise + return response + + retries.sleep_for_retry(response) + log.debug("Redirecting %s -> %s", url, redirect_location) + return self.urlopen( + method, redirect_location, body, headers, + retries=retries, redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, body_pos=body_pos, + **response_kw) + + # Check if we should retry the HTTP response. + has_retry_after = bool(response.getheader('Retry-After')) + if retries.is_retry(method, response.status, has_retry_after): + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_status: + # Release the connection for this response, since we're not + # returning it to be released manually. + response.release_conn() + raise + return response + retries.sleep(response) + log.debug("Retry: %s", url) + return self.urlopen( + method, url, body, headers, + retries=retries, redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, + body_pos=body_pos, **response_kw) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + When Python is compiled with the :mod:`ssl` module, then + :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, + instead of :class:`.HTTPSConnection`. + + :class:`.VerifiedHTTPSConnection` uses one of ``assert_fingerprint``, + ``assert_hostname`` and ``host`` in this order to verify connections. + If ``assert_hostname`` is False, no verification is done. + + The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, + ``ca_cert_dir``, and ``ssl_version`` are only used if :mod:`ssl` is + available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade + the connection socket into an SSL socket. + """ + + scheme = 'https' + ConnectionCls = HTTPSConnection + + def __init__(self, host, port=None, + strict=False, timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, + block=False, headers=None, retries=None, + _proxy=None, _proxy_headers=None, + key_file=None, cert_file=None, cert_reqs=None, + ca_certs=None, ssl_version=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None, **conn_kw): + + HTTPConnectionPool.__init__(self, host, port, strict, timeout, maxsize, + block, headers, retries, _proxy, _proxy_headers, + **conn_kw) + + if ca_certs and cert_reqs is None: + cert_reqs = 'CERT_REQUIRED' + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.ca_certs = ca_certs + self.ca_cert_dir = ca_cert_dir + self.ssl_version = ssl_version + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + + def _prepare_conn(self, conn): + """ + Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` + and establish the tunnel if proxy is used. + """ + + if isinstance(conn, VerifiedHTTPSConnection): + conn.set_cert(key_file=self.key_file, + cert_file=self.cert_file, + cert_reqs=self.cert_reqs, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + assert_hostname=self.assert_hostname, + assert_fingerprint=self.assert_fingerprint) + conn.ssl_version = self.ssl_version + return conn + + def _prepare_proxy(self, conn): + """ + Establish tunnel connection early, because otherwise httplib + would improperly set Host: header to proxy's IP:port. + """ + # Python 2.7+ + try: + set_tunnel = conn.set_tunnel + except AttributeError: # Platform-specific: Python 2.6 + set_tunnel = conn._set_tunnel + + if sys.version_info <= (2, 6, 4) and not self.proxy_headers: # Python 2.6.4 and older + set_tunnel(self.host, self.port) + else: + set_tunnel(self.host, self.port, self.proxy_headers) + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTPS connection (%d): %s", + self.num_connections, self.host) + + if not self.ConnectionCls or self.ConnectionCls is DummyConnection: + raise SSLError("Can't connect to HTTPS URL because the SSL " + "module is not available.") + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + conn = self.ConnectionCls(host=actual_host, port=actual_port, + timeout=self.timeout.connect_timeout, + strict=self.strict, **self.conn_kw) + + return self._prepare_conn(conn) + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + super(HTTPSConnectionPool, self)._validate_conn(conn) + + # Force connect early to allow us to validate the connection. + if not getattr(conn, 'sock', None): # AppEngine might not have `.sock` + conn.connect() + + if not conn.is_verified: + warnings.warn(( + 'Unverified HTTPS request is being made. ' + 'Adding certificate verification is strongly advised. See: ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings'), + InsecureRequestWarning) + + +def connection_from_url(url, **kw): + """ + Given a url, return an :class:`.ConnectionPool` instance of its host. + + This is a shortcut for not having to parse out the scheme, host, and port + of the url before creating an :class:`.ConnectionPool` instance. + + :param url: + Absolute URL string that must include the scheme. Port is optional. + + :param \\**kw: + Passes additional parameters to the constructor of the appropriate + :class:`.ConnectionPool`. Useful for specifying things like + timeout, maxsize, headers, etc. + + Example:: + + >>> conn = connection_from_url('http://google.com/') + >>> r = conn.request('GET', '/') + """ + scheme, host, port = get_host(url) + port = port or port_by_scheme.get(scheme, 80) + if scheme == 'https': + return HTTPSConnectionPool(host, port=port, **kw) + else: + return HTTPConnectionPool(host, port=port, **kw) + + +def _ipv6_host(host): + """ + Process IPv6 address literals + """ + + # httplib doesn't like it when we include brackets in IPv6 addresses + # Specifically, if we include brackets but also pass the port then + # httplib crazily doubles up the square brackets on the Host header. + # Instead, we need to make sure we never pass ``None`` as the port. + # However, for backward compatibility reasons we can't actually + # *assert* that. See http://bugs.python.org/issue28539 + # + # Also if an IPv6 address literal has a zone identifier, the + # percent sign might be URIencoded, convert it back into ASCII + if host.startswith('[') and host.endswith(']'): + host = host.replace('%25', '%').strip('[]') + return host diff --git a/pipenv/vendor/requests/packages/urllib3/contrib/__init__.py b/pipenv/vendor/requests/packages/urllib3/contrib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pipenv/vendor/requests/packages/urllib3/contrib/appengine.py b/pipenv/vendor/requests/packages/urllib3/contrib/appengine.py new file mode 100644 index 00000000..814b0222 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/contrib/appengine.py @@ -0,0 +1,296 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service `_. + +Example usage:: + + from urllib3 import PoolManager + from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox + + if is_appengine_sandbox(): + # AppEngineManager uses AppEngine's URLFetch API behind the scenes + http = AppEngineManager() + else: + # PoolManager uses a socket-level API behind the scenes + http = PoolManager() + + r = http.request('GET', 'https://google.com/') + +There are `limitations `_ to the URLFetch service and it may not be +the best choice for your application. There are three options for using +urllib3 on Google App Engine: + +1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is + cost-effective in many circumstances as long as your usage is within the + limitations. +2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. + Sockets also have `limitations and restrictions + `_ and have a lower free quota than URLFetch. + To use sockets, be sure to specify the following in your ``app.yaml``:: + + env_variables: + GAE_USE_SOCKETS_HTTPLIB : 'true' + +3. If you are using `App Engine Flexible +`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import +import logging +import os +import warnings +from ..packages.six.moves.urllib.parse import urljoin + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + TimeoutError, + SSLError +) + +from ..packages.six import BytesIO +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.timeout import Timeout +from ..util.retry import Retry + +try: + from google.appengine.api import urlfetch +except ImportError: + urlfetch = None + + +log = logging.getLogger(__name__) + + +class AppEnginePlatformWarning(HTTPWarning): + pass + + +class AppEnginePlatformError(HTTPError): + pass + + +class AppEngineManager(RequestMethods): + """ + Connection manager for Google App Engine sandbox applications. + + This manager uses the URLFetch service directly instead of using the + emulated httplib, and is subject to URLFetch limitations as described in + the App Engine documentation `here + `_. + + Notably it will raise an :class:`AppEnginePlatformError` if: + * URLFetch is not available. + * If you attempt to use this on App Engine Flexible, as full socket + support is available. + * If a request size is more than 10 megabytes. + * If a response size is more than 32 megabtyes. + * If you use an unsupported request method such as OPTIONS. + + Beyond those cases, it will raise normal urllib3 errors. + """ + + def __init__(self, headers=None, retries=None, validate_certificate=True, + urlfetch_retries=True): + if not urlfetch: + raise AppEnginePlatformError( + "URLFetch is not available in this environment.") + + if is_prod_appengine_mvms(): + raise AppEnginePlatformError( + "Use normal urllib3.PoolManager instead of AppEngineManager" + "on Managed VMs, as using URLFetch is not necessary in " + "this environment.") + + warnings.warn( + "urllib3 is using URLFetch on Google App Engine sandbox instead " + "of sockets. To use sockets directly instead of URLFetch see " + "https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.", + AppEnginePlatformWarning) + + RequestMethods.__init__(self, headers) + self.validate_certificate = validate_certificate + self.urlfetch_retries = urlfetch_retries + + self.retries = retries or Retry.DEFAULT + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Return False to re-raise any potential exceptions + return False + + def urlopen(self, method, url, body=None, headers=None, + retries=None, redirect=True, timeout=Timeout.DEFAULT_TIMEOUT, + **response_kw): + + retries = self._get_retries(retries, redirect) + + try: + follow_redirects = ( + redirect and + retries.redirect != 0 and + retries.total) + response = urlfetch.fetch( + url, + payload=body, + method=method, + headers=headers or {}, + allow_truncated=False, + follow_redirects=self.urlfetch_retries and follow_redirects, + deadline=self._get_absolute_timeout(timeout), + validate_certificate=self.validate_certificate, + ) + except urlfetch.DeadlineExceededError as e: + raise TimeoutError(self, e) + + except urlfetch.InvalidURLError as e: + if 'too large' in str(e): + raise AppEnginePlatformError( + "URLFetch request too large, URLFetch only " + "supports requests up to 10mb in size.", e) + raise ProtocolError(e) + + except urlfetch.DownloadError as e: + if 'Too many redirects' in str(e): + raise MaxRetryError(self, url, reason=e) + raise ProtocolError(e) + + except urlfetch.ResponseTooLargeError as e: + raise AppEnginePlatformError( + "URLFetch response too large, URLFetch only supports" + "responses up to 32mb in size.", e) + + except urlfetch.SSLCertificateError as e: + raise SSLError(e) + + except urlfetch.InvalidMethodError as e: + raise AppEnginePlatformError( + "URLFetch does not support method: %s" % method, e) + + http_response = self._urlfetch_response_to_http_response( + response, retries=retries, **response_kw) + + # Handle redirect? + redirect_location = redirect and http_response.get_redirect_location() + if redirect_location: + # Check for redirect response + if (self.urlfetch_retries and retries.raise_on_redirect): + raise MaxRetryError(self, url, "too many redirects") + else: + if http_response.status == 303: + method = 'GET' + + try: + retries = retries.increment(method, url, response=http_response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + return http_response + + retries.sleep_for_retry(http_response) + log.debug("Redirecting %s -> %s", url, redirect_location) + redirect_url = urljoin(url, redirect_location) + return self.urlopen( + method, redirect_url, body, headers, + retries=retries, redirect=redirect, + timeout=timeout, **response_kw) + + # Check if we should retry the HTTP response. + has_retry_after = bool(http_response.getheader('Retry-After')) + if retries.is_retry(method, http_response.status, has_retry_after): + retries = retries.increment( + method, url, response=http_response, _pool=self) + log.debug("Retry: %s", url) + retries.sleep(http_response) + return self.urlopen( + method, url, + body=body, headers=headers, + retries=retries, redirect=redirect, + timeout=timeout, **response_kw) + + return http_response + + def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): + + if is_prod_appengine(): + # Production GAE handles deflate encoding automatically, but does + # not remove the encoding header. + content_encoding = urlfetch_resp.headers.get('content-encoding') + + if content_encoding == 'deflate': + del urlfetch_resp.headers['content-encoding'] + + transfer_encoding = urlfetch_resp.headers.get('transfer-encoding') + # We have a full response's content, + # so let's make sure we don't report ourselves as chunked data. + if transfer_encoding == 'chunked': + encodings = transfer_encoding.split(",") + encodings.remove('chunked') + urlfetch_resp.headers['transfer-encoding'] = ','.join(encodings) + + return HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **response_kw + ) + + def _get_absolute_timeout(self, timeout): + if timeout is Timeout.DEFAULT_TIMEOUT: + return None # Defer to URLFetch's default. + if isinstance(timeout, Timeout): + if timeout._read is not None or timeout._connect is not None: + warnings.warn( + "URLFetch does not support granular timeout settings, " + "reverting to total or default URLFetch timeout.", + AppEnginePlatformWarning) + return timeout.total + return timeout + + def _get_retries(self, retries, redirect): + if not isinstance(retries, Retry): + retries = Retry.from_int( + retries, redirect=redirect, default=self.retries) + + if retries.connect or retries.read or retries.redirect: + warnings.warn( + "URLFetch only supports total retries and does not " + "recognize connect, read, or redirect retry parameters.", + AppEnginePlatformWarning) + + return retries + + +def is_appengine(): + return (is_local_appengine() or + is_prod_appengine() or + is_prod_appengine_mvms()) + + +def is_appengine_sandbox(): + return is_appengine() and not is_prod_appengine_mvms() + + +def is_local_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Development/' in os.environ['SERVER_SOFTWARE']) + + +def is_prod_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and + not is_prod_appengine_mvms()) + + +def is_prod_appengine_mvms(): + return os.environ.get('GAE_VM', False) == 'true' diff --git a/pipenv/vendor/requests/packages/urllib3/contrib/ntlmpool.py b/pipenv/vendor/requests/packages/urllib3/contrib/ntlmpool.py new file mode 100644 index 00000000..642e99ed --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/contrib/ntlmpool.py @@ -0,0 +1,112 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +from logging import getLogger +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + + +log = getLogger(__name__) + + +class NTLMConnectionPool(HTTPSConnectionPool): + """ + Implements an NTLM authentication version of an urllib3 connection pool + """ + + scheme = 'https' + + def __init__(self, user, pw, authurl, *args, **kwargs): + """ + authurl is a random URL on the server that is protected by NTLM. + user is the Windows user, probably in the DOMAIN\\username format. + pw is the password for the user. + """ + super(NTLMConnectionPool, self).__init__(*args, **kwargs) + self.authurl = authurl + self.rawuser = user + user_parts = user.split('\\', 1) + self.domain = user_parts[0].upper() + self.user = user_parts[1] + self.pw = pw + + def _new_conn(self): + # Performs the NTLM handshake that secures the connection. The socket + # must be kept open while requests are performed. + self.num_connections += 1 + log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s', + self.num_connections, self.host, self.authurl) + + headers = {} + headers['Connection'] = 'Keep-Alive' + req_header = 'Authorization' + resp_header = 'www-authenticate' + + conn = HTTPSConnection(host=self.host, port=self.port) + + # Send negotiation message + headers[req_header] = ( + 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser)) + log.debug('Request headers: %s', headers) + conn.request('GET', self.authurl, None, headers) + res = conn.getresponse() + reshdr = dict(res.getheaders()) + log.debug('Response status: %s %s', res.status, res.reason) + log.debug('Response headers: %s', reshdr) + log.debug('Response data: %s [...]', res.read(100)) + + # Remove the reference to the socket, so that it can not be closed by + # the response object (we want to keep the socket open) + res.fp = None + + # Server should respond with a challenge message + auth_header_values = reshdr[resp_header].split(', ') + auth_header_value = None + for s in auth_header_values: + if s[:5] == 'NTLM ': + auth_header_value = s[5:] + if auth_header_value is None: + raise Exception('Unexpected %s response header: %s' % + (resp_header, reshdr[resp_header])) + + # Send authentication message + ServerChallenge, NegotiateFlags = \ + ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value) + auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, + self.user, + self.domain, + self.pw, + NegotiateFlags) + headers[req_header] = 'NTLM %s' % auth_msg + log.debug('Request headers: %s', headers) + conn.request('GET', self.authurl, None, headers) + res = conn.getresponse() + log.debug('Response status: %s %s', res.status, res.reason) + log.debug('Response headers: %s', dict(res.getheaders())) + log.debug('Response data: %s [...]', res.read()[:100]) + if res.status != 200: + if res.status == 401: + raise Exception('Server rejected request: wrong ' + 'username or password') + raise Exception('Wrong server response: %s %s' % + (res.status, res.reason)) + + res.fp = None + log.debug('Connection established') + return conn + + def urlopen(self, method, url, body=None, headers=None, retries=3, + redirect=True, assert_same_host=True): + if headers is None: + headers = {} + headers['Connection'] = 'Keep-Alive' + return super(NTLMConnectionPool, self).urlopen(method, url, body, + headers, retries, + redirect, + assert_same_host) diff --git a/pipenv/vendor/requests/packages/urllib3/contrib/pyopenssl.py b/pipenv/vendor/requests/packages/urllib3/contrib/pyopenssl.py new file mode 100644 index 00000000..eb4d4765 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/contrib/pyopenssl.py @@ -0,0 +1,450 @@ +""" +SSL with SNI_-support for Python 2. Follow these instructions if you would +like to verify SSL certificates in Python 2. Note, the default libraries do +*not* do certificate checking; you need to do additional work to validate +certificates yourself. + +This needs the following packages installed: + +* pyOpenSSL (tested with 16.0.0) +* cryptography (minimum 1.3.4, from pyopenssl) +* idna (minimum 2.0, from cryptography) + +However, pyopenssl depends on cryptography, which depends on idna, so while we +use all three directly here we end up having relatively few packages required. + +You can install them with the following command: + + pip install pyopenssl cryptography idna + +To activate certificate checking, call +:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code +before you begin making HTTP requests. This can be done in a ``sitecustomize`` +module, or at any other time before your application begins using ``urllib3``, +like this:: + + try: + import urllib3.contrib.pyopenssl + urllib3.contrib.pyopenssl.inject_into_urllib3() + except ImportError: + pass + +Now you can use :mod:`urllib3` as you normally would, and it will support SNI +when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +compression in Python 2 (see `CRIME attack`_). + +If you want to configure the default list of supported cipher suites, you can +set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +""" +from __future__ import absolute_import + +import OpenSSL.SSL +from cryptography import x509 +from cryptography.hazmat.backends.openssl import backend as openssl_backend +from cryptography.hazmat.backends.openssl.x509 import _Certificate + +from socket import timeout, error as SocketError +from io import BytesIO + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +import logging +import ssl +import six +import sys + +from .. import util + +__all__ = ['inject_into_urllib3', 'extract_from_urllib3'] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, +} + +if hasattr(ssl, 'PROTOCOL_TLSv1_1') and hasattr(OpenSSL.SSL, 'TLSv1_1_METHOD'): + _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD + +if hasattr(ssl, 'PROTOCOL_TLSv1_2') and hasattr(OpenSSL.SSL, 'TLSv1_2_METHOD'): + _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD + +try: + _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD}) +except AttributeError: + pass + +_stdlib_to_openssl_verify = { + ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, + ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, + ssl.CERT_REQUIRED: + OpenSSL.SSL.VERIFY_PEER + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, +} +_openssl_to_stdlib_verify = dict( + (v, k) for k, v in _stdlib_to_openssl_verify.items() +) + +# OpenSSL will only write 16K at a time +SSL_WRITE_BLOCKSIZE = 16384 + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + + +log = logging.getLogger(__name__) + + +def inject_into_urllib3(): + 'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.' + + _validate_dependencies_met() + + util.ssl_.SSLContext = PyOpenSSLContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_PYOPENSSL = True + util.ssl_.IS_PYOPENSSL = True + + +def extract_from_urllib3(): + 'Undo monkey-patching by :func:`inject_into_urllib3`.' + + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_PYOPENSSL = False + util.ssl_.IS_PYOPENSSL = False + + +def _validate_dependencies_met(): + """ + Verifies that PyOpenSSL's package-level dependencies have been met. + Throws `ImportError` if they are not met. + """ + # Method added in `cryptography==1.1`; not available in older versions + from cryptography.x509.extensions import Extensions + if getattr(Extensions, "get_extension_for_class", None) is None: + raise ImportError("'cryptography' module missing required functionality. " + "Try upgrading to v1.3.4 or newer.") + + # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 + # attribute is only present on those versions. + from OpenSSL.crypto import X509 + x509 = X509() + if getattr(x509, "_x509", None) is None: + raise ImportError("'pyOpenSSL' module missing required functionality. " + "Try upgrading to v0.14 or newer.") + + +def _dnsname_to_stdlib(name): + """ + Converts a dNSName SubjectAlternativeName field to the form used by the + standard library on the given Python version. + + Cryptography produces a dNSName as a unicode string that was idna-decoded + from ASCII bytes. We need to idna-encode that string to get it back, and + then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib + uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + """ + def idna_encode(name): + """ + Borrowed wholesale from the Python Cryptography Project. It turns out + that we can't just safely call `idna.encode`: it can explode for + wildcard names. This avoids that problem. + """ + import idna + + for prefix in [u'*.', u'.']: + if name.startswith(prefix): + name = name[len(prefix):] + return prefix.encode('ascii') + idna.encode(name) + return idna.encode(name) + + name = idna_encode(name) + if sys.version_info >= (3, 0): + name = name.decode('utf-8') + return name + + +def get_subj_alt_name(peer_cert): + """ + Given an PyOpenSSL certificate, provides all the subject alternative names. + """ + # Pass the cert to cryptography, which has much better APIs for this. + # This is technically using private APIs, but should work across all + # relevant versions until PyOpenSSL gets something proper for this. + cert = _Certificate(openssl_backend, peer_cert._x509) + + # We want to find the SAN extension. Ask Cryptography to locate it (it's + # faster than looping in Python) + try: + ext = cert.extensions.get_extension_for_class( + x509.SubjectAlternativeName + ).value + except x509.ExtensionNotFound: + # No such extension, return the empty list. + return [] + except (x509.DuplicateExtension, x509.UnsupportedExtension, + x509.UnsupportedGeneralNameType, UnicodeError) as e: + # A problem has been found with the quality of the certificate. Assume + # no SAN field is present. + log.warning( + "A problem was encountered with the certificate that prevented " + "urllib3 from finding the SubjectAlternativeName field. This can " + "affect certificate validation. The error was %s", + e, + ) + return [] + + # We want to return dNSName and iPAddress fields. We need to cast the IPs + # back to strings because the match_hostname function wants them as + # strings. + # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 + # decoded. This is pretty frustrating, but that's what the standard library + # does with certificates, and so we need to attempt to do the same. + names = [ + ('DNS', _dnsname_to_stdlib(name)) + for name in ext.get_values_for_type(x509.DNSName) + ] + names.extend( + ('IP Address', str(name)) + for name in ext.get_values_for_type(x509.IPAddress) + ) + + return names + + +class WrappedSocket(object): + '''API-compatibility wrapper for Python OpenSSL's Connection-class. + + Note: _makefile_refs, _drop() and _reuse() are needed for the garbage + collector of pypy. + ''' + + def __init__(self, connection, socket, suppress_ragged_eofs=True): + self.connection = connection + self.socket = socket + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + self._closed = False + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, *args, **kwargs): + try: + data = self.connection.recv(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): + return b'' + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b'' + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv(*args, **kwargs) + else: + return data + + def recv_into(self, *args, **kwargs): + try: + return self.connection.recv_into(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): + return 0 + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv_into(*args, **kwargs) + + def settimeout(self, timeout): + return self.socket.settimeout(timeout) + + def _send_until_done(self, data): + while True: + try: + return self.connection.send(data) + except OpenSSL.SSL.WantWriteError: + wr = util.wait_for_write(self.socket, self.socket.gettimeout()) + if not wr: + raise timeout() + continue + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self._send_until_done(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE]) + total_sent += sent + + def shutdown(self): + # FIXME rethrow compatible exceptions should we ever use this + self.connection.shutdown() + + def close(self): + if self._makefile_refs < 1: + try: + self._closed = True + return self.connection.close() + except OpenSSL.SSL.Error: + return + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + x509 = self.connection.get_peer_certificate() + + if not x509: + return x509 + + if binary_form: + return OpenSSL.crypto.dump_certificate( + OpenSSL.crypto.FILETYPE_ASN1, + x509) + + return { + 'subject': ( + (('commonName', x509.get_subject().CN),), + ), + 'subjectAltName': get_subj_alt_name(x509) + } + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) +else: # Platform-specific: Python 3 + makefile = backport_makefile + +WrappedSocket.makefile = makefile + + +class PyOpenSSLContext(object): + """ + I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible + for translating the interface of the standard library ``SSLContext`` object + to calls into PyOpenSSL. + """ + def __init__(self, protocol): + self.protocol = _openssl_versions[protocol] + self._ctx = OpenSSL.SSL.Context(self.protocol) + self._options = 0 + self.check_hostname = False + + @property + def options(self): + return self._options + + @options.setter + def options(self, value): + self._options = value + self._ctx.set_options(value) + + @property + def verify_mode(self): + return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] + + @verify_mode.setter + def verify_mode(self, value): + self._ctx.set_verify( + _stdlib_to_openssl_verify[value], + _verify_callback + ) + + def set_default_verify_paths(self): + self._ctx.set_default_verify_paths() + + def set_ciphers(self, ciphers): + if isinstance(ciphers, six.text_type): + ciphers = ciphers.encode('utf-8') + self._ctx.set_cipher_list(ciphers) + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile is not None: + cafile = cafile.encode('utf-8') + if capath is not None: + capath = capath.encode('utf-8') + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_file(certfile) + if password is not None: + self._ctx.set_passwd_cb(lambda max_length, prompt_twice, userdata: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + def wrap_socket(self, sock, server_side=False, + do_handshake_on_connect=True, suppress_ragged_eofs=True, + server_hostname=None): + cnx = OpenSSL.SSL.Connection(self._ctx, sock) + + if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 + server_hostname = server_hostname.encode('utf-8') + + if server_hostname is not None: + cnx.set_tlsext_host_name(server_hostname) + + cnx.set_connect_state() + + while True: + try: + cnx.do_handshake() + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(sock, sock.gettimeout()) + if not rd: + raise timeout('select timed out') + continue + except OpenSSL.SSL.Error as e: + raise ssl.SSLError('bad handshake: %r' % e) + break + + return WrappedSocket(cnx, sock) + + +def _verify_callback(cnx, x509, err_no, err_depth, return_code): + return err_no == 0 diff --git a/pipenv/vendor/requests/packages/urllib3/contrib/socks.py b/pipenv/vendor/requests/packages/urllib3/contrib/socks.py new file mode 100644 index 00000000..39e92fde --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/contrib/socks.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) and +SOCKS5. To enable its functionality, either install PySocks or install this +module with the ``socks`` extra. + +The SOCKS implementation supports the full range of urllib3 features. It also +supports the following SOCKS features: + +- SOCKS4 +- SOCKS4a +- SOCKS5 +- Usernames and passwords for the SOCKS proxy + +Known Limitations: + +- Currently PySocks does not support contacting remote websites via literal + IPv6 addresses. Any such connection attempt will fail. You must use a domain + name. +- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any + such connection attempt will fail. +""" +from __future__ import absolute_import + +try: + import socks +except ImportError: + import warnings + from ..exceptions import DependencyWarning + + warnings.warn(( + 'SOCKS support in urllib3 requires the installation of optional ' + 'dependencies: specifically, PySocks. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies' + ), + DependencyWarning + ) + raise + +from socket import error as SocketError, timeout as SocketTimeout + +from ..connection import ( + HTTPConnection, HTTPSConnection +) +from ..connectionpool import ( + HTTPConnectionPool, HTTPSConnectionPool +) +from ..exceptions import ConnectTimeoutError, NewConnectionError +from ..poolmanager import PoolManager +from ..util.url import parse_url + +try: + import ssl +except ImportError: + ssl = None + + +class SOCKSConnection(HTTPConnection): + """ + A plain-text HTTP connection that connects via a SOCKS proxy. + """ + def __init__(self, *args, **kwargs): + self._socks_options = kwargs.pop('_socks_options') + super(SOCKSConnection, self).__init__(*args, **kwargs) + + def _new_conn(self): + """ + Establish a new connection via the SOCKS proxy. + """ + extra_kw = {} + if self.source_address: + extra_kw['source_address'] = self.source_address + + if self.socket_options: + extra_kw['socket_options'] = self.socket_options + + try: + conn = socks.create_connection( + (self.host, self.port), + proxy_type=self._socks_options['socks_version'], + proxy_addr=self._socks_options['proxy_host'], + proxy_port=self._socks_options['proxy_port'], + proxy_username=self._socks_options['username'], + proxy_password=self._socks_options['password'], + proxy_rdns=self._socks_options['rdns'], + timeout=self.timeout, + **extra_kw + ) + + except SocketTimeout as e: + raise ConnectTimeoutError( + self, "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout)) + + except socks.ProxyError as e: + # This is fragile as hell, but it seems to be the only way to raise + # useful errors here. + if e.socket_err: + error = e.socket_err + if isinstance(error, SocketTimeout): + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout) + ) + else: + raise NewConnectionError( + self, + "Failed to establish a new connection: %s" % error + ) + else: + raise NewConnectionError( + self, + "Failed to establish a new connection: %s" % e + ) + + except SocketError as e: # Defensive: PySocks should catch all these. + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e) + + return conn + + +# We don't need to duplicate the Verified/Unverified distinction from +# urllib3/connection.py here because the HTTPSConnection will already have been +# correctly set to either the Verified or Unverified form by that module. This +# means the SOCKSHTTPSConnection will automatically be the correct type. +class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): + pass + + +class SOCKSHTTPConnectionPool(HTTPConnectionPool): + ConnectionCls = SOCKSConnection + + +class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): + ConnectionCls = SOCKSHTTPSConnection + + +class SOCKSProxyManager(PoolManager): + """ + A version of the urllib3 ProxyManager that routes connections via the + defined SOCKS proxy. + """ + pool_classes_by_scheme = { + 'http': SOCKSHTTPConnectionPool, + 'https': SOCKSHTTPSConnectionPool, + } + + def __init__(self, proxy_url, username=None, password=None, + num_pools=10, headers=None, **connection_pool_kw): + parsed = parse_url(proxy_url) + + if parsed.scheme == 'socks5': + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = False + elif parsed.scheme == 'socks5h': + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = True + elif parsed.scheme == 'socks4': + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = False + elif parsed.scheme == 'socks4a': + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = True + else: + raise ValueError( + "Unable to determine SOCKS version from %s" % proxy_url + ) + + self.proxy_url = proxy_url + + socks_options = { + 'socks_version': socks_version, + 'proxy_host': parsed.host, + 'proxy_port': parsed.port, + 'username': username, + 'password': password, + 'rdns': rdns + } + connection_pool_kw['_socks_options'] = socks_options + + super(SOCKSProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw + ) + + self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/pipenv/vendor/requests/packages/urllib3/exceptions.py b/pipenv/vendor/requests/packages/urllib3/exceptions.py new file mode 100644 index 00000000..6c4be581 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/exceptions.py @@ -0,0 +1,246 @@ +from __future__ import absolute_import +from .packages.six.moves.http_client import ( + IncompleteRead as httplib_IncompleteRead +) +# Base Exceptions + + +class HTTPError(Exception): + "Base exception used by this module." + pass + + +class HTTPWarning(Warning): + "Base warning used by this module." + pass + + +class PoolError(HTTPError): + "Base exception for errors caused within a pool." + def __init__(self, pool, message): + self.pool = pool + HTTPError.__init__(self, "%s: %s" % (pool, message)) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, None) + + +class RequestError(PoolError): + "Base exception for PoolErrors that have associated URLs." + def __init__(self, pool, url, message): + self.url = url + PoolError.__init__(self, pool, message) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, self.url, None) + + +class SSLError(HTTPError): + "Raised when SSL certificate fails in an HTTPS connection." + pass + + +class ProxyError(HTTPError): + "Raised when the connection to a proxy fails." + pass + + +class DecodeError(HTTPError): + "Raised when automatic decoding based on Content-Type fails." + pass + + +class ProtocolError(HTTPError): + "Raised when something unexpected happens mid-request/response." + pass + + +#: Renamed to ProtocolError but aliased for backwards compatibility. +ConnectionError = ProtocolError + + +# Leaf Exceptions + +class MaxRetryError(RequestError): + """Raised when the maximum number of retries is exceeded. + + :param pool: The connection pool + :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` + :param string url: The requested Url + :param exceptions.Exception reason: The underlying error + + """ + + def __init__(self, pool, url, reason=None): + self.reason = reason + + message = "Max retries exceeded with url: %s (Caused by %r)" % ( + url, reason) + + RequestError.__init__(self, pool, url, message) + + +class HostChangedError(RequestError): + "Raised when an existing pool gets a request for a foreign host." + + def __init__(self, pool, url, retries=3): + message = "Tried to open a foreign host with url: %s" % url + RequestError.__init__(self, pool, url, message) + self.retries = retries + + +class TimeoutStateError(HTTPError): + """ Raised when passing an invalid state to a timeout """ + pass + + +class TimeoutError(HTTPError): + """ Raised when a socket timeout error occurs. + + Catching this error will catch both :exc:`ReadTimeoutErrors + ` and :exc:`ConnectTimeoutErrors `. + """ + pass + + +class ReadTimeoutError(TimeoutError, RequestError): + "Raised when a socket timeout occurs while receiving data from a server" + pass + + +# This timeout error does not have a URL attached and needs to inherit from the +# base HTTPError +class ConnectTimeoutError(TimeoutError): + "Raised when a socket timeout occurs while connecting to a server" + pass + + +class NewConnectionError(ConnectTimeoutError, PoolError): + "Raised when we fail to establish a new connection. Usually ECONNREFUSED." + pass + + +class EmptyPoolError(PoolError): + "Raised when a pool runs out of connections and no more are allowed." + pass + + +class ClosedPoolError(PoolError): + "Raised when a request enters a pool after the pool has been closed." + pass + + +class LocationValueError(ValueError, HTTPError): + "Raised when there is something wrong with a given URL input." + pass + + +class LocationParseError(LocationValueError): + "Raised when get_host or similar fails to parse the URL input." + + def __init__(self, location): + message = "Failed to parse: %s" % location + HTTPError.__init__(self, message) + + self.location = location + + +class ResponseError(HTTPError): + "Used as a container for an error reason supplied in a MaxRetryError." + GENERIC_ERROR = 'too many error responses' + SPECIFIC_ERROR = 'too many {status_code} error responses' + + +class SecurityWarning(HTTPWarning): + "Warned when perfoming security reducing actions" + pass + + +class SubjectAltNameWarning(SecurityWarning): + "Warned when connecting to a host with a certificate missing a SAN." + pass + + +class InsecureRequestWarning(SecurityWarning): + "Warned when making an unverified HTTPS request." + pass + + +class SystemTimeWarning(SecurityWarning): + "Warned when system time is suspected to be wrong" + pass + + +class InsecurePlatformWarning(SecurityWarning): + "Warned when certain SSL configuration is not available on a platform." + pass + + +class SNIMissingWarning(HTTPWarning): + "Warned when making a HTTPS request without SNI available." + pass + + +class DependencyWarning(HTTPWarning): + """ + Warned when an attempt is made to import a module with missing optional + dependencies. + """ + pass + + +class ResponseNotChunked(ProtocolError, ValueError): + "Response needs to be chunked in order to read it as chunks." + pass + + +class BodyNotHttplibCompatible(HTTPError): + """ + Body should be httplib.HTTPResponse like (have an fp attribute which + returns raw chunks) for read_chunked(). + """ + pass + + +class IncompleteRead(HTTPError, httplib_IncompleteRead): + """ + Response length doesn't match expected Content-Length + + Subclass of http_client.IncompleteRead to allow int value + for `partial` to avoid creating large objects on streamed + reads. + """ + def __init__(self, partial, expected): + super(IncompleteRead, self).__init__(partial, expected) + + def __repr__(self): + return ('IncompleteRead(%i bytes read, ' + '%i more expected)' % (self.partial, self.expected)) + + +class InvalidHeader(HTTPError): + "The header provided was somehow invalid." + pass + + +class ProxySchemeUnknown(AssertionError, ValueError): + "ProxyManager does not support the supplied scheme" + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + message = "Not supported proxy scheme %s" % scheme + super(ProxySchemeUnknown, self).__init__(message) + + +class HeaderParsingError(HTTPError): + "Raised by assert_header_parsing, but we convert it to a log.warning statement." + def __init__(self, defects, unparsed_data): + message = '%s, unparsed data: %r' % (defects or 'Unknown', unparsed_data) + super(HeaderParsingError, self).__init__(message) + + +class UnrewindableBodyError(HTTPError): + "urllib3 encountered an error when trying to rewind a body" + pass diff --git a/pipenv/vendor/requests/packages/urllib3/fields.py b/pipenv/vendor/requests/packages/urllib3/fields.py new file mode 100644 index 00000000..19b0ae0c --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/fields.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +import email.utils +import mimetypes + +from .packages import six + + +def guess_content_type(filename, default='application/octet-stream'): + """ + Guess the "Content-Type" of a file. + + :param filename: + The filename to guess the "Content-Type" of using :mod:`mimetypes`. + :param default: + If no "Content-Type" can be guessed, default to `default`. + """ + if filename: + return mimetypes.guess_type(filename)[0] or default + return default + + +def format_header_param(name, value): + """ + Helper function to format and quote a single header parameter. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows RFC 2231, as + suggested by RFC 2388 Section 4.4. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + if not any(ch in value for ch in '"\\\r\n'): + result = '%s="%s"' % (name, value) + try: + result.encode('ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + if not six.PY3 and isinstance(value, six.text_type): # Python 2: + value = value.encode('utf-8') + value = email.utils.encode_rfc2231(value, 'utf-8') + value = '%s*=%s' % (name, value) + return value + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. + :param headers: + An optional dict-like object of headers to initially use for the field. + """ + def __init__(self, name, data, filename=None, headers=None): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + + @classmethod + def from_tuples(cls, fieldname, value): + """ + A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. + + Supports constructing :class:`~urllib3.fields.RequestField` from + parameter of key/value strings AND key/filetuple. A filetuple is a + (filename, data, MIME type) tuple where the MIME type is optional. + For example:: + + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + + Field names and filenames must be unicode. + """ + if isinstance(value, tuple): + if len(value) == 3: + filename, data, content_type = value + else: + filename, data = value + content_type = guess_content_type(filename) + else: + filename = None + content_type = None + data = value + + request_param = cls(fieldname, data, filename=filename) + request_param.make_multipart(content_type=content_type) + + return request_param + + def _render_part(self, name, value): + """ + Overridable helper function to format a single header parameter. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + return format_header_param(name, value) + + def _render_parts(self, header_parts): + """ + Helper function to format and quote a single header. + + Useful for single headers that are composed of multiple items. E.g., + 'Content-Disposition' fields. + + :param header_parts: + A sequence of (k, v) typles or a :class:`dict` of (k, v) to format + as `k1="v1"; k2="v2"; ...`. + """ + parts = [] + iterable = header_parts + if isinstance(header_parts, dict): + iterable = header_parts.items() + + for name, value in iterable: + if value is not None: + parts.append(self._render_part(name, value)) + + return '; '.join(parts) + + def render_headers(self): + """ + Renders the headers for this request field. + """ + lines = [] + + sort_keys = ['Content-Disposition', 'Content-Type', 'Content-Location'] + for sort_key in sort_keys: + if self.headers.get(sort_key, False): + lines.append('%s: %s' % (sort_key, self.headers[sort_key])) + + for header_name, header_value in self.headers.items(): + if header_name not in sort_keys: + if header_value: + lines.append('%s: %s' % (header_name, header_value)) + + lines.append('\r\n') + return '\r\n'.join(lines) + + def make_multipart(self, content_disposition=None, content_type=None, + content_location=None): + """ + Makes this request field into a multipart request field. + + This method overrides "Content-Disposition", "Content-Type" and + "Content-Location" headers to the request parameter. + + :param content_type: + The 'Content-Type' of the request body. + :param content_location: + The 'Content-Location' of the request body. + + """ + self.headers['Content-Disposition'] = content_disposition or 'form-data' + self.headers['Content-Disposition'] += '; '.join([ + '', self._render_parts( + (('name', self._name), ('filename', self._filename)) + ) + ]) + self.headers['Content-Type'] = content_type + self.headers['Content-Location'] = content_location diff --git a/pipenv/vendor/requests/packages/urllib3/filepost.py b/pipenv/vendor/requests/packages/urllib3/filepost.py new file mode 100644 index 00000000..cd11cee4 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/filepost.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import +import codecs + +from uuid import uuid4 +from io import BytesIO + +from .packages import six +from .packages.six import b +from .fields import RequestField + +writer = codecs.lookup('utf-8')[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + return uuid4().hex + + +def iter_field_objects(fields): + """ + Iterate over fields. + + Supports list of (k, v) tuples and dicts, and lists of + :class:`~urllib3.fields.RequestField`. + + """ + if isinstance(fields, dict): + i = six.iteritems(fields) + else: + i = iter(fields) + + for field in i: + if isinstance(field, RequestField): + yield field + else: + yield RequestField.from_tuples(*field) + + +def iter_fields(fields): + """ + .. deprecated:: 1.6 + + Iterate over fields. + + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. + + Supports list of (k, v) tuples and dicts. + """ + if isinstance(fields, dict): + return ((k, v) for k, v in six.iteritems(fields)) + + return ((k, v) for k, v in fields) + + +def encode_multipart_formdata(fields, boundary=None): + """ + Encode a dictionary of ``fields`` using the multipart/form-data MIME format. + + :param fields: + Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). + + :param boundary: + If not specified, then a random boundary will be generated using + :func:`mimetools.choose_boundary`. + """ + body = BytesIO() + if boundary is None: + boundary = choose_boundary() + + for field in iter_field_objects(fields): + body.write(b('--%s\r\n' % (boundary))) + + writer(body).write(field.render_headers()) + data = field.data + + if isinstance(data, int): + data = str(data) # Backwards compatibility + + if isinstance(data, six.text_type): + writer(body).write(data) + else: + body.write(data) + + body.write(b'\r\n') + + body.write(b('--%s--\r\n' % (boundary))) + + content_type = str('multipart/form-data; boundary=%s' % boundary) + + return body.getvalue(), content_type diff --git a/pipenv/vendor/requests/packages/urllib3/packages/__init__.py b/pipenv/vendor/requests/packages/urllib3/packages/__init__.py new file mode 100644 index 00000000..170e974c --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from . import ssl_match_hostname + +__all__ = ('ssl_match_hostname', ) diff --git a/pipenv/vendor/requests/packages/urllib3/packages/backports/__init__.py b/pipenv/vendor/requests/packages/urllib3/packages/backports/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pipenv/vendor/requests/packages/urllib3/packages/backports/makefile.py b/pipenv/vendor/requests/packages/urllib3/packages/backports/makefile.py new file mode 100644 index 00000000..75b80dcf --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/backports/makefile.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" +backports.makefile +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``socket.makefile`` method for use with anything that +wants to create a "fake" socket object. +""" +import io + +from socket import SocketIO + + +def backport_makefile(self, mode="r", buffering=None, encoding=None, + errors=None, newline=None): + """ + Backport of ``socket.makefile`` from Python 3.5. + """ + if not set(mode) <= set(["r", "w", "b"]): + raise ValueError( + "invalid mode %r (only r, w, b allowed)" % (mode,) + ) + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = SocketIO(self, rawmode) + self._makefile_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text diff --git a/pipenv/vendor/requests/packages/urllib3/packages/ordered_dict.py b/pipenv/vendor/requests/packages/urllib3/packages/ordered_dict.py new file mode 100644 index 00000000..4479363c --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/ordered_dict.py @@ -0,0 +1,259 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger, released under the MIT License. +# http://code.activestate.com/recipes/576693/ +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/pipenv/vendor/requests/packages/urllib3/packages/six.py b/pipenv/vendor/requests/packages/urllib3/packages/six.py new file mode 100644 index 00000000..190c0239 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 Benjamin Peterson +# +# 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. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.10.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py b/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py new file mode 100644 index 00000000..d6594eb2 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py @@ -0,0 +1,19 @@ +import sys + +try: + # Our match_hostname function is the same as 3.5's, so we only want to + # import the match_hostname function if it's at least that good. + if sys.version_info < (3, 5): + raise ImportError("Fallback to vendored code") + + from ssl import CertificateError, match_hostname +except ImportError: + try: + # Backport of the function from a pypi module + from backports.ssl_match_hostname import CertificateError, match_hostname + except ImportError: + # Our vendored copy + from ._implementation import CertificateError, match_hostname + +# Not needed, but documenting what we provide. +__all__ = ('CertificateError', 'match_hostname') diff --git a/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py b/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py new file mode 100644 index 00000000..1fd42f38 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py @@ -0,0 +1,157 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# backports.ssl_match_hostname to continue to be used all the way back to +# python-2.4. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = '3.5.0.1' + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r'.') + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count('*') + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + obj = unicode(obj, encoding='ascii', errors='strict') + return obj + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED") + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except ValueError: + # Not an IP address (common case) + host_ip = None + except UnicodeError: + # Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: + raise + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == 'IP Address': + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") diff --git a/pipenv/vendor/requests/packages/urllib3/poolmanager.py b/pipenv/vendor/requests/packages/urllib3/poolmanager.py new file mode 100644 index 00000000..cc5a00e4 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/poolmanager.py @@ -0,0 +1,363 @@ +from __future__ import absolute_import +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from .connectionpool import port_by_scheme +from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.url import parse_url +from .util.retry import Retry + + +__all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url'] + + +log = logging.getLogger(__name__) + +SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs', + 'ssl_version', 'ca_cert_dir', 'ssl_context') + +# The base fields to use when determining what pool to get a connection from; +# these do not rely on the ``connection_pool_kw`` and can be determined by the +# URL and potentially the ``urllib3.connection.port_by_scheme`` dictionary. +# +# All custom key schemes should include the fields in this key at a minimum. +BasePoolKey = collections.namedtuple('BasePoolKey', ('scheme', 'host', 'port')) + +# The fields to use when determining what pool to get a HTTP and HTTPS +# connection from. All additional fields must be present in the PoolManager's +# ``connection_pool_kw`` instance variable. +HTTPPoolKey = collections.namedtuple( + 'HTTPPoolKey', BasePoolKey._fields + ('timeout', 'retries', 'strict', + 'block', 'source_address') +) +HTTPSPoolKey = collections.namedtuple( + 'HTTPSPoolKey', HTTPPoolKey._fields + SSL_KEYWORDS +) + + +def _default_key_normalizer(key_class, request_context): + """ + Create a pool key of type ``key_class`` for a request. + + According to RFC 3986, both the scheme and host are case-insensitive. + Therefore, this function normalizes both before constructing the pool + key for an HTTPS request. If you wish to change this behaviour, provide + alternate callables to ``key_fn_by_scheme``. + + :param key_class: + The class to use when constructing the key. This should be a namedtuple + with the ``scheme`` and ``host`` keys at a minimum. + + :param request_context: + A dictionary-like object that contain the context for a request. + It should contain a key for each field in the :class:`HTTPPoolKey` + """ + context = {} + for key in key_class._fields: + context[key] = request_context.get(key) + context['scheme'] = context['scheme'].lower() + context['host'] = context['host'].lower() + return key_class(**context) + + +# A dictionary that maps a scheme to a callable that creates a pool key. +# This can be used to alter the way pool keys are constructed, if desired. +# Each PoolManager makes a copy of this dictionary so they can be configured +# globally here, or individually on the instance. +key_fn_by_scheme = { + 'http': functools.partial(_default_key_normalizer, HTTPPoolKey), + 'https': functools.partial(_default_key_normalizer, HTTPSPoolKey), +} + +pool_classes_by_scheme = { + 'http': HTTPConnectionPool, + 'https': HTTPSConnectionPool, +} + + +class PoolManager(RequestMethods): + """ + Allows for arbitrary requests while transparently keeping track of + necessary connection pools for you. + + :param num_pools: + Number of connection pools to cache before discarding the least + recently used pool. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param \\**connection_pool_kw: + Additional parameters are used to create fresh + :class:`urllib3.connectionpool.ConnectionPool` instances. + + Example:: + + >>> manager = PoolManager(num_pools=2) + >>> r = manager.request('GET', 'http://google.com/') + >>> r = manager.request('GET', 'http://google.com/mail') + >>> r = manager.request('GET', 'http://yahoo.com/') + >>> len(manager.pools) + 2 + + """ + + proxy = None + + def __init__(self, num_pools=10, headers=None, **connection_pool_kw): + RequestMethods.__init__(self, headers) + self.connection_pool_kw = connection_pool_kw + self.pools = RecentlyUsedContainer(num_pools, + dispose_func=lambda p: p.close()) + + # Locally set the pool classes and keys so other PoolManagers can + # override them. + self.pool_classes_by_scheme = pool_classes_by_scheme + self.key_fn_by_scheme = key_fn_by_scheme.copy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.clear() + # Return False to re-raise any potential exceptions + return False + + def _new_pool(self, scheme, host, port): + """ + Create a new :class:`ConnectionPool` based on host, port and scheme. + + This method is used to actually create the connection pools handed out + by :meth:`connection_from_url` and companion methods. It is intended + to be overridden for customization. + """ + pool_cls = self.pool_classes_by_scheme[scheme] + kwargs = self.connection_pool_kw + if scheme == 'http': + kwargs = self.connection_pool_kw.copy() + for kw in SSL_KEYWORDS: + kwargs.pop(kw, None) + + return pool_cls(host, port, **kwargs) + + def clear(self): + """ + Empty our store of pools and direct them all to close. + + This will not affect in-flight connections, but they will not be + re-used after completion. + """ + self.pools.clear() + + def connection_from_host(self, host, port=None, scheme='http'): + """ + Get a :class:`ConnectionPool` based on the host, port, and scheme. + + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. + """ + + if not host: + raise LocationValueError("No host specified.") + + request_context = self.connection_pool_kw.copy() + request_context['scheme'] = scheme or 'http' + if not port: + port = port_by_scheme.get(request_context['scheme'].lower(), 80) + request_context['port'] = port + request_context['host'] = host + + return self.connection_from_context(request_context) + + def connection_from_context(self, request_context): + """ + Get a :class:`ConnectionPool` based on the request context. + + ``request_context`` must at least contain the ``scheme`` key and its + value must be a key in ``key_fn_by_scheme`` instance variable. + """ + scheme = request_context['scheme'].lower() + pool_key_constructor = self.key_fn_by_scheme[scheme] + pool_key = pool_key_constructor(request_context) + + return self.connection_from_pool_key(pool_key) + + def connection_from_pool_key(self, pool_key): + """ + Get a :class:`ConnectionPool` based on the provided pool key. + + ``pool_key`` should be a namedtuple that only contains immutable + objects. At a minimum it must have the ``scheme``, ``host``, and + ``port`` fields. + """ + with self.pools.lock: + # If the scheme, host, or port doesn't match existing open + # connections, open a new ConnectionPool. + pool = self.pools.get(pool_key) + if pool: + return pool + + # Make a fresh ConnectionPool of the desired type + pool = self._new_pool(pool_key.scheme, pool_key.host, pool_key.port) + self.pools[pool_key] = pool + + return pool + + def connection_from_url(self, url): + """ + Similar to :func:`urllib3.connectionpool.connection_from_url` but + doesn't pass any additional parameters to the + :class:`urllib3.connectionpool.ConnectionPool` constructor. + + Additional parameters are taken from the :class:`.PoolManager` + constructor. + """ + u = parse_url(url) + return self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + def urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. + + The given ``url`` parameter must be absolute, such that an appropriate + :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. + """ + u = parse_url(url) + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + kw['assert_same_host'] = False + kw['redirect'] = False + if 'headers' not in kw: + kw['headers'] = self.headers + + if self.proxy is not None and u.scheme == "http": + response = conn.urlopen(method, url, **kw) + else: + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + + # RFC 7231, Section 6.4.4 + if response.status == 303: + method = 'GET' + + retries = kw.get('retries') + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + raise + return response + + kw['retries'] = retries + kw['redirect'] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + return self.urlopen(method, redirect_location, **kw) + + +class ProxyManager(PoolManager): + """ + Behaves just like :class:`PoolManager`, but sends all requests through + the defined proxy, using the CONNECT method for HTTPS URLs. + + :param proxy_url: + The URL of the proxy to be used. + + :param proxy_headers: + A dictionary contaning headers that will be sent to the proxy. In case + of HTTP they are being sent with each request, while in the + HTTPS/CONNECT case they are sent only once. Could be used for proxy + authentication. + + Example: + >>> proxy = urllib3.ProxyManager('http://localhost:3128/') + >>> r1 = proxy.request('GET', 'http://google.com/') + >>> r2 = proxy.request('GET', 'http://httpbin.org/') + >>> len(proxy.pools) + 1 + >>> r3 = proxy.request('GET', 'https://httpbin.org/') + >>> r4 = proxy.request('GET', 'https://twitter.com/') + >>> len(proxy.pools) + 3 + + """ + + def __init__(self, proxy_url, num_pools=10, headers=None, + proxy_headers=None, **connection_pool_kw): + + if isinstance(proxy_url, HTTPConnectionPool): + proxy_url = '%s://%s:%i' % (proxy_url.scheme, proxy_url.host, + proxy_url.port) + proxy = parse_url(proxy_url) + if not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + + connection_pool_kw['_proxy'] = self.proxy + connection_pool_kw['_proxy_headers'] = self.proxy_headers + + super(ProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw) + + def connection_from_host(self, host, port=None, scheme='http'): + if scheme == "https": + return super(ProxyManager, self).connection_from_host( + host, port, scheme) + + return super(ProxyManager, self).connection_from_host( + self.proxy.host, self.proxy.port, self.proxy.scheme) + + def _set_proxy_headers(self, url, headers=None): + """ + Sets headers needed by proxies: specifically, the Accept and Host + headers. Only sets headers not provided by the user. + """ + headers_ = {'Accept': '*/*'} + + netloc = parse_url(url).netloc + if netloc: + headers_['Host'] = netloc + + if headers: + headers_.update(headers) + return headers_ + + def urlopen(self, method, url, redirect=True, **kw): + "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." + u = parse_url(url) + + if u.scheme == "http": + # For proxied HTTPS requests, httplib sets the necessary headers + # on the CONNECT to the proxy. For HTTP, we'll definitely + # need to set 'Host' at the very least. + headers = kw.get('headers', self.headers) + kw['headers'] = self._set_proxy_headers(url, headers) + + return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) + + +def proxy_from_url(url, **kw): + return ProxyManager(proxy_url=url, **kw) diff --git a/pipenv/vendor/requests/packages/urllib3/request.py b/pipenv/vendor/requests/packages/urllib3/request.py new file mode 100644 index 00000000..c0fddff0 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/request.py @@ -0,0 +1,148 @@ +from __future__ import absolute_import + +from .filepost import encode_multipart_formdata +from .packages.six.moves.urllib.parse import urlencode + + +__all__ = ['RequestMethods'] + + +class RequestMethods(object): + """ + Convenience mixin for classes who implement a :meth:`urlopen` method, such + as :class:`~urllib3.connectionpool.HTTPConnectionPool` and + :class:`~urllib3.poolmanager.PoolManager`. + + Provides behavior for making common types of HTTP request methods and + decides which type of request field encoding to use. + + Specifically, + + :meth:`.request_encode_url` is for sending requests whose fields are + encoded in the URL (such as GET, HEAD, DELETE). + + :meth:`.request_encode_body` is for sending requests whose fields are + encoded in the *body* of the request using multipart or www-form-urlencoded + (such as for POST, PUT, PATCH). + + :meth:`.request` is for making any kind of request, it will look up the + appropriate encoding format and use one of the above two methods to make + the request. + + Initializer parameters: + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + """ + + _encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS']) + + def __init__(self, headers=None): + self.headers = headers or {} + + def urlopen(self, method, url, body=None, headers=None, + encode_multipart=True, multipart_boundary=None, + **kw): # Abstract + raise NotImplemented("Classes extending RequestMethods must implement " + "their own ``urlopen`` method.") + + def request(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the appropriate encoding of + ``fields`` based on the ``method`` used. + + This is a convenience method that requires the least amount of manual + effort. It can be used in most situations, while still having the + option to drop down to more specific methods when necessary, such as + :meth:`request_encode_url`, :meth:`request_encode_body`, + or even the lowest level :meth:`urlopen`. + """ + method = method.upper() + + if method in self._encode_url_methods: + return self.request_encode_url(method, url, fields=fields, + headers=headers, + **urlopen_kw) + else: + return self.request_encode_body(method, url, fields=fields, + headers=headers, + **urlopen_kw) + + def request_encode_url(self, method, url, fields=None, headers=None, + **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the url. This is useful for request methods like GET, HEAD, DELETE, etc. + """ + if headers is None: + headers = self.headers + + extra_kw = {'headers': headers} + extra_kw.update(urlopen_kw) + + if fields: + url += '?' + urlencode(fields) + + return self.urlopen(method, url, **extra_kw) + + def request_encode_body(self, method, url, fields=None, headers=None, + encode_multipart=True, multipart_boundary=None, + **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the body. This is useful for request methods like POST, PUT, PATCH, etc. + + When ``encode_multipart=True`` (default), then + :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :meth:`urllib.urlencode` is used with the + 'application/x-www-form-urlencoded' content type. + + Multipart encoding must be used when posting files, and it's reasonably + safe to use it in other times too. However, it may break request + signing, such as with OAuth. + + Supports an optional ``fields`` parameter of key/value strings AND + key/filetuple. A filetuple is a (filename, data, MIME type) tuple where + the MIME type is optional. For example:: + + fields = { + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), + 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + } + + When uploading a file, providing a filename (the first parameter of the + tuple) is optional but recommended to best mimick behavior of browsers. + + Note that if ``headers`` are supplied, the 'Content-Type' header will + be overwritten because it depends on the dynamic random boundary string + which is used to compose the body of the request. The random boundary + string can be explicitly set with the ``multipart_boundary`` parameter. + """ + if headers is None: + headers = self.headers + + extra_kw = {'headers': {}} + + if fields: + if 'body' in urlopen_kw: + raise TypeError( + "request got values for both 'fields' and 'body', can only specify one.") + + if encode_multipart: + body, content_type = encode_multipart_formdata(fields, boundary=multipart_boundary) + else: + body, content_type = urlencode(fields), 'application/x-www-form-urlencoded' + + extra_kw['body'] = body + extra_kw['headers'] = {'Content-Type': content_type} + + extra_kw['headers'].update(headers) + extra_kw.update(urlopen_kw) + + return self.urlopen(method, url, **extra_kw) diff --git a/pipenv/vendor/requests/packages/urllib3/response.py b/pipenv/vendor/requests/packages/urllib3/response.py new file mode 100644 index 00000000..6f1b63c8 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/response.py @@ -0,0 +1,618 @@ +from __future__ import absolute_import +from contextlib import contextmanager +import zlib +import io +import logging +from socket import timeout as SocketTimeout +from socket import error as SocketError + +from ._collections import HTTPHeaderDict +from .exceptions import ( + BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError, + ResponseNotChunked, IncompleteRead, InvalidHeader +) +from .packages.six import string_types as basestring, binary_type, PY3 +from .packages.six.moves import http_client as httplib +from .connection import HTTPException, BaseSSLError +from .util.response import is_fp_closed, is_response_to_head + +log = logging.getLogger(__name__) + + +class DeflateDecoder(object): + + def __init__(self): + self._first_try = True + self._data = binary_type() + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + + if not self._first_try: + return self._obj.decompress(data) + + self._data += data + try: + return self._obj.decompress(data) + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: + return self.decompress(self._data) + finally: + self._data = None + + +class GzipDecoder(object): + + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + return self._obj.decompress(data) + + +def _get_decoder(mode): + if mode == 'gzip': + return GzipDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible to httplib's HTTPResponse but the response ``body`` is + loaded and decoded on-demand when the ``data`` property is accessed. This + class is also compatible with the Python standard library's :mod:`io` + module, and can hence be treated as a readable object in the context of that + framework. + + Extra parameters for behaviour not present in httplib.HTTPResponse: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, attempts to decode specific content-encoding's based on headers + (like 'gzip' and 'deflate') will be skipped and raw data will be used + instead. + + :param original_response: + When this HTTPResponse wrapper is generated from an httplib.HTTPResponse + object, it's convenient to include the original for debug purposes. It's + otherwise unused. + + :param retries: + The retries contains the last :class:`~urllib3.util.retry.Retry` that + was used during the request. + + :param enforce_content_length: + Enforce content length checking. Body returned by server must match + value of Content-Length header, if present. Otherwise, raise error. + """ + + CONTENT_DECODERS = ['gzip', 'deflate'] + REDIRECT_STATUSES = [301, 302, 303, 307, 308] + + def __init__(self, body='', headers=None, status=0, version=0, reason=None, + strict=0, preload_content=True, decode_content=True, + original_response=None, pool=None, connection=None, + retries=None, enforce_content_length=False, request_method=None): + + if isinstance(headers, HTTPHeaderDict): + self.headers = headers + else: + self.headers = HTTPHeaderDict(headers) + self.status = status + self.version = version + self.reason = reason + self.strict = strict + self.decode_content = decode_content + self.retries = retries + self.enforce_content_length = enforce_content_length + + self._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + + if body and isinstance(body, (basestring, binary_type)): + self._body = body + + self._pool = pool + self._connection = connection + + if hasattr(body, 'read'): + self._fp = body + + # Are we using the chunked-style of transfer encoding? + self.chunked = False + self.chunk_left = None + tr_enc = self.headers.get('transfer-encoding', '').lower() + # Don't incur the penalty of creating a list and then discarding it + encodings = (enc.strip() for enc in tr_enc.split(",")) + if "chunked" in encodings: + self.chunked = True + + # Determine length of response + self.length_remaining = self._init_length(request_method) + + # If requested, preload the body. + if preload_content and not self._body: + self._body = self.read(decode_content=decode_content) + + def get_redirect_location(self): + """ + Should we redirect and where to? + + :returns: Truthy redirect location string if we got a redirect status + code and valid location. ``None`` if redirect status and no + location. ``False`` if not a redirect status code. + """ + if self.status in self.REDIRECT_STATUSES: + return self.headers.get('location') + + return False + + def release_conn(self): + if not self._pool or not self._connection: + return + + self._pool._put_conn(self._connection) + self._connection = None + + @property + def data(self): + # For backwords-compat with earlier urllib3 0.4 and earlier. + if self._body: + return self._body + + if self._fp: + return self.read(cache_content=True) + + @property + def connection(self): + return self._connection + + def tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``HTTPResponse.read`` if bytes + are encoded on the wire (e.g, compressed). + """ + return self._fp_bytes_read + + def _init_length(self, request_method): + """ + Set initial length value for Response content if available. + """ + length = self.headers.get('content-length') + + if length is not None and self.chunked: + # This Response will fail with an IncompleteRead if it can't be + # received as chunked. This method falls back to attempt reading + # the response before raising an exception. + log.warning("Received response with both Content-Length and " + "Transfer-Encoding set. This is expressly forbidden " + "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " + "attempting to process response as Transfer-Encoding: " + "chunked.") + return None + + elif length is not None: + try: + # RFC 7230 section 3.3.2 specifies multiple content lengths can + # be sent in a single Content-Length header + # (e.g. Content-Length: 42, 42). This line ensures the values + # are all valid ints and that as long as the `set` length is 1, + # all values are the same. Otherwise, the header is invalid. + lengths = set([int(val) for val in length.split(',')]) + if len(lengths) > 1: + raise InvalidHeader("Content-Length contained multiple " + "unmatching values (%s)" % length) + length = lengths.pop() + except ValueError: + length = None + else: + if length < 0: + length = None + + # Convert status to int for comparison + # In some cases, httplib returns a status of "_UNKNOWN" + try: + status = int(self.status) + except ValueError: + status = 0 + + # Check for responses that shouldn't include a body + if status in (204, 304) or 100 <= status < 200 or request_method == 'HEAD': + length = 0 + + return length + + def _init_decoder(self): + """ + Set-up the _decoder attribute if necessary. + """ + # Note: content-encoding value should be case-insensitive, per RFC 7230 + # Section 3.2 + content_encoding = self.headers.get('content-encoding', '').lower() + if self._decoder is None and content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + try: + if decode_content and self._decoder: + data = self._decoder.decompress(data) + except (IOError, zlib.error) as e: + content_encoding = self.headers.get('content-encoding', '').lower() + raise DecodeError( + "Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding, e) + + if flush_decoder and decode_content: + data += self._flush_decoder() + + return data + + def _flush_decoder(self): + """ + Flushes the decoder. Should only be called if the decoder is actually + being used. + """ + if self._decoder: + buf = self._decoder.decompress(b'') + return buf + self._decoder.flush() + + return b'' + + @contextmanager + def _error_catcher(self): + """ + Catch low-level python exceptions, instead re-raising urllib3 + variants, so that low-level exceptions are not leaked in the + high-level api. + + On exit, release the connection back to the pool. + """ + clean_exit = False + + try: + try: + yield + + except SocketTimeout: + # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but + # there is yet no clean way to get at it from this context. + raise ReadTimeoutError(self._pool, None, 'Read timed out.') + + except BaseSSLError as e: + # FIXME: Is there a better way to differentiate between SSLErrors? + if 'read operation timed out' not in str(e): # Defensive: + # This shouldn't happen but just in case we're missing an edge + # case, let's avoid swallowing SSL errors. + raise + + raise ReadTimeoutError(self._pool, None, 'Read timed out.') + + except (HTTPException, SocketError) as e: + # This includes IncompleteRead. + raise ProtocolError('Connection broken: %r' % e, e) + + # If no exception is thrown, we should avoid cleaning up + # unnecessarily. + clean_exit = True + finally: + # If we didn't terminate cleanly, we need to throw away our + # connection. + if not clean_exit: + # The response may not be closed but we're not going to use it + # anymore so close it now to ensure that the connection is + # released back to the pool. + if self._original_response: + self._original_response.close() + + # Closing the response may not actually be sufficient to close + # everything, so if we have a hold of the connection close that + # too. + if self._connection: + self._connection.close() + + # If we hold the original response but it's closed now, we should + # return the connection back to the pool. + if self._original_response and self._original_response.isclosed(): + self.release_conn() + + def read(self, amt=None, decode_content=None, cache_content=False): + """ + Similar to :meth:`httplib.HTTPResponse.read`, but with two additional + parameters: ``decode_content`` and ``cache_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param cache_content: + If True, will save the returned data such that the same result is + returned despite of the state of the underlying file object. This + is useful if you want the ``.data`` property to continue working + after having ``.read()`` the file object. (Overridden if ``amt`` is + set.) + """ + self._init_decoder() + if decode_content is None: + decode_content = self.decode_content + + if self._fp is None: + return + + flush_decoder = False + data = None + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) + if amt != 0 and not data: # Platform-specific: Buggy versions of Python. + # Close the connection when no data is returned + # + # This is redundant to what httplib/http.client _should_ + # already do. However, versions of python released before + # December 15, 2012 (http://bugs.python.org/issue16298) do + # not properly close the connection in all cases. There is + # no harm in redundantly calling close. + self._fp.close() + flush_decoder = True + if self.enforce_content_length and self.length_remaining not in (0, None): + # This is an edge case that httplib failed to cover due + # to concerns of backward compatibility. We're + # addressing it here to make sure IncompleteRead is + # raised during streaming, so all calls with incorrect + # Content-Length are caught. + raise IncompleteRead(self._fp_bytes_read, self.length_remaining) + + if data: + self._fp_bytes_read += len(data) + if self.length_remaining is not None: + self.length_remaining -= len(data) + + data = self._decode(data, decode_content, flush_decoder) + + if cache_content: + self._body = data + + return data + + def stream(self, amt=2**16, decode_content=None): + """ + A generator wrapper for the read() method. A call will block until + ``amt`` bytes have been read from the connection or until the + connection is closed. + + :param amt: + How much of the content to read. The generator will return up to + much data per iteration, but may return less. This is particularly + likely when using compressed data. However, the empty string will + never be returned. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + if self.chunked and self.supports_chunked_reads(): + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: + while not is_fp_closed(self._fp): + data = self.read(amt=amt, decode_content=decode_content) + + if data: + yield data + + @classmethod + def from_httplib(ResponseCls, r, **response_kw): + """ + Given an :class:`httplib.HTTPResponse` instance ``r``, return a + corresponding :class:`urllib3.response.HTTPResponse` object. + + Remaining parameters are passed to the HTTPResponse constructor, along + with ``original_response=r``. + """ + headers = r.msg + + if not isinstance(headers, HTTPHeaderDict): + if PY3: # Python 3 + headers = HTTPHeaderDict(headers.items()) + else: # Python 2 + headers = HTTPHeaderDict.from_httplib(headers) + + # HTTPResponse objects in Python 3 don't have a .strict attribute + strict = getattr(r, 'strict', 0) + resp = ResponseCls(body=r, + headers=headers, + status=r.status, + version=r.version, + reason=r.reason, + strict=strict, + original_response=r, + **response_kw) + return resp + + # Backwards-compatibility methods for httplib.HTTPResponse + def getheaders(self): + return self.headers + + def getheader(self, name, default=None): + return self.headers.get(name, default) + + # Overrides from io.IOBase + def close(self): + if not self.closed: + self._fp.close() + + if self._connection: + self._connection.close() + + @property + def closed(self): + if self._fp is None: + return True + elif hasattr(self._fp, 'isclosed'): + return self._fp.isclosed() + elif hasattr(self._fp, 'closed'): + return self._fp.closed + else: + return True + + def fileno(self): + if self._fp is None: + raise IOError("HTTPResponse has no file to get a fileno from") + elif hasattr(self._fp, "fileno"): + return self._fp.fileno() + else: + raise IOError("The file-like object this HTTPResponse is wrapped " + "around has no file descriptor") + + def flush(self): + if self._fp is not None and hasattr(self._fp, 'flush'): + return self._fp.flush() + + def readable(self): + # This method is required for `io` module compatibility. + return True + + def readinto(self, b): + # This method is required for `io` module compatibility. + temp = self.read(len(b)) + if len(temp) == 0: + return 0 + else: + b[:len(temp)] = temp + return len(temp) + + def supports_chunked_reads(self): + """ + Checks if the underlying file-like object looks like a + httplib.HTTPResponse object. We do this by testing for the fp + attribute. If it is present we assume it returns raw chunks as + processed by read_chunked(). + """ + return hasattr(self._fp, 'fp') + + def _update_chunk_length(self): + # First, we'll figure out length of a chunk and then + # we'll try to read it from socket. + if self.chunk_left is not None: + return + line = self._fp.fp.readline() + line = line.split(b';', 1)[0] + try: + self.chunk_left = int(line, 16) + except ValueError: + # Invalid chunked protocol response, abort. + self.close() + raise httplib.IncompleteRead(line) + + def _handle_chunk(self, amt): + returned_chunk = None + if amt is None: + chunk = self._fp._safe_read(self.chunk_left) + returned_chunk = chunk + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + elif amt < self.chunk_left: + value = self._fp._safe_read(amt) + self.chunk_left = self.chunk_left - amt + returned_chunk = value + elif amt == self.chunk_left: + value = self._fp._safe_read(amt) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + returned_chunk = value + else: # amt > self.chunk_left + returned_chunk = self._fp._safe_read(self.chunk_left) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + return returned_chunk + + def read_chunked(self, amt=None, decode_content=None): + """ + Similar to :meth:`HTTPResponse.read`, but with an additional + parameter: ``decode_content``. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + self._init_decoder() + # FIXME: Rewrite this method and make it a class with a better structured logic. + if not self.chunked: + raise ResponseNotChunked( + "Response is not chunked. " + "Header 'transfer-encoding: chunked' is missing.") + if not self.supports_chunked_reads(): + raise BodyNotHttplibCompatible( + "Body should be httplib.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks.") + + # Don't bother reading the body of a HEAD request. + if self._original_response and is_response_to_head(self._original_response): + self._original_response.close() + return + + with self._error_catcher(): + while True: + self._update_chunk_length() + if self.chunk_left == 0: + break + chunk = self._handle_chunk(amt) + decoded = self._decode(chunk, decode_content=decode_content, + flush_decoder=False) + if decoded: + yield decoded + + if decode_content: + # On CPython and PyPy, we should never need to flush the + # decoder. However, on Jython we *might* need to, so + # lets defensively do it anyway. + decoded = self._flush_decoder() + if decoded: # Platform-specific: Jython. + yield decoded + + # Chunk content ends with \r\n: discard it. + while True: + line = self._fp.fp.readline() + if not line: + # Some sites may not end with '\r\n'. + break + if line == b'\r\n': + break + + # We read everything; close the "file". + if self._original_response: + self._original_response.close() diff --git a/pipenv/vendor/requests/packages/urllib3/util/__init__.py b/pipenv/vendor/requests/packages/urllib3/util/__init__.py new file mode 100644 index 00000000..5ced5a44 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/__init__.py @@ -0,0 +1,52 @@ +from __future__ import absolute_import +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import make_headers +from .response import is_fp_closed +from .ssl_ import ( + SSLContext, + HAS_SNI, + IS_PYOPENSSL, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import ( + current_time, + Timeout, +) + +from .retry import Retry +from .url import ( + get_host, + parse_url, + split_first, + Url, +) +from .wait import ( + wait_for_read, + wait_for_write +) + +__all__ = ( + 'HAS_SNI', + 'IS_PYOPENSSL', + 'SSLContext', + 'Retry', + 'Timeout', + 'Url', + 'assert_fingerprint', + 'current_time', + 'is_connection_dropped', + 'is_fp_closed', + 'get_host', + 'parse_url', + 'make_headers', + 'resolve_cert_reqs', + 'resolve_ssl_version', + 'split_first', + 'ssl_wrap_socket', + 'wait_for_read', + 'wait_for_write' +) diff --git a/pipenv/vendor/requests/packages/urllib3/util/connection.py b/pipenv/vendor/requests/packages/urllib3/util/connection.py new file mode 100644 index 00000000..bf699cfd --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/connection.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import +import socket +from .wait import wait_for_read +from .selectors import HAS_SELECT, SelectorError + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`httplib.HTTPConnection` object. + + Note: For platforms like AppEngine, this will always return ``False`` to + let the platform handle connection recycling transparently for us. + """ + sock = getattr(conn, 'sock', False) + if sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + + if not HAS_SELECT: + return False + + try: + return bool(wait_for_read(sock, timeout=0.0)) + except SelectorError: + return True + + +# This function is copied from socket.py in the Python 2.7 standard +# library test suite. Added to its signature is only `socket_options`. +# One additional modification is that we avoid binding to IPv6 servers +# discovered in DNS if the system doesn't have IPv6 functionality. +def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + source_address=None, socket_options=None): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + + host, port = address + if host.startswith('['): + host = host.strip('[]') + err = None + + # Using the value from allowed_gai_family() in the context of getaddrinfo lets + # us select whether to work with IPv4 DNS records, IPv6 records, or both. + # The original create_connection function always returns all records. + family = allowed_gai_family() + + for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + + # If provided, set socket level options before connecting. + _set_socket_options(sock, socket_options) + + if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except socket.error as e: + err = e + if sock is not None: + sock.close() + sock = None + + if err is not None: + raise err + + raise socket.error("getaddrinfo returns an empty list") + + +def _set_socket_options(sock, options): + if options is None: + return + + for opt in options: + sock.setsockopt(*opt) + + +def allowed_gai_family(): + """This function is designed to work in the context of + getaddrinfo, where family=socket.AF_UNSPEC is the default and + will perform a DNS search for both IPv6 and IPv4 records.""" + + family = socket.AF_INET + if HAS_IPV6: + family = socket.AF_UNSPEC + return family + + +def _has_ipv6(host): + """ Returns True if the system can bind an IPv6 address. """ + sock = None + has_ipv6 = False + + if socket.has_ipv6: + # has_ipv6 returns true if cPython was compiled with IPv6 support. + # It does not tell us if the system has IPv6 support enabled. To + # determine that we must bind to an IPv6 address. + # https://github.com/shazow/urllib3/pull/611 + # https://bugs.python.org/issue658327 + try: + sock = socket.socket(socket.AF_INET6) + sock.bind((host, 0)) + has_ipv6 = True + except Exception: + pass + + if sock: + sock.close() + return has_ipv6 + + +HAS_IPV6 = _has_ipv6('::1') diff --git a/pipenv/vendor/requests/packages/urllib3/util/request.py b/pipenv/vendor/requests/packages/urllib3/util/request.py new file mode 100644 index 00000000..974fc40a --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/request.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import +from base64 import b64encode + +from ..packages.six import b, integer_types +from ..exceptions import UnrewindableBodyError + +ACCEPT_ENCODING = 'gzip,deflate' +_FAILEDTELL = object() + + +def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, + basic_auth=None, proxy_basic_auth=None, disable_cache=None): + """ + Shortcuts for generating request headers. + + :param keep_alive: + If ``True``, adds 'connection: keep-alive' header. + + :param accept_encoding: + Can be a boolean, list, or string. + ``True`` translates to 'gzip,deflate'. + List will get joined by comma. + String will be used as provided. + + :param user_agent: + String representing the user-agent you want, such as + "python-urllib3/0.6" + + :param basic_auth: + Colon-separated username:password string for 'authorization: basic ...' + auth header. + + :param proxy_basic_auth: + Colon-separated username:password string for 'proxy-authorization: basic ...' + auth header. + + :param disable_cache: + If ``True``, adds 'cache-control: no-cache' header. + + Example:: + + >>> make_headers(keep_alive=True, user_agent="Batman/1.0") + {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} + >>> make_headers(accept_encoding=True) + {'accept-encoding': 'gzip,deflate'} + """ + headers = {} + if accept_encoding: + if isinstance(accept_encoding, str): + pass + elif isinstance(accept_encoding, list): + accept_encoding = ','.join(accept_encoding) + else: + accept_encoding = ACCEPT_ENCODING + headers['accept-encoding'] = accept_encoding + + if user_agent: + headers['user-agent'] = user_agent + + if keep_alive: + headers['connection'] = 'keep-alive' + + if basic_auth: + headers['authorization'] = 'Basic ' + \ + b64encode(b(basic_auth)).decode('utf-8') + + if proxy_basic_auth: + headers['proxy-authorization'] = 'Basic ' + \ + b64encode(b(proxy_basic_auth)).decode('utf-8') + + if disable_cache: + headers['cache-control'] = 'no-cache' + + return headers + + +def set_file_position(body, pos): + """ + If a position is provided, move file to that point. + Otherwise, we'll attempt to record a position for future use. + """ + if pos is not None: + rewind_body(body, pos) + elif getattr(body, 'tell', None) is not None: + try: + pos = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body. + pos = _FAILEDTELL + + return pos + + +def rewind_body(body, body_pos): + """ + Attempt to rewind body to a certain position. + Primarily used for request redirects and retries. + + :param body: + File-like object that supports seek. + + :param int pos: + Position to seek to in file. + """ + body_seek = getattr(body, 'seek', None) + if body_seek is not None and isinstance(body_pos, integer_types): + try: + body_seek(body_pos) + except (IOError, OSError): + raise UnrewindableBodyError("An error occured when rewinding request " + "body for redirect/retry.") + elif body_pos is _FAILEDTELL: + raise UnrewindableBodyError("Unable to record file position for rewinding " + "request body during a redirect/retry.") + else: + raise ValueError("body_pos must be of type integer, " + "instead it was %s." % type(body_pos)) diff --git a/pipenv/vendor/requests/packages/urllib3/util/response.py b/pipenv/vendor/requests/packages/urllib3/util/response.py new file mode 100644 index 00000000..67cf730a --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/response.py @@ -0,0 +1,81 @@ +from __future__ import absolute_import +from ..packages.six.moves import http_client as httplib + +from ..exceptions import HeaderParsingError + + +def is_fp_closed(obj): + """ + Checks whether a given file-like object is closed. + + :param obj: + The file-like object to check. + """ + + try: + # Check `isclosed()` first, in case Python3 doesn't set `closed`. + # GH Issue #928 + return obj.isclosed() + except AttributeError: + pass + + try: + # Check via the official file-like-object way. + return obj.closed + except AttributeError: + pass + + try: + # Check if the object is a container for another file-like object that + # gets released on exhaustion (e.g. HTTPResponse). + return obj.fp is None + except AttributeError: + pass + + raise ValueError("Unable to determine whether fp is closed.") + + +def assert_header_parsing(headers): + """ + Asserts whether all headers have been successfully parsed. + Extracts encountered errors from the result of parsing headers. + + Only works on Python 3. + + :param headers: Headers to verify. + :type headers: `httplib.HTTPMessage`. + + :raises urllib3.exceptions.HeaderParsingError: + If parsing errors are found. + """ + + # This will fail silently if we pass in the wrong kind of parameter. + # To make debugging easier add an explicit check. + if not isinstance(headers, httplib.HTTPMessage): + raise TypeError('expected httplib.Message, got {0}.'.format( + type(headers))) + + defects = getattr(headers, 'defects', None) + get_payload = getattr(headers, 'get_payload', None) + + unparsed_data = None + if get_payload: # Platform-specific: Python 3. + unparsed_data = get_payload() + + if defects or unparsed_data: + raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) + + +def is_response_to_head(response): + """ + Checks whether the request of a response has been a HEAD-request. + Handles the quirks of AppEngine. + + :param conn: + :type conn: :class:`httplib.HTTPResponse` + """ + # FIXME: Can we do this somehow without accessing private httplib _method? + method = response._method + if isinstance(method, int): # Platform-specific: Appengine + return method == 3 + return method.upper() == 'HEAD' diff --git a/pipenv/vendor/requests/packages/urllib3/util/retry.py b/pipenv/vendor/requests/packages/urllib3/util/retry.py new file mode 100644 index 00000000..c9e7d287 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/retry.py @@ -0,0 +1,389 @@ +from __future__ import absolute_import +import time +import logging +from collections import namedtuple +from itertools import takewhile +import email +import re + +from ..exceptions import ( + ConnectTimeoutError, + MaxRetryError, + ProtocolError, + ReadTimeoutError, + ResponseError, + InvalidHeader, +) +from ..packages import six + + +log = logging.getLogger(__name__) + +# Data structure for representing the metadata of requests that result in a retry. +RequestHistory = namedtuple('RequestHistory', ["method", "url", "error", + "status", "redirect_location"]) + + +class Retry(object): + """ Retry configuration. + + Each retry attempt will create a new Retry object with updated values, so + they can be safely reused. + + Retries can be defined as a default for a pool:: + + retries = Retry(connect=5, read=2, redirect=5) + http = PoolManager(retries=retries) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', retries=Retry(10)) + + Retries can be disabled by passing ``False``:: + + response = http.request('GET', 'http://example.com/', retries=False) + + Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless + retries are disabled, in which case the causing exception will be raised. + + :param int total: + Total number of retries to allow. Takes precedence over other counts. + + Set to ``None`` to remove this constraint and fall back on other + counts. It's a good idea to set this to some sensibly-high value to + account for unexpected edge cases and avoid infinite retry loops. + + Set to ``0`` to fail on the first retry. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int connect: + How many connection-related errors to retry on. + + These are errors raised before the request is sent to the remote server, + which we assume has not triggered the server to process the request. + + Set to ``0`` to fail on the first retry of this type. + + :param int read: + How many times to retry on read errors. + + These errors are raised after the request was sent to the server, so the + request may have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + :param int redirect: + How many redirects to perform. Limit this to avoid infinite redirect + loops. + + A redirect is a HTTP response with a status code 301, 302, 303, 307 or + 308. + + Set to ``0`` to fail on the first retry of this type. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param iterable method_whitelist: + Set of uppercased HTTP method verbs that we should retry on. + + By default, we only retry on methods which are considered to be + idempotent (multiple requests with the same parameters end with the + same state). See :attr:`Retry.DEFAULT_METHOD_WHITELIST`. + + Set to a ``False`` value to retry on any verb. + + :param iterable status_forcelist: + A set of integer HTTP status codes that we should force a retry on. + A retry is initiated if the request method is in ``method_whitelist`` + and the response status code is in ``status_forcelist``. + + By default, this is disabled with ``None``. + + :param float backoff_factor: + A backoff factor to apply between attempts after the second try + (most errors are resolved immediately by a second try without a + delay). urllib3 will sleep for:: + + {backoff factor} * (2 ^ ({number of total retries} - 1)) + + seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep + for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer + than :attr:`Retry.BACKOFF_MAX`. + + By default, backoff is disabled (set to 0). + + :param bool raise_on_redirect: Whether, if the number of redirects is + exhausted, to raise a MaxRetryError, or to return a response with a + response code in the 3xx range. + + :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: + whether we should raise an exception, or return a response, + if status falls in ``status_forcelist`` range and retries have + been exhausted. + + :param tuple history: The history of the request encountered during + each call to :meth:`~Retry.increment`. The list is in the order + the requests occurred. Each list item is of class :class:`RequestHistory`. + + :param bool respect_retry_after_header: + Whether to respect Retry-After header on status codes defined as + :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. + + """ + + DEFAULT_METHOD_WHITELIST = frozenset([ + 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) + + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 + + def __init__(self, total=10, connect=None, read=None, redirect=None, + method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, + backoff_factor=0, raise_on_redirect=True, raise_on_status=True, + history=None, respect_retry_after_header=True): + + self.total = total + self.connect = connect + self.read = read + + if redirect is False or total is False: + redirect = 0 + raise_on_redirect = False + + self.redirect = redirect + self.status_forcelist = status_forcelist or set() + self.method_whitelist = method_whitelist + self.backoff_factor = backoff_factor + self.raise_on_redirect = raise_on_redirect + self.raise_on_status = raise_on_status + self.history = history or tuple() + self.respect_retry_after_header = respect_retry_after_header + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, read=self.read, redirect=self.redirect, + method_whitelist=self.method_whitelist, + status_forcelist=self.status_forcelist, + backoff_factor=self.backoff_factor, + raise_on_redirect=self.raise_on_redirect, + raise_on_status=self.raise_on_status, + history=self.history, + ) + params.update(kw) + return type(self)(**params) + + @classmethod + def from_int(cls, retries, redirect=True, default=None): + """ Backwards-compatibility for the old retries format.""" + if retries is None: + retries = default if default is not None else cls.DEFAULT + + if isinstance(retries, Retry): + return retries + + redirect = bool(redirect) and None + new_retries = cls(retries, redirect=redirect) + log.debug("Converted retries value: %r -> %r", retries, new_retries) + return new_retries + + def get_backoff_time(self): + """ Formula for computing the current backoff + + :rtype: float + """ + # We want to consider only the last consecutive errors sequence (Ignore redirects). + consecutive_errors_len = len(list(takewhile(lambda x: x.redirect_location is None, + reversed(self.history)))) + if consecutive_errors_len <= 1: + return 0 + + backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) + return min(self.BACKOFF_MAX, backoff_value) + + def parse_retry_after(self, retry_after): + # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = int(retry_after) + else: + retry_date_tuple = email.utils.parsedate(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + retry_date = time.mktime(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + def get_retry_after(self, response): + """ Get the value of Retry-After in seconds. """ + + retry_after = response.getheader("Retry-After") + + if retry_after is None: + return None + + return self.parse_retry_after(retry_after) + + def sleep_for_retry(self, response=None): + retry_after = self.get_retry_after(response) + if retry_after: + time.sleep(retry_after) + return True + + return False + + def _sleep_backoff(self): + backoff = self.get_backoff_time() + if backoff <= 0: + return + time.sleep(backoff) + + def sleep(self, response=None): + """ Sleep between retry attempts. + + This method will respect a server's ``Retry-After`` response header + and sleep the duration of the time requested. If that is not present, it + will use an exponential backoff. By default, the backoff factor is 0 and + this method will return immediately. + """ + + if response: + slept = self.sleep_for_retry(response) + if slept: + return + + self._sleep_backoff() + + def _is_connection_error(self, err): + """ Errors when we're fairly sure that the server did not receive the + request, so it should be safe to retry. + """ + return isinstance(err, ConnectTimeoutError) + + def _is_read_error(self, err): + """ Errors that occur after the request has been started, so we should + assume that the server began processing it. + """ + return isinstance(err, (ReadTimeoutError, ProtocolError)) + + def _is_method_retryable(self, method): + """ Checks if a given HTTP method should be retried upon, depending if + it is included on the method whitelist. + """ + if self.method_whitelist and method.upper() not in self.method_whitelist: + return False + + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """ Is this method/status code retryable? (Based on whitelists and control + variables such as the number of total retries to allow, whether to + respect the Retry-After header, whether this header is present, and + whether the returned status code is on the list of status codes to + be retried upon on the presence of the aforementioned header) + """ + if not self._is_method_retryable(method): + return False + + if self.status_forcelist and status_code in self.status_forcelist: + return True + + return (self.total and self.respect_retry_after_header and + has_retry_after and (status_code in self.RETRY_AFTER_STATUS_CODES)) + + def is_exhausted(self): + """ Are we out of retries? """ + retry_counts = (self.total, self.connect, self.read, self.redirect) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + + return min(retry_counts) < 0 + + def increment(self, method=None, url=None, response=None, error=None, + _pool=None, _stacktrace=None): + """ Return a new Retry object with incremented retry counters. + + :param response: A response object, or None, if the server did not + return a response. + :type response: :class:`~urllib3.response.HTTPResponse` + :param Exception error: An error encountered during the request, or + None if the response was received successfully. + + :return: A new ``Retry`` object. + """ + if self.total is False and error: + # Disabled, indicate to re-raise the error. + raise six.reraise(type(error), error, _stacktrace) + + total = self.total + if total is not None: + total -= 1 + + connect = self.connect + read = self.read + redirect = self.redirect + cause = 'unknown' + status = None + redirect_location = None + + if error and self._is_connection_error(error): + # Connect retry? + if connect is False: + raise six.reraise(type(error), error, _stacktrace) + elif connect is not None: + connect -= 1 + + elif error and self._is_read_error(error): + # Read retry? + if read is False or not self._is_method_retryable(method): + raise six.reraise(type(error), error, _stacktrace) + elif read is not None: + read -= 1 + + elif response and response.get_redirect_location(): + # Redirect retry? + if redirect is not None: + redirect -= 1 + cause = 'too many redirects' + redirect_location = response.get_redirect_location() + status = response.status + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and a the given method is in the whitelist + cause = ResponseError.GENERIC_ERROR + if response and response.status: + cause = ResponseError.SPECIFIC_ERROR.format( + status_code=response.status) + status = response.status + + history = self.history + (RequestHistory(method, url, error, status, redirect_location),) + + new_retry = self.new( + total=total, + connect=connect, read=read, redirect=redirect, + history=history) + + if new_retry.is_exhausted(): + raise MaxRetryError(_pool, url, error or ResponseError(cause)) + + log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) + + return new_retry + + def __repr__(self): + return ('{cls.__name__}(total={self.total}, connect={self.connect}, ' + 'read={self.read}, redirect={self.redirect})').format( + cls=type(self), self=self) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/pipenv/vendor/requests/packages/urllib3/util/selectors.py b/pipenv/vendor/requests/packages/urllib3/util/selectors.py new file mode 100644 index 00000000..51208b69 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/selectors.py @@ -0,0 +1,524 @@ +# Backport of selectors.py from Python 3.5+ to support Python < 3.4 +# Also has the behavior specified in PEP 475 which is to retry syscalls +# in the case of an EINTR error. This module is required because selectors34 +# does not follow this behavior and instead returns that no dile descriptor +# events have occurred rather than retry the syscall. The decision to drop +# support for select.devpoll is made to maintain 100% test coverage. + +import errno +import math +import select +from collections import namedtuple, Mapping + +import time +try: + monotonic = time.monotonic +except (AttributeError, ImportError): # Python 3.3< + monotonic = time.time + +EVENT_READ = (1 << 0) +EVENT_WRITE = (1 << 1) + +HAS_SELECT = True # Variable that shows whether the platform has a selector. +_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. + + +class SelectorError(Exception): + def __init__(self, errcode): + super(SelectorError, self).__init__() + self.errno = errcode + + def __repr__(self): + return "".format(self.errno) + + def __str__(self): + return self.__repr__() + + +def _fileobj_to_fd(fileobj): + """ Return a file descriptor from a file object. If + given an integer will simply return that integer back. """ + if isinstance(fileobj, int): + fd = fileobj + else: + try: + fd = int(fileobj.fileno()) + except (AttributeError, TypeError, ValueError): + raise ValueError("Invalid file object: {0!r}".format(fileobj)) + if fd < 0: + raise ValueError("Invalid file descriptor: {0}".format(fd)) + return fd + + +def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): + """ Wrapper function for syscalls that could fail due to EINTR. + All functions should be retried if there is time left in the timeout + in accordance with PEP 475. """ + timeout = kwargs.get("timeout", None) + if timeout is None: + expires = None + recalc_timeout = False + else: + timeout = float(timeout) + if timeout < 0.0: # Timeout less than 0 treated as no timeout. + expires = None + else: + expires = monotonic() + timeout + + args = list(args) + if recalc_timeout and "timeout" not in kwargs: + raise ValueError( + "Timeout must be in args or kwargs to be recalculated") + + result = _SYSCALL_SENTINEL + while result is _SYSCALL_SENTINEL: + try: + result = func(*args, **kwargs) + # OSError is thrown by select.select + # IOError is thrown by select.epoll.poll + # select.error is thrown by select.poll.poll + # Aren't we thankful for Python 3.x rework for exceptions? + except (OSError, IOError, select.error) as e: + # select.error wasn't a subclass of OSError in the past. + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + elif hasattr(e, "args"): + errcode = e.args[0] + + # Also test for the Windows equivalent of EINTR. + is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and + errcode == errno.WSAEINTR)) + + if is_interrupt: + if expires is not None: + current_time = monotonic() + if current_time > expires: + raise OSError(errno=errno.ETIMEDOUT) + if recalc_timeout: + if "timeout" in kwargs: + kwargs["timeout"] = expires - current_time + continue + if errcode: + raise SelectorError(errcode) + else: + raise + return result + + +SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) + + +class _SelectorMapping(Mapping): + """ Mapping of file objects to selector keys """ + + def __init__(self, selector): + self._selector = selector + + def __len__(self): + return len(self._selector._fd_to_key) + + def __getitem__(self, fileobj): + try: + fd = self._selector._fileobj_lookup(fileobj) + return self._selector._fd_to_key[fd] + except KeyError: + raise KeyError("{0!r} is not registered.".format(fileobj)) + + def __iter__(self): + return iter(self._selector._fd_to_key) + + +class BaseSelector(object): + """ Abstract Selector class + + A selector supports registering file objects to be monitored + for specific I/O events. + + A file object is a file descriptor or any object with a + `fileno()` method. An arbitrary object can be attached to the + file object which can be used for example to store context info, + a callback, etc. + + A selector can use various implementations (select(), poll(), epoll(), + and kqueue()) depending on the platform. The 'DefaultSelector' class uses + the most efficient implementation for the current platform. + """ + def __init__(self): + # Maps file descriptors to keys. + self._fd_to_key = {} + + # Read-only mapping returned by get_map() + self._map = _SelectorMapping(self) + + def _fileobj_lookup(self, fileobj): + """ Return a file descriptor from a file object. + This wraps _fileobj_to_fd() to do an exhaustive + search in case the object is invalid but we still + have it in our map. Used by unregister() so we can + unregister an object that was previously registered + even if it is closed. It is also used by _SelectorMapping + """ + try: + return _fileobj_to_fd(fileobj) + except ValueError: + + # Search through all our mapped keys. + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + return key.fd + + # Raise ValueError after all. + raise + + def register(self, fileobj, events, data=None): + """ Register a file object for a set of events to monitor. """ + if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): + raise ValueError("Invalid events: {0!r}".format(events)) + + key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) + + if key.fd in self._fd_to_key: + raise KeyError("{0!r} (FD {1}) is already registered" + .format(fileobj, key.fd)) + + self._fd_to_key[key.fd] = key + return key + + def unregister(self, fileobj): + """ Unregister a file object from being monitored. """ + try: + key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + return key + + def modify(self, fileobj, events, data=None): + """ Change a registered file object monitored events and data. """ + # NOTE: Some subclasses optimize this operation even further. + try: + key = self._fd_to_key[self._fileobj_lookup(fileobj)] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + if events != key.events: + self.unregister(fileobj) + key = self.register(fileobj, events, data) + + elif data != key.data: + # Use a shortcut to update the data. + key = key._replace(data=data) + self._fd_to_key[key.fd] = key + + return key + + def select(self, timeout=None): + """ Perform the actual selection until some monitored file objects + are ready or the timeout expires. """ + raise NotImplementedError() + + def close(self): + """ Close the selector. This must be called to ensure that all + underlying resources are freed. """ + self._fd_to_key.clear() + self._map = None + + def get_key(self, fileobj): + """ Return the key associated with a registered file object. """ + mapping = self.get_map() + if mapping is None: + raise RuntimeError("Selector is closed") + try: + return mapping[fileobj] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + def get_map(self): + """ Return a mapping of file objects to selector keys """ + return self._map + + def _key_from_fd(self, fd): + """ Return the key associated to a given file descriptor + Return None if it is not found. """ + try: + return self._fd_to_key[fd] + except KeyError: + return None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + +# Almost all platforms have select.select() +if hasattr(select, "select"): + class SelectSelector(BaseSelector): + """ Select-based selector. """ + def __init__(self): + super(SelectSelector, self).__init__() + self._readers = set() + self._writers = set() + + def register(self, fileobj, events, data=None): + key = super(SelectSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + self._readers.add(key.fd) + if events & EVENT_WRITE: + self._writers.add(key.fd) + return key + + def unregister(self, fileobj): + key = super(SelectSelector, self).unregister(fileobj) + self._readers.discard(key.fd) + self._writers.discard(key.fd) + return key + + def _select(self, r, w, timeout=None): + """ Wrapper for select.select because timeout is a positional arg """ + return select.select(r, w, [], timeout) + + def select(self, timeout=None): + # Selecting on empty lists on Windows errors out. + if not len(self._readers) and not len(self._writers): + return [] + + timeout = None if timeout is None else max(timeout, 0.0) + ready = [] + r, w, _ = _syscall_wrapper(self._select, True, self._readers, + self._writers, timeout) + r = set(r) + w = set(w) + for fd in r | w: + events = 0 + if fd in r: + events |= EVENT_READ + if fd in w: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + +if hasattr(select, "poll"): + class PollSelector(BaseSelector): + """ Poll-based selector """ + def __init__(self): + super(PollSelector, self).__init__() + self._poll = select.poll() + + def register(self, fileobj, events, data=None): + key = super(PollSelector, self).register(fileobj, events, data) + event_mask = 0 + if events & EVENT_READ: + event_mask |= select.POLLIN + if events & EVENT_WRITE: + event_mask |= select.POLLOUT + self._poll.register(key.fd, event_mask) + return key + + def unregister(self, fileobj): + key = super(PollSelector, self).unregister(fileobj) + self._poll.unregister(key.fd) + return key + + def _wrap_poll(self, timeout=None): + """ Wrapper function for select.poll.poll() so that + _syscall_wrapper can work with only seconds. """ + if timeout is not None: + if timeout <= 0: + timeout = 0 + else: + # select.poll.poll() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) + + result = self._poll.poll(timeout) + return result + + def select(self, timeout=None): + ready = [] + fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.POLLIN: + events |= EVENT_WRITE + if event_mask & ~select.POLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + + return ready + + +if hasattr(select, "epoll"): + class EpollSelector(BaseSelector): + """ Epoll-based selector """ + def __init__(self): + super(EpollSelector, self).__init__() + self._epoll = select.epoll() + + def fileno(self): + return self._epoll.fileno() + + def register(self, fileobj, events, data=None): + key = super(EpollSelector, self).register(fileobj, events, data) + events_mask = 0 + if events & EVENT_READ: + events_mask |= select.EPOLLIN + if events & EVENT_WRITE: + events_mask |= select.EPOLLOUT + _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) + return key + + def unregister(self, fileobj): + key = super(EpollSelector, self).unregister(fileobj) + try: + _syscall_wrapper(self._epoll.unregister, False, key.fd) + except SelectorError: + # This can occur when the fd was closed since registry. + pass + return key + + def select(self, timeout=None): + if timeout is not None: + if timeout <= 0: + timeout = 0.0 + else: + # select.epoll.poll() has a resolution of 1 millisecond + # but luckily takes seconds so we don't need a wrapper + # like PollSelector. Just for better rounding. + timeout = math.ceil(timeout * 1e3) * 1e-3 + timeout = float(timeout) + else: + timeout = -1.0 # epoll.poll() must have a float. + + # We always want at least 1 to ensure that select can be called + # with no file descriptors registered. Otherwise will fail. + max_events = max(len(self._fd_to_key), 1) + + ready = [] + fd_events = _syscall_wrapper(self._epoll.poll, True, + timeout=timeout, + maxevents=max_events) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.EPOLLIN: + events |= EVENT_WRITE + if event_mask & ~select.EPOLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + def close(self): + self._epoll.close() + super(EpollSelector, self).close() + + +if hasattr(select, "kqueue"): + class KqueueSelector(BaseSelector): + """ Kqueue / Kevent-based selector """ + def __init__(self): + super(KqueueSelector, self).__init__() + self._kqueue = select.kqueue() + + def fileno(self): + return self._kqueue.fileno() + + def register(self, fileobj, events, data=None): + key = super(KqueueSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + if events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + return key + + def unregister(self, fileobj): + key = super(KqueueSelector, self).unregister(fileobj) + if key.events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + if key.events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + + return key + + def select(self, timeout=None): + if timeout is not None: + timeout = max(timeout, 0) + + max_events = len(self._fd_to_key) * 2 + ready_fds = {} + + kevent_list = _syscall_wrapper(self._kqueue.control, True, + None, max_events, timeout) + + for kevent in kevent_list: + fd = kevent.ident + event_mask = kevent.filter + events = 0 + if event_mask == select.KQ_FILTER_READ: + events |= EVENT_READ + if event_mask == select.KQ_FILTER_WRITE: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + if key.fd not in ready_fds: + ready_fds[key.fd] = (key, events & key.events) + else: + old_events = ready_fds[key.fd][1] + ready_fds[key.fd] = (key, (events | old_events) & key.events) + + return list(ready_fds.values()) + + def close(self): + self._kqueue.close() + super(KqueueSelector, self).close() + + +# Choose the best implementation, roughly: +# kqueue == epoll > poll > select. Devpoll not supported. (See above) +# select() also can't accept a FD > FD_SETSIZE (usually around 1024) +if 'KqueueSelector' in globals(): # Platform-specific: Mac OS and BSD + DefaultSelector = KqueueSelector +elif 'EpollSelector' in globals(): # Platform-specific: Linux + DefaultSelector = EpollSelector +elif 'PollSelector' in globals(): # Platform-specific: Linux + DefaultSelector = PollSelector +elif 'SelectSelector' in globals(): # Platform-specific: Windows + DefaultSelector = SelectSelector +else: # Platform-specific: AppEngine + def no_selector(_): + raise ValueError("Platform does not have a selector") + DefaultSelector = no_selector + HAS_SELECT = False diff --git a/pipenv/vendor/requests/packages/urllib3/util/ssl_.py b/pipenv/vendor/requests/packages/urllib3/util/ssl_.py new file mode 100644 index 00000000..c4c55df6 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/ssl_.py @@ -0,0 +1,336 @@ +from __future__ import absolute_import +import errno +import warnings +import hmac + +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning + + +SSLContext = None +HAS_SNI = False +IS_PYOPENSSL = False + +# Maps the length of a digest to a possible hash function producing this digest +HASHFUNC_MAP = { + 32: md5, + 40: sha1, + 64: sha256, +} + + +def _const_compare_digest_backport(a, b): + """ + Compare two digests of equal length in constant time. + + The digests must be of type str/bytes. + Returns True if the digests match, and False otherwise. + """ + result = abs(len(a) - len(b)) + for l, r in zip(bytearray(a), bytearray(b)): + result |= l ^ r + return result == 0 + + +_const_compare_digest = getattr(hmac, 'compare_digest', + _const_compare_digest_backport) + + +try: # Test for SSL features + import ssl + from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23 + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + + +try: + from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs and DSS for security reasons. +DEFAULT_CIPHERS = ':'.join([ + 'ECDH+AESGCM', + 'ECDH+CHACHA20', + 'DH+AESGCM', + 'DH+CHACHA20', + 'ECDH+AES256', + 'DH+AES256', + 'ECDH+AES128', + 'DH+AES', + 'RSA+AESGCM', + 'RSA+AES', + '!aNULL', + '!eNULL', + '!MD5', +]) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + import sys + + class SSLContext(object): # Platform-specific: Python 2 & 3.1 + supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or + (3, 2) <= sys.version_info) + + def __init__(self, protocol_version): + self.protocol = protocol_version + # Use default values from a real SSLContext + self.check_hostname = False + self.verify_mode = ssl.CERT_NONE + self.ca_certs = None + self.options = 0 + self.certfile = None + self.keyfile = None + self.ciphers = None + + def load_cert_chain(self, certfile, keyfile): + self.certfile = certfile + self.keyfile = keyfile + + def load_verify_locations(self, cafile=None, capath=None): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + if not self.supports_set_ciphers: + raise TypeError( + 'Your version of Python does not support setting ' + 'a custom cipher suite. Please upgrade to Python ' + '2.7, 3.2, or later if you need this functionality.' + ) + self.ciphers = cipher_suite + + def wrap_socket(self, socket, server_hostname=None, server_side=False): + warnings.warn( + 'A true SSLContext object is not available. This prevents ' + 'urllib3 from configuring SSL appropriately and may cause ' + 'certain SSL connections to fail. You can upgrade to a newer ' + 'version of Python to solve this. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings', + InsecurePlatformWarning + ) + kwargs = { + 'keyfile': self.keyfile, + 'certfile': self.certfile, + 'ca_certs': self.ca_certs, + 'cert_reqs': self.verify_mode, + 'ssl_version': self.protocol, + 'server_side': server_side, + } + if self.supports_set_ciphers: # Platform-specific: Python 2.7+ + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + else: # Platform-specific: Python 2.6 + return wrap_socket(socket, **kwargs) + + +def assert_fingerprint(cert, fingerprint): + """ + Checks if given fingerprint matches the supplied certificate. + + :param cert: + Certificate as bytes object. + :param fingerprint: + Fingerprint as string of hexdigits, can be interspersed by colons. + """ + + fingerprint = fingerprint.replace(':', '').lower() + digest_length = len(fingerprint) + hashfunc = HASHFUNC_MAP.get(digest_length) + if not hashfunc: + raise SSLError( + 'Fingerprint of invalid length: {0}'.format(fingerprint)) + + # We need encode() here for py32; works on py2 and p33. + fingerprint_bytes = unhexlify(fingerprint.encode()) + + cert_digest = hashfunc(cert).digest() + + if not _const_compare_digest(cert_digest, fingerprint_bytes): + raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".' + .format(fingerprint, hexlify(cert_digest))) + + +def resolve_cert_reqs(candidate): + """ + Resolves the argument to a numeric constant, which can be passed to + the wrap_socket function/method from the ssl module. + Defaults to :data:`ssl.CERT_NONE`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbrevation. + (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. + If it's neither `None` nor a string we assume it is already the numeric + constant which can directly be passed to wrap_socket. + """ + if candidate is None: + return CERT_NONE + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, 'CERT_' + candidate) + return res + + return candidate + + +def resolve_ssl_version(candidate): + """ + like resolve_cert_reqs + """ + if candidate is None: + return PROTOCOL_SSLv23 + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, 'PROTOCOL_' + candidate) + return res + + return candidate + + +def create_urllib3_context(ssl_version=None, cert_reqs=None, + options=None, ciphers=None): + """All arguments have the same meaning as ``ssl_wrap_socket``. + + By default, this function does a lot of the same work that + ``ssl.create_default_context`` does on Python 3.4+. It: + + - Disables SSLv2, SSLv3, and compression + - Sets a restricted set of server ciphers + + If you wish to enable SSLv3, you can do:: + + from urllib3.util import ssl_ + context = ssl_.create_urllib3_context() + context.options &= ~ssl_.OP_NO_SSLv3 + + You can do the same to enable compression (substituting ``COMPRESSION`` + for ``SSLv3`` in the last line above). + + :param ssl_version: + The desired protocol version to use. This will default to + PROTOCOL_SSLv23 which will negotiate the highest protocol that both + the server and your installation of OpenSSL support. + :param cert_reqs: + Whether to require the certificate verification. This defaults to + ``ssl.CERT_REQUIRED``. + :param options: + Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, + ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) + + # Setting the default here, as we may have no ssl module on import + cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs + + if options is None: + options = 0 + # SSLv2 is easily broken and is considered harmful and dangerous + options |= OP_NO_SSLv2 + # SSLv3 has several problems and is now dangerous + options |= OP_NO_SSLv3 + # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ + # (issue #309) + options |= OP_NO_COMPRESSION + + context.options |= options + + if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6 + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + context.verify_mode = cert_reqs + if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2 + # We do our own verification, including fingerprints and alternative + # hostnames. So disable it here + context.check_hostname = False + return context + + +def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, + ca_certs=None, server_hostname=None, + ssl_version=None, ciphers=None, ssl_context=None, + ca_cert_dir=None): + """ + All arguments except for server_hostname, ssl_context, and ca_cert_dir have + the same meaning as they do when using :func:`ssl.wrap_socket`. + + :param server_hostname: + When SNI is supported, the expected hostname of the certificate + :param ssl_context: + A pre-made :class:`SSLContext` object. If none is provided, one will + be created using :func:`create_urllib3_context`. + :param ciphers: + A string of ciphers we wish the client to support. This is not + supported on Python 2.6 as the ssl module does not support it. + :param ca_cert_dir: + A directory containing CA certificates in multiple separate files, as + supported by OpenSSL's -CApath flag or the capath argument to + SSLContext.load_verify_locations(). + """ + context = ssl_context + if context is None: + # Note: This branch of code and all the variables in it are no longer + # used by urllib3 itself. We should consider deprecating and removing + # this code. + context = create_urllib3_context(ssl_version, cert_reqs, + ciphers=ciphers) + + if ca_certs or ca_cert_dir: + try: + context.load_verify_locations(ca_certs, ca_cert_dir) + except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2 + raise SSLError(e) + # Py33 raises FileNotFoundError which subclasses OSError + # These are not equivalent unless we check the errno attribute + except OSError as e: # Platform-specific: Python 3.3 and beyond + if e.errno == errno.ENOENT: + raise SSLError(e) + raise + elif getattr(context, 'load_default_certs', None) is not None: + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + if certfile: + context.load_cert_chain(certfile, keyfile) + if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI + return context.wrap_socket(sock, server_hostname=server_hostname) + + warnings.warn( + 'An HTTPS request has been made, but the SNI (Subject Name ' + 'Indication) extension to TLS is not available on this platform. ' + 'This may cause the server to present an incorrect TLS ' + 'certificate, which can cause validation failures. You can upgrade to ' + 'a newer version of Python to solve this. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings', + SNIMissingWarning + ) + return context.wrap_socket(sock) diff --git a/pipenv/vendor/requests/packages/urllib3/util/timeout.py b/pipenv/vendor/requests/packages/urllib3/util/timeout.py new file mode 100644 index 00000000..cec817e6 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/timeout.py @@ -0,0 +1,242 @@ +from __future__ import absolute_import +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT +import time + +from ..exceptions import TimeoutStateError + +# A sentinel value to indicate that no timeout was specified by the user in +# urllib3 +_Default = object() + + +# Use time.monotonic if available. +current_time = getattr(time, "monotonic", time.time) + + +class Timeout(object): + """ Timeout configuration. + + Timeouts can be defined as a default for a pool:: + + timeout = Timeout(connect=2.0, read=7.0) + http = PoolManager(timeout=timeout) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``:: + + no_timeout = Timeout(connect=None, read=None) + response = http.request('GET', 'http://example.com/, timeout=no_timeout) + + + :param total: + This combines the connect and read timeouts into one; the read timeout + will be set to the time leftover from the connect attempt. In the + event that both a connect timeout and a total are specified, or a read + timeout and a total are specified, the shorter timeout will be applied. + + Defaults to None. + + :type total: integer, float, or None + + :param connect: + The maximum amount of time to wait for a connection attempt to a server + to succeed. Omitting the parameter will default the connect timeout to + the system default, probably `the global default timeout in socket.py + `_. + None will set an infinite timeout for connection attempts. + + :type connect: integer, float, or None + + :param read: + The maximum amount of time to wait between consecutive + read operations for a response from the server. Omitting + the parameter will default the read timeout to the system + default, probably `the global default timeout in socket.py + `_. + None will set an infinite timeout. + + :type read: integer, float, or None + + .. note:: + + Many factors can affect the total amount of time for urllib3 to return + an HTTP response. + + For example, Python's DNS resolver does not obey the timeout specified + on the socket. Other factors that can affect total request time include + high CPU load, high swap, the program running at a low priority level, + or other behaviors. + + In addition, the read and total timeouts only measure the time between + read operations on the socket connecting the client and the server, + not the total amount of time for the request to return a complete + response. For most requests, the timeout is raised because the server + has not sent the first byte in the specified time. This is not always + the case; if a server streams one byte every fifteen seconds, a timeout + of 20 seconds will not trigger, even though the request will take + several minutes to complete. + + If your goal is to cut off any request after a set amount of wall clock + time, consider having a second "watcher" thread to cut off a slow + request. + """ + + #: A sentinel object representing the default timeout value + DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT + + def __init__(self, total=None, connect=_Default, read=_Default): + self._connect = self._validate_timeout(connect, 'connect') + self._read = self._validate_timeout(read, 'read') + self.total = self._validate_timeout(total, 'total') + self._start_connect = None + + def __str__(self): + return '%s(connect=%r, read=%r, total=%r)' % ( + type(self).__name__, self._connect, self._read, self.total) + + @classmethod + def _validate_timeout(cls, value, name): + """ Check that a timeout attribute is valid. + + :param value: The timeout value to validate + :param name: The name of the timeout attribute to validate. This is + used to specify in error messages. + :return: The validated and casted version of the given value. + :raises ValueError: If it is a numeric value less than or equal to + zero, or the type is not an integer, float, or None. + """ + if value is _Default: + return cls.DEFAULT_TIMEOUT + + if value is None or value is cls.DEFAULT_TIMEOUT: + return value + + if isinstance(value, bool): + raise ValueError("Timeout cannot be a boolean value. It must " + "be an int, float or None.") + try: + float(value) + except (TypeError, ValueError): + raise ValueError("Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value)) + + try: + if value <= 0: + raise ValueError("Attempted to set %s timeout to %s, but the " + "timeout cannot be set to a value less " + "than or equal to 0." % (name, value)) + except TypeError: # Python 3 + raise ValueError("Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value)) + + return value + + @classmethod + def from_float(cls, timeout): + """ Create a new Timeout from a legacy timeout value. + + The timeout value used by httplib.py sets the same timeout on the + connect(), and recv() socket requests. This creates a :class:`Timeout` + object that sets the individual timeouts to the ``timeout`` value + passed to this function. + + :param timeout: The legacy timeout value. + :type timeout: integer, float, sentinel default object, or None + :return: Timeout object + :rtype: :class:`Timeout` + """ + return Timeout(read=timeout, connect=timeout) + + def clone(self): + """ Create a copy of the timeout object + + Timeout properties are stored per-pool but each request needs a fresh + Timeout object to ensure each one has its own start/stop configured. + + :return: a copy of the timeout object + :rtype: :class:`Timeout` + """ + # We can't use copy.deepcopy because that will also create a new object + # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to + # detect the user default. + return Timeout(connect=self._connect, read=self._read, + total=self.total) + + def start_connect(self): + """ Start the timeout clock, used during a connect() attempt + + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to start a timer that has been started already. + """ + if self._start_connect is not None: + raise TimeoutStateError("Timeout timer has already been started.") + self._start_connect = current_time() + return self._start_connect + + def get_connect_duration(self): + """ Gets the time elapsed since the call to :meth:`start_connect`. + + :return: Elapsed time. + :rtype: float + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to get duration for a timer that hasn't been started. + """ + if self._start_connect is None: + raise TimeoutStateError("Can't get connect duration for timer " + "that has not started.") + return current_time() - self._start_connect + + @property + def connect_timeout(self): + """ Get the value to use when setting a connection timeout. + + This will be a positive float or integer, the value None + (never timeout), or the default system timeout. + + :return: Connect timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + """ + if self.total is None: + return self._connect + + if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: + return self.total + + return min(self._connect, self.total) + + @property + def read_timeout(self): + """ Get the value for the read timeout. + + This assumes some time has elapsed in the connection timeout and + computes the read timeout appropriately. + + If self.total is set, the read timeout is dependent on the amount of + time taken by the connect timeout. If the connection time has not been + established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be + raised. + + :return: Value to use for the read timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` + has not yet been called on this object. + """ + if (self.total is not None and + self.total is not self.DEFAULT_TIMEOUT and + self._read is not None and + self._read is not self.DEFAULT_TIMEOUT): + # In case the connect timeout has not yet been established. + if self._start_connect is None: + return self._read + return max(0, min(self.total - self.get_connect_duration(), + self._read)) + elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: + return max(0, self.total - self.get_connect_duration()) + else: + return self._read diff --git a/pipenv/vendor/requests/packages/urllib3/util/url.py b/pipenv/vendor/requests/packages/urllib3/util/url.py new file mode 100644 index 00000000..61a326e4 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/url.py @@ -0,0 +1,226 @@ +from __future__ import absolute_import +from collections import namedtuple + +from ..exceptions import LocationParseError + + +url_attrs = ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'] + + +class Url(namedtuple('Url', url_attrs)): + """ + Datastructure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. Both the scheme and host are normalized as they are + both case-insensitive according to RFC 3986. + """ + __slots__ = () + + def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, + query=None, fragment=None): + if path and not path.startswith('/'): + path = '/' + path + if scheme: + scheme = scheme.lower() + if host: + host = host.lower() + return super(Url, cls).__new__(cls, scheme, auth, host, port, path, + query, fragment) + + @property + def hostname(self): + """For backwards-compatibility with urlparse. We're nice like that.""" + return self.host + + @property + def request_uri(self): + """Absolute path including the query string.""" + uri = self.path or '/' + + if self.query is not None: + uri += '?' + self.query + + return uri + + @property + def netloc(self): + """Network location including host and port""" + if self.port: + return '%s:%d' % (self.host, self.port) + return self.host + + @property + def url(self): + """ + Convert self into a url + + This function should more or less round-trip with :func:`.parse_url`. The + returned url may not be exactly the same as the url inputted to + :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls + with a blank port will have : removed). + + Example: :: + + >>> U = parse_url('http://google.com/mail/') + >>> U.url + 'http://google.com/mail/' + >>> Url('http', 'username:password', 'host.com', 80, + ... '/path', 'query', 'fragment').url + 'http://username:password@host.com:80/path?query#fragment' + """ + scheme, auth, host, port, path, query, fragment = self + url = '' + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + '://' + if auth is not None: + url += auth + '@' + if host is not None: + url += host + if port is not None: + url += ':' + str(port) + if path is not None: + url += path + if query is not None: + url += '?' + query + if fragment is not None: + url += '#' + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, '', None + + return s[:min_idx], s[min_idx + 1:], min_delim + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/mail/', ...) + >>> parse_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> parse_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + + # While this code has overlap with stdlib's urlparse, it is much + # simplified for our needs and less annoying. + # Additionally, this implementations does silly things to be optimal + # on CPython. + + if not url: + # Empty + return Url() + + scheme = None + auth = None + host = None + port = None + path = None + fragment = None + query = None + + # Scheme + if '://' in url: + scheme, url = url.split('://', 1) + + # Find the earliest Authority Terminator + # (http://tools.ietf.org/html/rfc3986#section-3.2) + url, path_, delim = split_first(url, ['/', '?', '#']) + + if delim: + # Reassemble the path + path = delim + path_ + + # Auth + if '@' in url: + # Last '@' denotes end of auth part + auth, url = url.rsplit('@', 1) + + # IPv6 + if url and url[0] == '[': + host, url = url.split(']', 1) + host += ']' + + # Port + if ':' in url: + _host, port = url.split(':', 1) + + if not host: + host = _host + + if port: + # If given, ports must be integers. No whitespace, no plus or + # minus prefixes, no non-integer digits such as ^2 (superscript). + if not port.isdigit(): + raise LocationParseError(url) + try: + port = int(port) + except ValueError: + raise LocationParseError(url) + else: + # Blank ports are cool, too. (rfc3986#section-3.2.3) + port = None + + elif not host and url: + host = url + + if not path: + return Url(scheme, auth, host, port, path, query, fragment) + + # Fragment + if '#' in path: + path, fragment = path.split('#', 1) + + # Query + if '?' in path: + path, query = path.split('?', 1) + + return Url(scheme, auth, host, port, path, query, fragment) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or 'http', p.hostname, p.port diff --git a/pipenv/vendor/requests/packages/urllib3/util/wait.py b/pipenv/vendor/requests/packages/urllib3/util/wait.py new file mode 100644 index 00000000..cb396e50 --- /dev/null +++ b/pipenv/vendor/requests/packages/urllib3/util/wait.py @@ -0,0 +1,40 @@ +from .selectors import ( + HAS_SELECT, + DefaultSelector, + EVENT_READ, + EVENT_WRITE +) + + +def _wait_for_io_events(socks, events, timeout=None): + """ Waits for IO events to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be interacted with immediately. """ + if not HAS_SELECT: + raise ValueError('Platform does not have a selector') + if not isinstance(socks, list): + # Probably just a single socket. + if hasattr(socks, "fileno"): + socks = [socks] + # Otherwise it might be a non-list iterable. + else: + socks = list(socks) + with DefaultSelector() as selector: + for sock in socks: + selector.register(sock, events) + return [key[0].fileobj for key in + selector.select(timeout) if key[1] & events] + + +def wait_for_read(socks, timeout=None): + """ Waits for reading to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be read from immediately. """ + return _wait_for_io_events(socks, EVENT_READ, timeout) + + +def wait_for_write(socks, timeout=None): + """ Waits for writing to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be written to immediately. """ + return _wait_for_io_events(socks, EVENT_WRITE, timeout) diff --git a/pipenv/vendor/requests/sessions.py b/pipenv/vendor/requests/sessions.py new file mode 100644 index 00000000..7983282a --- /dev/null +++ b/pipenv/vendor/requests/sessions.py @@ -0,0 +1,725 @@ +# -*- coding: utf-8 -*- + +""" +requests.session +~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +from collections import Mapping +from datetime import datetime + +from .auth import _basic_auth_str +from .compat import cookielib, OrderedDict, urljoin, urlparse +from .cookies import ( + cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) +from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT +from .hooks import default_hooks, dispatch_hook +from ._internal_utils import to_native_string +from .utils import to_key_val_list, default_headers +from .exceptions import ( + TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) +from .packages.urllib3._collections import RecentlyUsedContainer +from .structures import CaseInsensitiveDict + +from .adapters import HTTPAdapter + +from .utils import ( + requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, + get_auth_from_url, rewind_body +) + +from .status_codes import codes + +# formerly defined here, reexposed here for backward compatibility +from .models import REDIRECT_STATI + +REDIRECT_CACHE_SIZE = 1000 + + +def merge_setting(request_setting, session_setting, dict_class=OrderedDict): + """Determines appropriate setting for a given request, taking into account + the explicit setting on that request, and the setting in the session. If a + setting is a dictionary, they will be merged together using `dict_class` + """ + + if session_setting is None: + return request_setting + + if request_setting is None: + return session_setting + + # Bypass if not a dictionary (e.g. verify) + if not ( + isinstance(session_setting, Mapping) and + isinstance(request_setting, Mapping) + ): + return request_setting + + merged_setting = dict_class(to_key_val_list(session_setting)) + merged_setting.update(to_key_val_list(request_setting)) + + # Remove keys that are set to None. Extract keys first to avoid altering + # the dictionary during iteration. + none_keys = [k for (k, v) in merged_setting.items() if v is None] + for key in none_keys: + del merged_setting[key] + + return merged_setting + + +def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): + """Properly merges both requests and session hooks. + + This is necessary because when request_hooks == {'response': []}, the + merge breaks Session hooks entirely. + """ + if session_hooks is None or session_hooks.get('response') == []: + return request_hooks + + if request_hooks is None or request_hooks.get('response') == []: + return session_hooks + + return merge_setting(request_hooks, session_hooks, dict_class) + + +class SessionRedirectMixin(object): + def resolve_redirects(self, resp, req, stream=False, timeout=None, + verify=True, cert=None, proxies=None, **adapter_kwargs): + """Receives a Response. Returns a generator of Responses.""" + + i = 0 + hist = [] # keep track of history + + while resp.is_redirect: + prepared_request = req.copy() + + if i > 0: + # Update history and keep track of redirects. + hist.append(resp) + new_hist = list(hist) + resp.history = new_hist + + try: + resp.content # Consume socket so it can be released + except (ChunkedEncodingError, ContentDecodingError, RuntimeError): + resp.raw.read(decode_content=False) + + if i >= self.max_redirects: + raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects, response=resp) + + # Release the connection back into the pool. + resp.close() + + url = resp.headers['location'] + + # Handle redirection without scheme (see: RFC 1808 Section 4) + if url.startswith('//'): + parsed_rurl = urlparse(resp.url) + url = '%s:%s' % (parsed_rurl.scheme, url) + + # The scheme should be lower case... + parsed = urlparse(url) + url = parsed.geturl() + + # Facilitate relative 'location' headers, as allowed by RFC 7231. + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') + # Compliant with RFC3986, we percent encode the url. + if not parsed.netloc: + url = urljoin(resp.url, requote_uri(url)) + else: + url = requote_uri(url) + + prepared_request.url = to_native_string(url) + # Cache the url, unless it redirects to itself. + if resp.is_permanent_redirect and req.url != prepared_request.url: + self.redirect_cache[req.url] = prepared_request.url + + self.rebuild_method(prepared_request, resp) + + # https://github.com/kennethreitz/requests/issues/1084 + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + # https://github.com/kennethreitz/requests/issues/3490 + purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding') + for header in purged_headers: + prepared_request.headers.pop(header, None) + prepared_request.body = None + + headers = prepared_request.headers + try: + del headers['Cookie'] + except KeyError: + pass + + # Extract any cookies sent on the response to the cookiejar + # in the new request. Because we've mutated our copied prepared + # request, use the old one that we haven't yet touched. + extract_cookies_to_jar(prepared_request._cookies, req, resp.raw) + merge_cookies(prepared_request._cookies, self.cookies) + prepared_request.prepare_cookies(prepared_request._cookies) + + # Rebuild auth and proxy information. + proxies = self.rebuild_proxies(prepared_request, proxies) + self.rebuild_auth(prepared_request, resp) + + # A failed tell() sets `_body_position` to `object()`. This non-None + # value ensures `rewindable` will be True, allowing us to raise an + # UnrewindableBodyError, instead of hanging the connection. + rewindable = ( + prepared_request._body_position is not None and + ('Content-Length' in headers or 'Transfer-Encoding' in headers) + ) + + # Attempt to rewind consumed file-like object. + if rewindable: + rewind_body(prepared_request) + + # Override the original request. + req = prepared_request + + resp = self.send( + req, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + allow_redirects=False, + **adapter_kwargs + ) + + extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) + + i += 1 + yield resp + + def rebuild_auth(self, prepared_request, response): + """When being redirected we may want to strip authentication from the + request to avoid leaking credentials. This method intelligently removes + and reapplies authentication where possible to avoid credential loss. + """ + headers = prepared_request.headers + url = prepared_request.url + + if 'Authorization' in headers: + # If we get redirected to a new host, we should strip out any + # authentication headers. + original_parsed = urlparse(response.request.url) + redirect_parsed = urlparse(url) + + if (original_parsed.hostname != redirect_parsed.hostname): + del headers['Authorization'] + + # .netrc might have more auth for us on our new host. + new_auth = get_netrc_auth(url) if self.trust_env else None + if new_auth is not None: + prepared_request.prepare_auth(new_auth) + + return + + def rebuild_proxies(self, prepared_request, proxies): + """This method re-evaluates the proxy configuration by considering the + environment variables. If we are redirected to a URL covered by + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing + proxy keys for this URL (in case they were stripped by a previous + redirect). + + This method also replaces the Proxy-Authorization header where + necessary. + + :rtype: dict + """ + headers = prepared_request.headers + url = prepared_request.url + scheme = urlparse(url).scheme + new_proxies = proxies.copy() if proxies is not None else {} + + if self.trust_env and not should_bypass_proxies(url): + environ_proxies = get_environ_proxies(url) + + proxy = environ_proxies.get(scheme, environ_proxies.get('all')) + + if proxy: + new_proxies.setdefault(scheme, proxy) + + if 'Proxy-Authorization' in headers: + del headers['Proxy-Authorization'] + + try: + username, password = get_auth_from_url(new_proxies[scheme]) + except KeyError: + username, password = None, None + + if username and password: + headers['Proxy-Authorization'] = _basic_auth_str(username, password) + + return new_proxies + + def rebuild_method(self, prepared_request, response): + """When being redirected we may want to change the method of the request + based on certain specs or browser behavior. + """ + method = prepared_request.method + + # http://tools.ietf.org/html/rfc7231#section-6.4.4 + if response.status_code == codes.see_other and method != 'HEAD': + method = 'GET' + + # Do what the browsers do, despite standards... + # First, turn 302s into GETs. + if response.status_code == codes.found and method != 'HEAD': + method = 'GET' + + # Second, if a POST is responded to with a 301, turn it into a GET. + # This bizarre behaviour is explained in Issue 1704. + if response.status_code == codes.moved and method == 'POST': + method = 'GET' + + prepared_request.method = method + + +class Session(SessionRedirectMixin): + """A Requests session. + + Provides cookie persistence, connection-pooling, and configuration. + + Basic Usage:: + + >>> import requests + >>> s = requests.Session() + >>> s.get('http://httpbin.org/get') + + + Or as a context manager:: + + >>> with requests.Session() as s: + >>> s.get('http://httpbin.org/get') + + """ + + __attrs__ = [ + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', + 'cert', 'prefetch', 'adapters', 'stream', 'trust_env', + 'max_redirects', + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request ` sent from this + #: :class:`Session `. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request `. + self.auth = None + + #: Dictionary mapping protocol or protocol and host to the URL of the proxy + #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to + #: be used on each :class:`Request `. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request `. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + self.verify = True + + #: SSL client certificate default. + self.cert = None + + #: Maximum number of redirects allowed. If the request exceeds this + #: limit, a :class:`TooManyRedirects` exception is raised. + #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is + #: 30. + self.max_redirects = DEFAULT_REDIRECT_LIMIT + + #: Trust environment settings for proxy configuration, default + #: authentication and similar. + self.trust_env = True + + #: A CookieJar containing all currently outstanding cookies set on this + #: session. By default it is a + #: :class:`RequestsCookieJar `, but + #: may be any other ``cookielib.CookieJar`` compatible object. + self.cookies = cookiejar_from_dict({}) + + # Default connection adapters. + self.adapters = OrderedDict() + self.mount('https://', HTTPAdapter()) + self.mount('http://', HTTPAdapter()) + + # Only store 1000 redirects to prevent using infinite memory + self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE) + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def prepare_request(self, request): + """Constructs a :class:`PreparedRequest ` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request ` instance and those of the + :class:`Session`. + + :param request: :class:`Request` instance to prepare with this + session's settings. + :rtype: requests.PreparedRequest + """ + cookies = request.cookies or {} + + # Bootstrap CookieJar. + if not isinstance(cookies, cookielib.CookieJar): + cookies = cookiejar_from_dict(cookies) + + # Merge with session cookies + merged_cookies = merge_cookies( + merge_cookies(RequestsCookieJar(), self.cookies), cookies) + + # Set environment's basic authentication if not explicitly set. + auth = request.auth + if self.trust_env and not auth and not self.auth: + auth = get_netrc_auth(request.url) + + p = PreparedRequest() + p.prepare( + method=request.method.upper(), + url=request.url, + files=request.files, + data=request.data, + json=request.json, + headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), + params=merge_setting(request.params, self.params), + auth=merge_setting(auth, self.auth), + cookies=merged_cookies, + hooks=merge_hooks(request.hooks, self.hooks), + ) + return p + + def request(self, method, url, + params=None, + data=None, + headers=None, + cookies=None, + files=None, + auth=None, + timeout=None, + allow_redirects=True, + proxies=None, + hooks=None, + stream=None, + verify=None, + cert=None, + json=None): + """Constructs a :class:`Request `, prepares it and sends it. + Returns :class:`Response ` object. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query + string for the :class:`Request`. + :param data: (optional) Dictionary, bytes, or file-like object to send + in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the + :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the + :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the + :class:`Request`. + :param files: (optional) Dictionary of ``'filename': file-like-objects`` + for multipart encoding upload. + :param auth: (optional) Auth tuple or callable to enable + Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Set to True by default. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol or protocol and + hostname to the URL of the proxy. + :param stream: (optional) whether to immediately download the response + content. Defaults to ``False``. + :param verify: (optional) whether the SSL cert will be verified. + A CA_BUNDLE path can also be provided. Defaults to ``True``. + :param cert: (optional) if String, path to ssl client cert file (.pem). + If Tuple, ('cert', 'key') pair. + :rtype: requests.Response + """ + # Create the Request. + req = Request( + method = method.upper(), + url = url, + headers = headers, + files = files, + data = data or {}, + json = json, + params = params or {}, + auth = auth, + cookies = cookies, + hooks = hooks, + ) + prep = self.prepare_request(req) + + proxies = proxies or {} + + settings = self.merge_environment_settings( + prep.url, proxies, stream, verify, cert + ) + + # Send the request. + send_kwargs = { + 'timeout': timeout, + 'allow_redirects': allow_redirects, + } + send_kwargs.update(settings) + resp = self.send(prep, **send_kwargs) + + return resp + + def get(self, url, **kwargs): + """Sends a GET request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('GET', url, **kwargs) + + def options(self, url, **kwargs): + """Sends a OPTIONS request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('OPTIONS', url, **kwargs) + + def head(self, url, **kwargs): + """Sends a HEAD request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return self.request('HEAD', url, **kwargs) + + def post(self, url, data=None, json=None, **kwargs): + """Sends a POST request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('POST', url, data=data, json=json, **kwargs) + + def put(self, url, data=None, **kwargs): + """Sends a PUT request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PUT', url, data=data, **kwargs) + + def patch(self, url, data=None, **kwargs): + """Sends a PATCH request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PATCH', url, data=data, **kwargs) + + def delete(self, url, **kwargs): + """Sends a DELETE request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('DELETE', url, **kwargs) + + def send(self, request, **kwargs): + """ + Send a given PreparedRequest. + + :rtype: requests.Response + """ + # Set defaults that the hooks can utilize to ensure they always have + # the correct parameters to reproduce the previous request. + kwargs.setdefault('stream', self.stream) + kwargs.setdefault('verify', self.verify) + kwargs.setdefault('cert', self.cert) + kwargs.setdefault('proxies', self.proxies) + + # It's possible that users might accidentally send a Request object. + # Guard against that specific failure case. + if isinstance(request, Request): + raise ValueError('You can only send PreparedRequests.') + + # Set up variables needed for resolve_redirects and dispatching of hooks + allow_redirects = kwargs.pop('allow_redirects', True) + stream = kwargs.get('stream') + hooks = request.hooks + + # Resolve URL in redirect cache, if available. + if allow_redirects: + checked_urls = set() + while request.url in self.redirect_cache: + checked_urls.add(request.url) + new_url = self.redirect_cache.get(request.url) + if new_url in checked_urls: + break + request.url = new_url + + # Get the appropriate adapter to use + adapter = self.get_adapter(url=request.url) + + # Start time (approximately) of the request + start = datetime.utcnow() + + # Send the request + r = adapter.send(request, **kwargs) + + # Total elapsed time of the request (approximately) + r.elapsed = datetime.utcnow() - start + + # Response manipulation hooks + r = dispatch_hook('response', hooks, r, **kwargs) + + # Persist cookies + if r.history: + + # If the hooks create history then we want those cookies too + for resp in r.history: + extract_cookies_to_jar(self.cookies, resp.request, resp.raw) + + extract_cookies_to_jar(self.cookies, request, r.raw) + + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + + # Resolve redirects if allowed. + history = [resp for resp in gen] if allow_redirects else [] + + # Shuffle things around if there's history. + if history: + # Insert the first (original) request at the start + history.insert(0, r) + # Get the last request made + r = history.pop() + r.history = history + + if not stream: + r.content + + return r + + def merge_environment_settings(self, url, proxies, stream, verify, cert): + """ + Check the environment and merge it with some settings. + + :rtype: dict + """ + # Gather clues from the surrounding environment. + if self.trust_env: + # Set environment's proxies. + env_proxies = get_environ_proxies(url) or {} + for (k, v) in env_proxies.items(): + proxies.setdefault(k, v) + + # Look for requests environment configuration and be compatible + # with cURL. + if verify is True or verify is None: + verify = (os.environ.get('REQUESTS_CA_BUNDLE') or + os.environ.get('CURL_CA_BUNDLE')) + + # Merge all the kwargs. + proxies = merge_setting(proxies, self.proxies) + stream = merge_setting(stream, self.stream) + verify = merge_setting(verify, self.verify) + cert = merge_setting(cert, self.cert) + + return {'verify': verify, 'proxies': proxies, 'stream': stream, + 'cert': cert} + + def get_adapter(self, url): + """ + Returns the appropriate connection adapter for the given URL. + + :rtype: requests.adapters.BaseAdapter + """ + for (prefix, adapter) in self.adapters.items(): + + if url.lower().startswith(prefix): + return adapter + + # Nothing matches :-/ + raise InvalidSchema("No connection adapters were found for '%s'" % url) + + def close(self): + """Closes all adapters and as such the session""" + for v in self.adapters.values(): + v.close() + + def mount(self, prefix, adapter): + """Registers a connection adapter to a prefix. + + Adapters are sorted in descending order by key length. + """ + self.adapters[prefix] = adapter + keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] + + for key in keys_to_move: + self.adapters[key] = self.adapters.pop(key) + + def __getstate__(self): + state = dict((attr, getattr(self, attr, None)) for attr in self.__attrs__) + state['redirect_cache'] = dict(self.redirect_cache) + return state + + def __setstate__(self, state): + redirect_cache = state.pop('redirect_cache', {}) + for attr, value in state.items(): + setattr(self, attr, value) + + self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE) + for redirect, to in redirect_cache.items(): + self.redirect_cache[redirect] = to + + +def session(): + """ + Returns a :class:`Session` for context-management. + + :rtype: Session + """ + + return Session() diff --git a/pipenv/vendor/requests/status_codes.py b/pipenv/vendor/requests/status_codes.py new file mode 100644 index 00000000..db2986bb --- /dev/null +++ b/pipenv/vendor/requests/status_codes.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +from .structures import LookupDict + +_codes = { + + # Informational. + 100: ('continue',), + 101: ('switching_protocols',), + 102: ('processing',), + 103: ('checkpoint',), + 122: ('uri_too_long', 'request_uri_too_long'), + 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), + 201: ('created',), + 202: ('accepted',), + 203: ('non_authoritative_info', 'non_authoritative_information'), + 204: ('no_content',), + 205: ('reset_content', 'reset'), + 206: ('partial_content', 'partial'), + 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), + 208: ('already_reported',), + 226: ('im_used',), + + # Redirection. + 300: ('multiple_choices',), + 301: ('moved_permanently', 'moved', '\\o-'), + 302: ('found',), + 303: ('see_other', 'other'), + 304: ('not_modified',), + 305: ('use_proxy',), + 306: ('switch_proxy',), + 307: ('temporary_redirect', 'temporary_moved', 'temporary'), + 308: ('permanent_redirect', + 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 + + # Client Error. + 400: ('bad_request', 'bad'), + 401: ('unauthorized',), + 402: ('payment_required', 'payment'), + 403: ('forbidden',), + 404: ('not_found', '-o-'), + 405: ('method_not_allowed', 'not_allowed'), + 406: ('not_acceptable',), + 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), + 408: ('request_timeout', 'timeout'), + 409: ('conflict',), + 410: ('gone',), + 411: ('length_required',), + 412: ('precondition_failed', 'precondition'), + 413: ('request_entity_too_large',), + 414: ('request_uri_too_large',), + 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), + 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), + 417: ('expectation_failed',), + 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), + 421: ('misdirected_request',), + 422: ('unprocessable_entity', 'unprocessable'), + 423: ('locked',), + 424: ('failed_dependency', 'dependency'), + 425: ('unordered_collection', 'unordered'), + 426: ('upgrade_required', 'upgrade'), + 428: ('precondition_required', 'precondition'), + 429: ('too_many_requests', 'too_many'), + 431: ('header_fields_too_large', 'fields_too_large'), + 444: ('no_response', 'none'), + 449: ('retry_with', 'retry'), + 450: ('blocked_by_windows_parental_controls', 'parental_controls'), + 451: ('unavailable_for_legal_reasons', 'legal_reasons'), + 499: ('client_closed_request',), + + # Server Error. + 500: ('internal_server_error', 'server_error', '/o\\', '✗'), + 501: ('not_implemented',), + 502: ('bad_gateway',), + 503: ('service_unavailable', 'unavailable'), + 504: ('gateway_timeout',), + 505: ('http_version_not_supported', 'http_version'), + 506: ('variant_also_negotiates',), + 507: ('insufficient_storage',), + 509: ('bandwidth_limit_exceeded', 'bandwidth'), + 510: ('not_extended',), + 511: ('network_authentication_required', 'network_auth', 'network_authentication'), +} + +codes = LookupDict(name='status_codes') + +for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith('\\'): + setattr(codes, title.upper(), code) diff --git a/pipenv/vendor/requests/structures.py b/pipenv/vendor/requests/structures.py new file mode 100644 index 00000000..05d2b3f5 --- /dev/null +++ b/pipenv/vendor/requests/structures.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +import collections + +from .compat import OrderedDict + + +class CaseInsensitiveDict(collections.MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``collections.MutableMapping`` as well as dict's ``copy``. Also + provides ``lower_items``. + + All keys are expected to be strings. The structure remembers the + case of the last key to be set, and ``iter(instance)``, + ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` + will contain case-sensitive keys. However, querying and contains + testing is case insensitive:: + + cid = CaseInsensitiveDict() + cid['Accept'] = 'application/json' + cid['aCCEPT'] == 'application/json' # True + list(cid) == ['Accept'] # True + + For example, ``headers['content-encoding']`` will return the + value of a ``'Content-Encoding'`` response header, regardless + of how the header name was originally stored. + + If the constructor, ``.update``, or equality comparison + operations are given keys that have equal ``.lower()``s, the + behavior is undefined. + """ + + def __init__(self, data=None, **kwargs): + self._store = OrderedDict() + if data is None: + data = {} + self.update(data, **kwargs) + + def __setitem__(self, key, value): + # Use the lowercased key for lookups, but store the actual + # key alongside the value. + self._store[key.lower()] = (key, value) + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __delitem__(self, key): + del self._store[key.lower()] + + def __iter__(self): + return (casedkey for casedkey, mappedvalue in self._store.values()) + + def __len__(self): + return len(self._store) + + def lower_items(self): + """Like iteritems(), but with all lowercase keys.""" + return ( + (lowerkey, keyval[1]) + for (lowerkey, keyval) + in self._store.items() + ) + + def __eq__(self, other): + if isinstance(other, collections.Mapping): + other = CaseInsensitiveDict(other) + else: + return NotImplemented + # Compare insensitively + return dict(self.lower_items()) == dict(other.lower_items()) + + # Copy is required + def copy(self): + return CaseInsensitiveDict(self._store.values()) + + def __repr__(self): + return str(dict(self.items())) + + +class LookupDict(dict): + """Dictionary lookup object.""" + + def __init__(self, name=None): + self.name = name + super(LookupDict, self).__init__() + + def __repr__(self): + return '' % (self.name) + + def __getitem__(self, key): + # We allow fall-through here, so values default to None + + return self.__dict__.get(key, None) + + def get(self, key, default=None): + return self.__dict__.get(key, default) diff --git a/pipenv/vendor/requests/utils.py b/pipenv/vendor/requests/utils.py new file mode 100644 index 00000000..47325090 --- /dev/null +++ b/pipenv/vendor/requests/utils.py @@ -0,0 +1,827 @@ +# -*- coding: utf-8 -*- + +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import cgi +import codecs +import collections +import io +import os +import re +import socket +import struct +import warnings + +from . import __version__ +from . import certs +# to_native_string is unused here, but imported here for backwards compatibility +from ._internal_utils import to_native_string +from .compat import parse_http_list as _parse_list_header +from .compat import ( + quote, urlparse, bytes, str, OrderedDict, unquote, getproxies, + proxy_bypass, urlunparse, basestring, integer_types) +from .cookies import RequestsCookieJar, cookiejar_from_dict +from .structures import CaseInsensitiveDict +from .exceptions import ( + InvalidURL, InvalidHeader, FileModeWarning, UnrewindableBodyError) + +_hush_pyflakes = (RequestsCookieJar,) + +NETRC_FILES = ('.netrc', '_netrc') + +DEFAULT_CA_BUNDLE_PATH = certs.where() + + +def dict_to_sequence(d): + """Returns an internal sequence dictionary update.""" + + if hasattr(d, 'items'): + d = d.items() + + return d + + +def super_len(o): + total_length = None + current_position = 0 + + if hasattr(o, '__len__'): + total_length = len(o) + + elif hasattr(o, 'len'): + total_length = o.len + + elif hasattr(o, 'fileno'): + try: + fileno = o.fileno() + except io.UnsupportedOperation: + pass + else: + total_length = os.fstat(fileno).st_size + + # Having used fstat to determine the file length, we need to + # confirm that this file was opened up in binary mode. + if 'b' not in o.mode: + warnings.warn(( + "Requests has determined the content-length for this " + "request using the binary size of the file: however, the " + "file has been opened in text mode (i.e. without the 'b' " + "flag in the mode). This may lead to an incorrect " + "content-length. In Requests 3.0, support will be removed " + "for files in text mode."), + FileModeWarning + ) + + if hasattr(o, 'tell'): + try: + current_position = o.tell() + except (OSError, IOError): + # This can happen in some weird situations, such as when the file + # is actually a special file descriptor like stdin. In this + # instance, we don't know what the length is, so set it to zero and + # let requests chunk it instead. + if total_length is not None: + current_position = total_length + else: + if hasattr(o, 'seek') and total_length is None: + # StringIO and BytesIO have seek but no useable fileno + + # seek to end of file + o.seek(0, 2) + total_length = o.tell() + + # seek back to current position to support + # partially read file-like objects + o.seek(current_position or 0) + + if total_length is None: + total_length = 0 + + return max(0, total_length - current_position) + + +def get_netrc_auth(url, raise_errors=False): + """Returns the Requests tuple auth for a given url from netrc.""" + + try: + from netrc import netrc, NetrcParseError + + netrc_path = None + + for f in NETRC_FILES: + try: + loc = os.path.expanduser('~/{0}'.format(f)) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See http://bugs.python.org/issue20164 & + # https://github.com/kennethreitz/requests/issues/1846 + return + + if os.path.exists(loc): + netrc_path = loc + break + + # Abort early if there isn't one. + if netrc_path is None: + return + + ri = urlparse(url) + + # Strip port numbers from netloc. This weird `if...encode`` dance is + # used for Python 3.2, which doesn't support unicode literals. + splitstr = b':' + if isinstance(url, str): + splitstr = splitstr.decode('ascii') + host = ri.netloc.split(splitstr)[0] + + try: + _netrc = netrc(netrc_path).authenticators(host) + if _netrc: + # Return with login / password + login_i = (0 if _netrc[0] else 1) + return (_netrc[login_i], _netrc[2]) + except (NetrcParseError, IOError): + # If there was a parsing error or a permissions issue reading the file, + # we'll just skip netrc auth unless explicitly asked to raise errors. + if raise_errors: + raise + + # AppEngine hackiness. + except (ImportError, AttributeError): + pass + + +def guess_filename(obj): + """Tries to guess the filename of the given object.""" + name = getattr(obj, 'name', None) + if (name and isinstance(name, basestring) and name[0] != '<' and + name[-1] != '>'): + return os.path.basename(name) + + +def from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + ValueError: need more than 1 value to unpack + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :rtype: OrderedDict + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + return OrderedDict(value) + + +def to_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. If it can be, return a list of tuples, e.g., + + :: + + >>> to_key_val_list([('key', 'val')]) + [('key', 'val')] + >>> to_key_val_list({'key': 'val'}) + [('key', 'val')] + >>> to_key_val_list('string') + ValueError: cannot encode objects that are not 2-tuples. + + :rtype: list + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + if isinstance(value, collections.Mapping): + value = value.items() + + return list(value) + + +# From mitsuhiko/werkzeug (used with permission). +def parse_list_header(value): + """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. Quotes are removed automatically after parsing. + + It basically works like :func:`parse_set_header` just that items + may appear multiple times and case sensitivity is preserved. + + The return value is a standard :class:`list`: + + >>> parse_list_header('token, "quoted value"') + ['token', 'quoted value'] + + To create a header from the :class:`list` again, use the + :func:`dump_header` function. + + :param value: a string with a list header. + :return: :class:`list` + :rtype: list + """ + result = [] + for item in _parse_list_header(value): + if item[:1] == item[-1:] == '"': + item = unquote_header_value(item[1:-1]) + result.append(item) + return result + + +# From mitsuhiko/werkzeug (used with permission). +def parse_dict_header(value): + """Parse lists of key, value pairs as described by RFC 2068 Section 2 and + convert them into a python dict: + + >>> d = parse_dict_header('foo="is a fish", bar="as well"') + >>> type(d) is dict + True + >>> sorted(d.items()) + [('bar', 'as well'), ('foo', 'is a fish')] + + If there is no value for a key it will be `None`: + + >>> parse_dict_header('key_without_value') + {'key_without_value': None} + + To create a header from the :class:`dict` again, use the + :func:`dump_header` function. + + :param value: a string with a dict header. + :return: :class:`dict` + :rtype: dict + """ + result = {} + for item in _parse_list_header(value): + if '=' not in item: + result[item] = None + continue + name, value = item.split('=', 1) + if value[:1] == value[-1:] == '"': + value = unquote_header_value(value[1:-1]) + result[name] = value + return result + + +# From mitsuhiko/werkzeug (used with permission). +def unquote_header_value(value, is_filename=False): + r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). + This does not use the real unquoting but what browsers are actually + using for quoting. + + :param value: the header value to unquote. + :rtype: str + """ + if value and value[0] == value[-1] == '"': + # this is not the real unquoting, but fixing this so that the + # RFC is met will result in bugs with internet explorer and + # probably some other browsers as well. IE for example is + # uploading files with "C:\foo\bar.txt" as filename + value = value[1:-1] + + # if this is a filename and the starting characters look like + # a UNC path, then just return the value without quotes. Using the + # replace sequence below on a UNC path has the effect of turning + # the leading double slash into a single slash and then + # _fix_ie_filename() doesn't work correctly. See #458. + if not is_filename or value[:2] != '\\\\': + return value.replace('\\\\', '\\').replace('\\"', '"') + return value + + +def dict_from_cookiejar(cj): + """Returns a key/value dictionary from a CookieJar. + + :param cj: CookieJar object to extract cookies from. + :rtype: dict + """ + + cookie_dict = {} + + for cookie in cj: + cookie_dict[cookie.name] = cookie.value + + return cookie_dict + + +def add_dict_to_cookiejar(cj, cookie_dict): + """Returns a CookieJar from a key/value dictionary. + + :param cj: CookieJar to insert cookies into. + :param cookie_dict: Dict of key/values to insert into CookieJar. + :rtype: CookieJar + """ + + return cookiejar_from_dict(cookie_dict, cj) + + +def get_encodings_from_content(content): + """Returns encodings from given content string. + + :param content: bytestring to extract encodings from. + """ + warnings.warn(( + 'In requests 3.0, get_encodings_from_content will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + charset_re = re.compile(r']', flags=re.I) + pragma_re = re.compile(r']', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return (charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content)) + + +def get_encoding_from_headers(headers): + """Returns encodings from given HTTP Header Dict. + + :param headers: dictionary to extract encoding from. + :rtype: str + """ + + content_type = headers.get('content-type') + + if not content_type: + return None + + content_type, params = cgi.parse_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + if 'text' in content_type: + return 'ISO-8859-1' + + +def stream_decode_response_unicode(iterator, r): + """Stream decodes a iterator.""" + + if r.encoding is None: + for item in iterator: + yield item + return + + decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') + for chunk in iterator: + rv = decoder.decode(chunk) + if rv: + yield rv + rv = decoder.decode(b'', final=True) + if rv: + yield rv + + +def iter_slices(string, slice_length): + """Iterate over slices of a string.""" + pos = 0 + if slice_length is None or slice_length <= 0: + slice_length = len(string) + while pos < len(string): + yield string[pos:pos + slice_length] + pos += slice_length + + +def get_unicode_from_response(r): + """Returns the requested content back in unicode. + + :param r: Response object to get unicode content from. + + Tried: + + 1. charset from content-type + 2. fall back and replace all unicode characters + + :rtype: str + """ + warnings.warn(( + 'In requests 3.0, get_unicode_from_response will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + tried_encodings = [] + + # Try charset from content-type + encoding = get_encoding_from_headers(r.headers) + + if encoding: + try: + return str(r.content, encoding) + except UnicodeError: + tried_encodings.append(encoding) + + # Fall back: + try: + return str(r.content, encoding, errors='replace') + except TypeError: + return r.content + + +# The unreserved URI characters (RFC 3986) +UNRESERVED_SET = frozenset( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + "0123456789-._~") + + +def unquote_unreserved(uri): + """Un-escape any percent-escape sequences in a URI that are unreserved + characters. This leaves all reserved, illegal and non-ASCII bytes encoded. + + :rtype: str + """ + parts = uri.split('%') + for i in range(1, len(parts)): + h = parts[i][0:2] + if len(h) == 2 and h.isalnum(): + try: + c = chr(int(h, 16)) + except ValueError: + raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) + + if c in UNRESERVED_SET: + parts[i] = c + parts[i][2:] + else: + parts[i] = '%' + parts[i] + else: + parts[i] = '%' + parts[i] + return ''.join(parts) + + +def requote_uri(uri): + """Re-quote the given URI. + + This function passes the given URI through an unquote/quote cycle to + ensure that it is fully and consistently quoted. + + :rtype: str + """ + safe_with_percent = "!#$%&'()*+,/:;=?@[]~" + safe_without_percent = "!#$&'()*+,/:;=?@[]~" + try: + # Unquote only the unreserved characters + # Then quote only illegal characters (do not quote reserved, + # unreserved, or '%') + return quote(unquote_unreserved(uri), safe=safe_with_percent) + except InvalidURL: + # We couldn't unquote the given URI, so let's try quoting it, but + # there may be unquoted '%'s in the URI. We need to make sure they're + # properly quoted so they do not cause issues elsewhere. + return quote(uri, safe=safe_without_percent) + + +def address_in_network(ip, net): + """This function allows you to check if on IP belongs to a network subnet + + Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24 + returns False if ip = 192.168.1.1 and net = 192.168.100.0/24 + + :rtype: bool + """ + ipaddr = struct.unpack('=L', socket.inet_aton(ip))[0] + netaddr, bits = net.split('/') + netmask = struct.unpack('=L', socket.inet_aton(dotted_netmask(int(bits))))[0] + network = struct.unpack('=L', socket.inet_aton(netaddr))[0] & netmask + return (ipaddr & netmask) == (network & netmask) + + +def dotted_netmask(mask): + """Converts mask from /xx format to xxx.xxx.xxx.xxx + + Example: if mask is 24 function returns 255.255.255.0 + + :rtype: str + """ + bits = 0xffffffff ^ (1 << 32 - mask) - 1 + return socket.inet_ntoa(struct.pack('>I', bits)) + + +def is_ipv4_address(string_ip): + """ + :rtype: bool + """ + try: + socket.inet_aton(string_ip) + except socket.error: + return False + return True + + +def is_valid_cidr(string_network): + """ + Very simple check of the cidr format in no_proxy variable. + + :rtype: bool + """ + if string_network.count('/') == 1: + try: + mask = int(string_network.split('/')[1]) + except ValueError: + return False + + if mask < 1 or mask > 32: + return False + + try: + socket.inet_aton(string_network.split('/')[0]) + except socket.error: + return False + else: + return False + return True + + +def should_bypass_proxies(url): + """ + Returns whether we should bypass proxies or not. + + :rtype: bool + """ + get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) + + # First check whether no_proxy is defined. If it is, check that the URL + # we're getting isn't in the no_proxy list. + no_proxy = get_proxy('no_proxy') + netloc = urlparse(url).netloc + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the netloc, both with and without the port. + no_proxy = ( + host for host in no_proxy.replace(' ', '').split(',') if host + ) + + ip = netloc.split(':')[0] + if is_ipv4_address(ip): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(ip, proxy_ip): + return True + elif ip == proxy_ip: + # If no_proxy ip was defined in plain IP notation instead of cidr notation & + # matches the IP of the index + return True + else: + for host in no_proxy: + if netloc.endswith(host) or netloc.split(':')[0].endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + # If the system proxy settings indicate that this URL should be bypassed, + # don't proxy. + # The proxy_bypass function is incredibly buggy on OS X in early versions + # of Python 2.6, so allow this call to fail. Only catch the specific + # exceptions we've seen, though: this call failing in other ways can reveal + # legitimate problems. + try: + bypass = proxy_bypass(netloc) + except (TypeError, socket.gaierror): + bypass = False + + if bypass: + return True + + return False + + +def get_environ_proxies(url): + """ + Return a dict of environment proxies. + + :rtype: dict + """ + if should_bypass_proxies(url): + return {} + else: + return getproxies() + + +def select_proxy(url, proxies): + """Select a proxy for the url, if applicable. + + :param url: The url being for the request + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + """ + proxies = proxies or {} + urlparts = urlparse(url) + if urlparts.hostname is None: + return proxies.get(urlparts.scheme, proxies.get('all')) + + proxy_keys = [ + urlparts.scheme + '://' + urlparts.hostname, + urlparts.scheme, + 'all://' + urlparts.hostname, + 'all', + ] + proxy = None + for proxy_key in proxy_keys: + if proxy_key in proxies: + proxy = proxies[proxy_key] + break + + return proxy + + +def default_user_agent(name="python-requests"): + """ + Return a string representing the default user agent. + + :rtype: str + """ + return '%s/%s' % (name, __version__) + + +def default_headers(): + """ + :rtype: requests.structures.CaseInsensitiveDict + """ + return CaseInsensitiveDict({ + 'User-Agent': default_user_agent(), + 'Accept-Encoding': ', '.join(('gzip', 'deflate')), + 'Accept': '*/*', + 'Connection': 'keep-alive', + }) + + +def parse_header_links(value): + """Return a dict of parsed link headers proxies. + + i.e. Link: ; rel=front; type="image/jpeg",; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = ' \'"' + + for val in re.split(', *<', value): + try: + url, params = val.split(';', 1) + except ValueError: + url, params = val, '' + + link = {'url': url.strip('<> \'"')} + + for param in params.split(';'): + try: + key, value = param.split('=') + except ValueError: + break + + link[key.strip(replace_chars)] = value.strip(replace_chars) + + links.append(link) + + return links + + +# Null bytes; no need to recreate these on each call to guess_json_utf +_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 +_null2 = _null * 2 +_null3 = _null * 3 + + +def guess_json_utf(data): + """ + :rtype: str + """ + # JSON always starts with two ASCII characters, so detection is as + # easy as counting the nulls and from their location and count + # determine the encoding. Also detect a BOM, if present. + sample = data[:4] + if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): + return 'utf-32' # BOM included + if sample[:3] == codecs.BOM_UTF8: + return 'utf-8-sig' # BOM included, MS style (discouraged) + if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): + return 'utf-16' # BOM included + nullcount = sample.count(_null) + if nullcount == 0: + return 'utf-8' + if nullcount == 2: + if sample[::2] == _null2: # 1st and 3rd are null + return 'utf-16-be' + if sample[1::2] == _null2: # 2nd and 4th are null + return 'utf-16-le' + # Did not detect 2 valid UTF-16 ascii-range characters + if nullcount == 3: + if sample[:3] == _null3: + return 'utf-32-be' + if sample[1:] == _null3: + return 'utf-32-le' + # Did not detect a valid UTF-32 ascii-range character + return None + + +def prepend_scheme_if_needed(url, new_scheme): + """Given a URL that may or may not have a scheme, prepend the given scheme. + Does not replace a present scheme with the one provided as an argument. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme) + + # urlparse is a finicky beast, and sometimes decides that there isn't a + # netloc present. Assume that it's being over-cautious, and switch netloc + # and path if urlparse decided there was no netloc. + if not netloc: + netloc, path = path, netloc + + return urlunparse((scheme, netloc, path, params, query, fragment)) + + +def get_auth_from_url(url): + """Given a url with authentication components, extract them into a tuple of + username,password. + + :rtype: (str,str) + """ + parsed = urlparse(url) + + try: + auth = (unquote(parsed.username), unquote(parsed.password)) + except (AttributeError, TypeError): + auth = ('', '') + + return auth + + +# Moved outside of function to avoid recompile every call +_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$') +_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$') + +def check_header_validity(header): + """Verifies that header value is a string which doesn't contain + leading whitespace or return characters. This prevents unintended + header injection. + + :param header: tuple, in the format (name, value). + """ + name, value = header + + if isinstance(value, bytes): + pat = _CLEAN_HEADER_REGEX_BYTE + else: + pat = _CLEAN_HEADER_REGEX_STR + try: + if not pat.match(value): + raise InvalidHeader("Invalid return character or leading space in header: %s" % name) + except TypeError: + raise InvalidHeader("Header value %s must be of type str or bytes, " + "not %s" % (value, type(value))) + + +def urldefragauth(url): + """ + Given a url remove the fragment and the authentication part. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url) + + # see func:`prepend_scheme_if_needed` + if not netloc: + netloc, path = path, netloc + + netloc = netloc.rsplit('@', 1)[-1] + + return urlunparse((scheme, netloc, path, params, query, '')) + +def rewind_body(prepared_request): + """Move file pointer back to its recorded starting position + so it can be read again on redirect. + """ + body_seek = getattr(prepared_request.body, 'seek', None) + if body_seek is not None and isinstance(prepared_request._body_position, integer_types): + try: + body_seek(prepared_request._body_position) + except (IOError, OSError): + raise UnrewindableBodyError("An error occured when rewinding request " + "body for redirect.") + else: + raise UnrewindableBodyError("Unable to rewind request body for redirect.") diff --git a/pipenv/vendor/requirements/__init__.py b/pipenv/vendor/requirements/__init__.py new file mode 100644 index 00000000..f1025724 --- /dev/null +++ b/pipenv/vendor/requirements/__init__.py @@ -0,0 +1,22 @@ +from .parser import parse # noqa + +_MAJOR = 0 +_MINOR = 1 +_PATCH = 0 + + +def version_tuple(): + ''' + Returns a 3-tuple of ints that represent the version + ''' + return (_MAJOR, _MINOR, _PATCH) + + +def version(): + ''' + Returns a string representation of the version + ''' + return '%d.%d.%d' % (version_tuple()) + + +__version__ = version() diff --git a/pipenv/vendor/requirements/parser.py b/pipenv/vendor/requirements/parser.py new file mode 100644 index 00000000..024c905f --- /dev/null +++ b/pipenv/vendor/requirements/parser.py @@ -0,0 +1,50 @@ +import os +import warnings + +from .requirement import Requirement + + +def parse(reqstr): + """ + Parse a requirements file into a list of Requirements + + See: pip/req.py:parse_requirements() + + :param reqstr: a string or file like object containing requirements + :returns: a *generator* of Requirement objects + """ + filename = getattr(reqstr, 'name', None) + try: + # Python 2.x compatibility + if not isinstance(reqstr, basestring): + reqstr = reqstr.read() + except NameError: + # Python 3.x only + if not isinstance(reqstr, str): + reqstr = reqstr.read() + + for line in reqstr.splitlines(): + line = line.strip() + if line == '': + continue + elif not line or line.startswith('#'): + # comments are lines that start with # only + continue + elif line.startswith('-r') or line.startswith('--requirement'): + _, new_filename = line.split() + new_file_path = os.path.join(os.path.dirname(filename or '.'), + new_filename) + with open(new_file_path) as f: + for requirement in parse(f): + yield requirement + elif line.startswith('-f') or line.startswith('--find-links') or \ + line.startswith('-i') or line.startswith('--index-url') or \ + line.startswith('--extra-index-url') or \ + line.startswith('--no-index'): + warnings.warn('Private repos not supported. Skipping.') + continue + elif line.startswith('-Z') or line.startswith('--always-unzip'): + warnings.warn('Unused option --always-unzip. Skipping.') + continue + else: + yield Requirement.parse(line) diff --git a/pipenv/vendor/requirements/requirement.py b/pipenv/vendor/requirements/requirement.py new file mode 100644 index 00000000..2fc2bb1d --- /dev/null +++ b/pipenv/vendor/requirements/requirement.py @@ -0,0 +1,181 @@ +from __future__ import unicode_literals +import re +from pkg_resources import Requirement as Req + +from .vcs import VCS, VCS_SCHEMES + + +URI_REGEX = re.compile( + r'^(?Phttps?|file|ftps?)://(?P[^#]+)' + r'(#egg=(?P[^&]+))?$' +) + +VCS_REGEX = re.compile( + r'^(?P{0})://'.format(r'|'.join( + [scheme.replace('+', r'\+') for scheme in VCS_SCHEMES])) + + r'((?P[^/@]+)@)?' + r'(?P[^#@]+)' + r'(@(?P[^#]+))?' + r'(#egg=(?P[^&]+))?$' +) + +# This matches just about everyting +LOCAL_REGEX = re.compile( + r'^((?Pfile)://)?' + r'(?P[^#]+)' + r'(#egg=(?P[^&]+))?$' +) + + +class Requirement(object): + """ + Represents a single requirement + + Typically instances of this class are created with ``Requirement.parse``. + For local file requirements, there's no verification that the file + exists. This class attempts to be *dict-like*. + + See: http://www.pip-installer.org/en/latest/logic.html + + **Members**: + + * ``line`` - the actual requirement line being parsed + * ``editable`` - a boolean whether this requirement is "editable" + * ``local_file`` - a boolean whether this requirement is a local file/path + * ``specifier`` - a boolean whether this requirement used a requirement + specifier (eg. "django>=1.5" or "requirements") + * ``vcs`` - a string specifying the version control system + * ``revision`` - a version control system specifier + * ``name`` - the name of the requirement + * ``uri`` - the URI if this requirement was specified by URI + * ``path`` - the local path to the requirement + * ``extras`` - a list of extras for this requirement + (eg. "mymodule[extra1, extra2]") + * ``specs`` - a list of specs for this requirement + (eg. "mymodule>1.5,<1.6" => [('>', '1.5'), ('<', '1.6')]) + """ + + def __init__(self, line): + # Do not call this private method + self.line = line + self.editable = False + self.local_file = False + self.specifier = False + self.vcs = None + self.name = None + self.uri = None + self.path = None + self.revision = None + self.extras = [] + self.specs = [] + + def __repr__(self): + return ''.format(self.line) + + def __getitem__(self, key): + return getattr(self, key) + + def keys(self): + return self.__dict__.keys() + + @classmethod + def parse_editable(cls, line): + """ + Parses a Requirement from an "editable" requirement which is either + a local project path or a VCS project URI. + + See: pip/req.py:from_editable() + + :param line: an "editable" requirement + :returns: a Requirement instance for the given line + :raises: ValueError on an invalid requirement + """ + + req = cls('-e {0}'.format(line)) + req.editable = True + vcs_match = VCS_REGEX.match(line) + local_match = LOCAL_REGEX.match(line) + + if vcs_match is not None: + groups = vcs_match.groupdict() + req.uri = '{scheme}://{path}'.format(**groups) + req.revision = groups['revision'] + req.name = groups['name'] + for vcs in VCS: + if req.uri.startswith(vcs): + req.vcs = vcs + else: + assert local_match is not None, 'This should match everything' + groups = local_match.groupdict() + req.local_file = True + req.name = groups['name'] + req.path = groups['path'] + + return req + + @classmethod + def parse_line(cls, line): + """ + Parses a Requirement from a non-editable requirement. + + See: pip/req.py:from_line() + + :param line: a "non-editable" requirement + :returns: a Requirement instance for the given line + :raises: ValueError on an invalid requirement + """ + + req = cls(line) + + vcs_match = VCS_REGEX.match(line) + uri_match = URI_REGEX.match(line) + local_match = LOCAL_REGEX.match(line) + + if vcs_match is not None: + groups = vcs_match.groupdict() + req.uri = '{scheme}://{path}'.format(**groups) + req.revision = groups['revision'] + req.name = groups['name'] + for vcs in VCS: + if req.uri.startswith(vcs): + req.vcs = vcs + elif uri_match is not None: + groups = uri_match.groupdict() + req.uri = '{scheme}://{path}'.format(**groups) + req.name = groups['name'] + if groups['scheme'] == 'file': + req.local_file = True + elif '#egg=' in line: + # Assume a local file match + assert local_match is not None, 'This should match everything' + groups = local_match.groupdict() + req.local_file = True + req.name = groups['name'] + req.path = groups['path'] + else: + # This is a requirement specifier. + # Delegate to pkg_resources and hope for the best + req.specifier = True + pkg_req = Req.parse(line) + req.name = pkg_req.unsafe_name + req.extras = list(pkg_req.extras) + req.specs = pkg_req.specs + return req + + @classmethod + def parse(cls, line): + """ + Parses a Requirement from a line of a requirement file. + + :param line: a line of a requirement file + :returns: a Requirement instance for the given line + :raises: ValueError on an invalid requirement + """ + + if line.startswith('-e') or line.startswith('--editable'): + # Editable installs are either a local project path + # or a VCS project URI + return cls.parse_editable( + re.sub(r'^(-e|--editable=?)\s*', '', line)) + + return cls.parse_line(line) diff --git a/pipenv/vendor/requirements/vcs.py b/pipenv/vendor/requirements/vcs.py new file mode 100644 index 00000000..f5317b23 --- /dev/null +++ b/pipenv/vendor/requirements/vcs.py @@ -0,0 +1,30 @@ +from __future__ import unicode_literals + +VCS = [ + 'git', + 'hg', + 'svn', + 'bzr', +] + +VCS_SCHEMES = [ + 'git', + 'git+https', + 'git+ssh', + 'git+git', + 'hg+http', + 'hg+https', + 'hg+static-http', + 'hg+ssh', + 'svn', + 'svn+svn', + 'svn+http', + 'svn+https', + 'svn+ssh', + 'bzr+http', + 'bzr+https', + 'bzr+ssh', + 'bzr+sftp', + 'bzr+ftp', + 'bzr+lp', +] diff --git a/pipenv/vendor/shutilwhich/__init__.py b/pipenv/vendor/shutilwhich/__init__.py new file mode 100644 index 00000000..71528812 --- /dev/null +++ b/pipenv/vendor/shutilwhich/__init__.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +__version__ = '1.1.0' + +import shutil + +if not hasattr(shutil, 'which'): + from .lib import which + shutil.which = which +else: + from shutil import which diff --git a/pipenv/vendor/shutilwhich/lib.py b/pipenv/vendor/shutilwhich/lib.py new file mode 100644 index 00000000..6451083a --- /dev/null +++ b/pipenv/vendor/shutilwhich/lib.py @@ -0,0 +1,58 @@ +import os +import sys + + +# Everything below this point has been copied verbatim from the Python-3.3 +# sources. +def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + + """ + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + + # Short circuit. If we're given a full path which matches the mode + # and it exists, we're done here. + if _access_check(cmd, mode): + return cmd + + path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep) + + if sys.platform == "win32": + # The current directory takes precedence on Windows. + if not os.curdir in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given "python.exe". + matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())] + # If it does match, only test that one, otherwise we have to try + # others. + files = [cmd] if matches else [cmd + ext.lower() for ext in pathext] + else: + # On other platforms you don't have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + dir = os.path.normcase(dir) + if not dir in seen: + seen.add(dir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None diff --git a/pipenv/vendor/toml.py b/pipenv/vendor/toml.py new file mode 100644 index 00000000..dedddbb3 --- /dev/null +++ b/pipenv/vendor/toml.py @@ -0,0 +1,694 @@ +# This software is released under the MIT license + +import re +import datetime + +class TomlDecodeError(Exception): + pass + +class TomlTz(datetime.tzinfo): + + def __init__(self, toml_offset): + if toml_offset == "Z": + self._raw_offset = "+00:00" + else: + self._raw_offset = toml_offset + self._hours = int(self._raw_offset[:3]) + self._minutes = int(self._raw_offset[4:6]) + + def tzname(self, dt): + return "UTC"+self._raw_offset + + def utcoffset(self, dt): + return datetime.timedelta(hours=self._hours, minutes=self._minutes) + + def dst(self, dt): + return datetime.timedelta(0) + +try: + _range = xrange +except NameError: + unicode = str + _range = range + basestring = str + unichr = chr + +def load(f, _dict=dict): + """Returns a dictionary containing the named file parsed as toml.""" + if isinstance(f, basestring): + with open(f) as ffile: + return loads(ffile.read(), _dict) + elif isinstance(f, list): + for l in f: + if not isinstance(l, basestring): + raise TypeError("Load expects a list to contain filenames only") + d = _dict() + for l in f: + d.update(load(l)) + return d + elif f.read: + return loads(f.read(), _dict) + else: + raise TypeError("You can only load a file descriptor, filename or list") + +_groupname_re = re.compile(r'^[A-Za-z0-9_-]+$') + +def loads(s, _dict=dict): + """Returns a dictionary containing s, a string, parsed as toml.""" + implicitgroups = [] + retval = _dict() + currentlevel = retval + if not isinstance(s, basestring): + raise TypeError("What exactly are you trying to pull?") + try: + s = s.decode('utf8') + except AttributeError: + pass + sl = list(s) + openarr = 0 + openstring = False + openstrchar = "" + multilinestr = False + arrayoftables = False + beginline = True + keygroup = False + keyname = 0 + for i in _range(len(sl)): + if sl[i] == '\r' and sl[i+1] == '\n': + sl[i] = ' ' + continue + if keyname: + if sl[i] == '\n': + raise TomlDecodeError("Key name found without value. Reached end of line.") + if openstring: + if sl[i] == openstrchar: + keyname = 2 + openstring = False + openstrchar = "" + continue + elif keyname == 1: + if sl[i].isspace(): + keyname = 2 + continue + elif sl[i].isalnum() or sl[i] == '_' or sl[i] == '-': + continue + elif keyname == 2 and sl[i].isspace(): + continue + if sl[i] == '=': + keyname = 0 + else: + raise TomlDecodeError("Found invalid character in key name: '"+sl[i]+"'. Try quoting the key name.") + if sl[i] == "'" and openstrchar != '"': + k = 1 + try: + while sl[i-k] == "'": + k += 1 + if k == 3: + break + except IndexError: + pass + if k == 3: + multilinestr = not multilinestr + openstring = multilinestr + else: + openstring = not openstring + if openstring: + openstrchar = "'" + else: + openstrchar = "" + if sl[i] == '"' and openstrchar != "'": + oddbackslash = False + k = 1 + tripquote = False + try: + while sl[i-k] == '"': + k += 1 + if k == 3: + tripquote = True + break + while sl[i-k] == '\\': + oddbackslash = not oddbackslash + k += 1 + except IndexError: + pass + if not oddbackslash: + if tripquote: + multilinestr = not multilinestr + openstring = multilinestr + else: + openstring = not openstring + if openstring: + openstrchar = '"' + else: + openstrchar = "" + if sl[i] == '#' and not openstring and not keygroup and \ + not arrayoftables: + j = i + try: + while sl[j] != '\n': + sl[j] = ' ' + j += 1 + except IndexError: + break + if sl[i] == '[' and not openstring and not keygroup and \ + not arrayoftables: + if beginline: + if sl[i+1] == '[': + arrayoftables = True + else: + keygroup = True + else: + openarr += 1 + if sl[i] == ']' and not openstring: + if keygroup: + keygroup = False + elif arrayoftables: + if sl[i-1] == ']': + arrayoftables = False + else: + openarr -= 1 + if sl[i] == '\n': + if openstring or multilinestr: + if not multilinestr: + raise TomlDecodeError("Unbalanced quotes") + if sl[i-1] == "'" or sl[i-1] == '"': + sl[i] = sl[i-1] + sl[i-3] = ' ' + elif openarr: + sl[i] = ' ' + else: + beginline = True + elif beginline and sl[i] != ' ' and sl[i] != '\t': + beginline = False + if not keygroup and not arrayoftables: + if sl[i] == '=': + raise TomlDecodeError("Found empty keyname. ") + keyname = 1 + s = ''.join(sl) + s = s.split('\n') + multikey = None + multilinestr = "" + multibackslash = False + for line in s: + line = line.strip() + if line == "": + continue + if multikey: + if multibackslash: + multilinestr += line + else: + multilinestr += line + multibackslash = False + if len(line) > 2 and line[-1] == multilinestr[0] and \ + line[-2] == multilinestr[0] and line[-3] == multilinestr[0]: + value, vtype = _load_value(multilinestr) + currentlevel[multikey] = value + multikey = None + multilinestr = "" + else: + k = len(multilinestr) -1 + while k > -1 and multilinestr[k] == '\\': + multibackslash = not multibackslash + k -= 1 + if multibackslash: + multilinestr = multilinestr[:-1] + else: + multilinestr += "\n" + continue + if line[0] == '[': + arrayoftables = False + if line[1] == '[': + arrayoftables = True + line = line[2:].split(']]', 1) + else: + line = line[1:].split(']', 1) + if line[1].strip() != "": + raise TomlDecodeError("Key group not on a line by itself.") + groups = line[0].split('.') + i = 0 + while i < len(groups): + groups[i] = groups[i].strip() + if groups[i][0] == '"' or groups[i][0] == "'": + groupstr = groups[i] + j = i+1 + while not groupstr[0] == groupstr[-1]: + j += 1 + groupstr = '.'.join(groups[i:j]) + groups[i] = groupstr[1:-1] + groups[i+1:j] = [] + else: + if not _groupname_re.match(groups[i]): + raise TomlDecodeError("Invalid group name '"+groups[i]+"'. Try quoting it.") + i += 1 + currentlevel = retval + for i in _range(len(groups)): + group = groups[i] + if group == "": + raise TomlDecodeError("Can't have a keygroup with an empty name") + try: + currentlevel[group] + if i == len(groups) - 1: + if group in implicitgroups: + implicitgroups.remove(group) + if arrayoftables: + raise TomlDecodeError("An implicitly defined table can't be an array") + elif arrayoftables: + currentlevel[group].append(_dict()) + else: + raise TomlDecodeError("What? "+group+" already exists?"+str(currentlevel)) + except TypeError: + if i != len(groups) - 1: + implicitgroups.append(group) + currentlevel = currentlevel[-1] + try: + currentlevel[group] + except KeyError: + currentlevel[group] = _dict() + if i == len(groups) - 1 and arrayoftables: + currentlevel[group] = [_dict()] + except KeyError: + if i != len(groups) - 1: + implicitgroups.append(group) + currentlevel[group] = _dict() + if i == len(groups) - 1 and arrayoftables: + currentlevel[group] = [_dict()] + currentlevel = currentlevel[group] + if arrayoftables: + try: + currentlevel = currentlevel[-1] + except KeyError: + pass + elif line[0] == "{": + if line[-1] != "}": + raise TomlDecodeError("Line breaks are not allowed in inline objects") + _load_inline_object(line, currentlevel, multikey, multibackslash) + elif "=" in line: + ret = _load_line(line, currentlevel, multikey, multibackslash) + if ret is not None: + multikey, multilinestr, multibackslash = ret + return retval + +def _load_inline_object(line, currentlevel, multikey=False, multibackslash=False): + candidate_groups = line[1:-1].split(",") + groups = [] + while len(candidate_groups) > 0: + candidate_group = candidate_groups.pop(0) + _, value = candidate_group.split('=', 1) + value = value.strip() + if (value[0] == value[-1] and value[0] in ('"', "'")) or \ + value[0] in '0123456789' or \ + value in ('true', 'false') or \ + value[0] == "[" and value[-1] == "]": + groups.append(candidate_group) + else: + candidate_groups[0] = candidate_group + "," + candidate_groups[0] + for group in groups: + status = _load_line(group, currentlevel, multikey, multibackslash) + if status is not None: + break + +# Matches a TOML number, which allows underscores for readability +_number_with_underscores = re.compile('([0-9])(_([0-9]))*') + +def _load_line(line, currentlevel, multikey, multibackslash): + i = 1 + pair = line.split('=', i) + if _number_with_underscores.match(pair[-1]): + pair[-1] = pair[-1].replace('_', '') + while pair[-1][0] != ' ' and pair[-1][0] != '\t' and \ + pair[-1][0] != "'" and pair[-1][0] != '"' and \ + pair[-1][0] != '[' and pair[-1] != 'true' and \ + pair[-1] != 'false': + try: + float(pair[-1]) + break + except ValueError: + pass + if _load_date(pair[-1]) is not None: + break + i += 1 + prev_val = pair[-1] + pair = line.split('=', i) + if prev_val == pair[-1]: + raise TomlDecodeError("Invalid date or number") + pair = ['='.join(pair[:-1]).strip(), pair[-1].strip()] + if (pair[0][0] == '"' or pair[0][0] == "'") and \ + (pair[0][-1] == '"' or pair[0][-1] == "'"): + pair[0] = pair[0][1:-1] + if len(pair[1]) > 2 and (pair[1][0] == '"' or pair[1][0] == "'") \ + and pair[1][1] == pair[1][0] and pair[1][2] == pair[1][0] \ + and not (len(pair[1]) > 5 and pair[1][-1] == pair[1][0] and \ + pair[1][-2] == pair[1][0] and \ + pair[1][-3] == pair[1][0]): + k = len(pair[1]) -1 + while k > -1 and pair[1][k] == '\\': + multibackslash = not multibackslash + k -= 1 + if multibackslash: + multilinestr = pair[1][:-1] + else: + multilinestr = pair[1] + "\n" + multikey = pair[0] + else: + value, vtype = _load_value(pair[1]) + try: + currentlevel[pair[0]] + raise TomlDecodeError("Duplicate keys!") + except KeyError: + if multikey: + return multikey, multilinestr, multibackslash + else: + currentlevel[pair[0]] = value + +def _load_date(val): + microsecond = 0 + tz = None + try: + if len(val) > 19: + if val[19] == '.': + microsecond = int(val[20:26]) + if len(val) > 26: + tz = TomlTz(val[26:32]) + else: + tz = TomlTz(val[19:25]) + except ValueError: + tz = None + try: + d = datetime.datetime(int(val[:4]), int(val[5:7]), int(val[8:10]), int(val[11:13]), int(val[14:16]), int(val[17:19]), microsecond, tz) + except ValueError: + return None + return d + +def _load_unicode_escapes(v, hexbytes, prefix): + hexchars = ['0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'] + skip = False + i = len(v) - 1 + while i > -1 and v[i] == '\\': + skip = not skip + i -= 1 + for hx in hexbytes: + if skip: + skip = False + i = len(hx) - 1 + while i > -1 and hx[i] == '\\': + skip = not skip + i -= 1 + v += prefix + v += hx + continue + hxb = "" + i = 0 + hxblen = 4 + if prefix == "\\U": + hxblen = 8 + while i < hxblen: + try: + if not hx[i].lower() in hexchars: + raise IndexError("This is a hack") + except IndexError: + raise TomlDecodeError("Invalid escape sequence") + hxb += hx[i].lower() + i += 1 + v += unichr(int(hxb, 16)) + v += unicode(hx[len(hxb):]) + return v + +# Unescape TOML string values. +_escapes = ['0', 'b', 'f', 'n', 'r', 't', '"'] # content after the \ +_escapedchars = ['\0', '\b', '\f', '\n', '\r', '\t', '\"'] # What it should be replaced by +_escape_to_escapedchars = dict(zip(_escapes, _escapedchars)) # Used for substitution + +# Regexp that matches escaped value, checking the parity of the number +# of backslashes +_escapes_re = re.compile(""" + (?P([^\\\\](\\\\\\\\)*)) # Parity of the number of backslashs + \\\\ # The actual backslash before the escape + (?P[%s]) # The escape + """ % ''.join(_escapes), + re.VERBOSE) + +def _unescape(v): + """Unescape characters in a TOML string.""" + v = _escapes_re.sub(lambda match: match.group('prefix') + _escape_to_escapedchars[match.group('escape')], v) + v = v.replace("\\\\", "\\") + return v + +def _load_value(v): + if v == 'true': + return (True, "bool") + elif v == 'false': + return (False, "bool") + elif v[0] == '"': + testv = v[1:].split('"') + if testv[0] == '' and testv[1] == '': + testv = testv[2:-2] + closed = False + for tv in testv: + if tv == '': + closed = True + else: + oddbackslash = False + try: + i = -1 + j = tv[i] + while j == '\\': + oddbackslash = not oddbackslash + i -= 1 + j = tv[i] + except IndexError: + pass + if not oddbackslash: + if closed: + raise TomlDecodeError("Stuff after closed string. WTF?") + else: + closed = True + escapeseqs = v.split('\\')[1:] + backslash = False + for i in escapeseqs: + if i == '': + backslash = not backslash + else: + if i[0] not in _escapes and i[0] != 'u' and i[0] != 'U' and \ + not backslash: + raise TomlDecodeError("Reserved escape sequence used") + if backslash: + backslash = False + for prefix in ["\\u", "\\U"]: + if prefix in v: + hexbytes = v.split(prefix) + v = _load_unicode_escapes(hexbytes[0], hexbytes[1:], prefix) + v = _unescape(v) + if v[1] == '"': + v = v[2:-2] + return (v[1:-1], "str") + elif v[0] == "'": + if v[1] == "'": + v = v[2:-2] + return (v[1:-1], "str") + elif v[0] == '[': + return (_load_array(v), "array") + elif v[0] == '{': + inline_object = {} + _load_inline_object(v, inline_object) + return (inline_object, "inline_object") + else: + parsed_date = _load_date(v) + if parsed_date is not None: + return (parsed_date, "date") + itype = "int" + neg = False + if v[0] == '-': + neg = True + v = v[1:] + if '.' in v or 'e' in v: + if v.split('.', 1)[1] == '': + raise TomlDecodeError("This float is missing digits after the point") + if v[0] not in '0123456789': + raise TomlDecodeError("This float doesn't have a leading digit") + v = float(v) + itype = "float" + else: + v = int(v) + if neg: + return (0 - v, itype) + return (v, itype) + +def _load_array(a): + atype = None + retval = [] + a = a.strip() + if '[' not in a[1:-1]: + strarray = False + tmpa = a[1:-1].strip() + if tmpa != '' and tmpa[0] == '"': + strarray = True + if '{' not in a[1:-1]: + a = a[1:-1].split(',') + else: + # a is an inline object, we must find the matching parenthesis to difine groups + new_a = [] + start_group_index = 1 + end_group_index = 2 + in_str = False + while end_group_index < len(a[1:-1]): + if a[end_group_index] == '"' or a[end_group_index] == "'": + in_str = not in_str + if a[end_group_index] == '}' and not in_str: + # Increase end_group_index by 1 to get the closing bracket + end_group_index += 1 + new_a.append(a[start_group_index:end_group_index]) + # The next start index is at least after the closing bracket, a closing bracket + # can be followed by a comma since we are in an array. + start_group_index = end_group_index + 1 + while a[start_group_index] != '{' and start_group_index < len(a[1:-1]): + start_group_index += 1 + end_group_index = start_group_index + 1 + else: + end_group_index += 1 + a = new_a + b = 0 + if strarray: + while b < len(a) - 1: + while a[b].strip()[-1] != '"' and a[b+1].strip()[0] != '"': + a[b] = a[b] + ',' + a[b+1] + if b < len(a) - 2: + a = a[:b+1] + a[b+2:] + else: + a = a[:b+1] + b += 1 + else: + al = list(a[1:-1]) + a = [] + openarr = 0 + j = 0 + for i in _range(len(al)): + if al[i] == '[': + openarr += 1 + elif al[i] == ']': + openarr -= 1 + elif al[i] == ',' and not openarr: + a.append(''.join(al[j:i])) + j = i+1 + a.append(''.join(al[j:])) + for i in _range(len(a)): + a[i] = a[i].strip() + if a[i] != '': + nval, ntype = _load_value(a[i]) + if atype: + if ntype != atype: + raise TomlDecodeError("Not a homogeneous array") + else: + atype = ntype + retval.append(nval) + return retval + +def dump(o, f): + """Writes out to f the toml corresponding to o. Returns said toml.""" + if not f.write: + raise TypeError("You can only dump an object to a file descriptor") + d = dumps(o) + f.write(d) + return d + +def dumps(o): + """Returns a string containing the toml corresponding to o, a dictionary""" + retval = "" + addtoretval, sections = _dump_sections(o, "") + retval += addtoretval + while sections != {}: + newsections = {} + for section in sections: + addtoretval, addtosections = _dump_sections(sections[section], section) + if addtoretval: + retval += "["+section+"]\n" + retval += addtoretval + for s in addtosections: + newsections[section+"."+s] = addtosections[s] + sections = newsections + return retval + +def _dump_sections(o, sup): + retstr = "" + if sup != "" and sup[-1] != ".": + sup += '.' + retdict = {} + arraystr = "" + for section in o: + qsection = section + if not re.match(r'^[A-Za-z0-9_-]+$', section): + if '"' in section: + qsection = "'" + section + "'" + else: + qsection = '"' + section + '"' + if not isinstance(o[section], dict): + arrayoftables = False + if isinstance(o[section], list): + for a in o[section]: + if isinstance(a, dict): + arrayoftables = True + if arrayoftables: + for a in o[section]: + arraytabstr = "" + arraystr += "[["+sup+qsection+"]]\n" + s, d = _dump_sections(a, sup+qsection) + if s: + if s[0] == "[": + arraytabstr += s + else: + arraystr += s + while d != {}: + newd = {} + for dsec in d: + s1, d1 = _dump_sections(d[dsec], sup+qsection+"."+dsec) + if s1: + arraytabstr += "["+sup+qsection+"."+dsec+"]\n" + arraytabstr += s1 + for s1 in d1: + newd[dsec+"."+s1] = d1[s1] + d = newd + arraystr += arraytabstr + else: + if o[section] is not None: + retstr += (qsection + " = " + + str(_dump_value(o[section])) + '\n') + else: + retdict[qsection] = o[section] + retstr += arraystr + return (retstr, retdict) + +def _dump_value(v): + if isinstance(v, list): + t = [] + retval = "[" + for u in v: + t.append(_dump_value(u)) + while t != []: + s = [] + for u in t: + if isinstance(u, list): + for r in u: + s.append(r) + else: + retval += " " + str(u) + "," + t = s + retval += "]" + return retval + if isinstance(v, (str, unicode)): + v = "%r" % v + if v[0] == 'u': + v = v[1:] + singlequote = v[0] == "'" + v = v[1:-1] + if singlequote: + v = v.replace("\\'", "'") + v = v.replace('"', '\\"') + v = v.replace("\\x", "\\u00") + return str('"'+v+'"') + if isinstance(v, bool): + return str(v).lower() + if isinstance(v, datetime.datetime): + return v.isoformat()[:19]+'Z' + if isinstance(v, float): + return str(v) + return v diff --git a/setup.py b/setup.py index f894efca..3e91f1bb 100644 --- a/setup.py +++ b/setup.py @@ -21,21 +21,9 @@ if sys.argv[-1] == "publish": sys.exit() required = [ - 'crayons', - 'toml', - 'click>=6.7', - 'click-completion', - 'pip', - 'parse', - 'psutil', 'virtualenv', - 'delegator.py>=0.0.6', - 'requirements-parser', - 'pexpect', - 'pipfile==0.0.2', - 'requests>=2.4.0', 'pew>=0.1.26', - 'blindspin>=2.0.1' + 'pip' ] # Backport required for earlier versions of Python.