From e99d654183cf4fc7506893db16e11adaa56c75ce Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 23 Mar 2022 18:23:55 +0300 Subject: [PATCH 01/16] keep_memoryview context option --- VERSION | 2 +- doc/install.rst | 12 +++---- doc/news.rst | 9 +++++ pyderasn.py | 76 ++++++++++++++++++++++++++++++++---------- tests/test_crts.py | 3 +- tests/test_pyderasn.py | 34 +++++++++++++++++-- 6 files changed, 108 insertions(+), 28 deletions(-) diff --git a/VERSION b/VERSION index 28a2186..1a2c355 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9.1 +9.2 diff --git a/doc/install.rst b/doc/install.rst index c05ee24..41b4cb0 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -4,11 +4,11 @@ Install Preferable way is to :ref:`download ` tarball with the signature from `official website `__:: - $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.1.tar.zst - $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.1.tar.zst.sig - $ gpg --verify pyderasn-9.1.tar.zst.sig pyderasn-9.1.tar.zst - $ zstd -d < pyderasn-9.1.tar.zst | tar xf - - $ cd pyderasn-9.1 + $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.2.tar.zst + $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.2.tar.zst.sig + $ gpg --verify pyderasn-9.2.tar.zst.sig pyderasn-9.2.tar.zst + $ zstd -d < pyderasn-9.2.tar.zst | tar xf - + $ cd pyderasn-9.2 $ python setup.py install # or copy pyderasn.py (possibly termcolor.py) to your PYTHONPATH @@ -18,7 +18,7 @@ signature from `official website `__:: You could use pip (**no** OpenPGP authentication is performed!) with PyPI:: - $ echo pyderasn==9.1 --hash=sha256:TO-BE-FILLED > requirements.txt + $ echo pyderasn==9.2 --hash=sha256:TO-BE-FILLED > requirements.txt $ pip install --requirement requirements.txt You have to verify downloaded tarballs integrity and authenticity to be diff --git a/doc/news.rst b/doc/news.rst index 68d0a6e..ae6db17 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -1,6 +1,15 @@ News ==== +.. _release9.2: + +9.2 +--- +* ``keep_memoryview`` context option appeared, respected by OctetString + and Any objects during DER decoding. If set, then their internal + values will keep memoryview reference instead of full bytes copy +* Correspondingly OctetString and Any have ``.memoryview()`` method + .. _release9.1: 9.1 diff --git a/pyderasn.py b/pyderasn.py index 116ef6e..3c84666 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -235,6 +235,7 @@ Currently available context options: * :ref:`bered ` * :ref:`defines_by_path ` * :ref:`evgen_mode_upto ` +* :ref:`keep_memoryview ` .. _pprinting: @@ -706,6 +707,15 @@ creates read-only memoryview on the file contents:: page cache used for mmaps. It can take twice the necessary size in the memory: both in page cache and ZFS ARC. +.. _keep_memoryview_ctx: + +That read-only memoryview could be safe to be used as a value inside +decoded :py:class:`pyderasn.OctetString` and :py:class:`pyderasn.Any` +objects. You can enable that by setting `"keep_memoryview": True` in +:ref:`decode context `. No OCTET STRING and ANY values will be +copied to memory. Of course that works only in DER encoding, where the +value is continuously encoded. + CER encoding ____________ @@ -1186,7 +1196,7 @@ except ImportError: # pragma: no cover tzUTC = "missing" -__version__ = "9.1" +__version__ = "9.2" __all__ = ( "agg_octet_string", @@ -3630,6 +3640,7 @@ class OctetString(Obj): tag_default = tag_encode(4) asn1_type_name = "OCTET STRING" evgen_mode_skip_value = True + memoryview_safe = True def __init__( self, @@ -3726,6 +3737,10 @@ class OctetString(Obj): self._assert_ready() return bytes(self._value) + def memoryview(self): + self._assert_ready() + return memoryview(self._value) + def __eq__(self, their): if their.__class__ == bytes: return self._value == their @@ -3839,12 +3854,15 @@ class OctetString(Obj): decode_path=decode_path, offset=offset, ) + if evgen_mode and self.evgen_mode_skip_value: + value = None + elif self.memoryview_safe and ctx.get("keep_memoryview", False): + value = v + else: + value = v.tobytes() try: obj = self.__class__( - value=( - None if (evgen_mode and self.evgen_mode_skip_value) - else v.tobytes() - ), + value=value, bounds=(self._bound_min, self._bound_max), impl=self.tag, expl=self._expl, @@ -4694,6 +4712,7 @@ class CommonString(OctetString): - utf-16-be """ __slots__ = () + memoryview_safe = False def _value_sanitize(self, value): value_raw = None @@ -4743,6 +4762,9 @@ class CommonString(OctetString): return self._value.decode(self.encoding) return str(self._value) + def memoryview(self): + raise NotImplementedError() + def __repr__(self): return pp_console_row(next(self.pps())) @@ -5842,7 +5864,7 @@ class Any(Obj): value = self._value_sanitize(value) self._value = value if self._expl is None: - if value.__class__ == bytes: + if value.__class__ == bytes or value.__class__ == memoryview: tag_class, _, tag_num = tag_decode(tag_strip(value)[0]) else: tag_class, tag_num = value.tag_order @@ -5852,7 +5874,7 @@ class Any(Obj): self.defined = None def _value_sanitize(self, value): - if value.__class__ == bytes: + if value.__class__ == bytes or value.__class__ == memoryview: if len(value) == 0: raise ValueError("%s value can not be empty" % self.__class__.__name__) return value @@ -5903,13 +5925,13 @@ class Any(Obj): self.defined = state.defined def __eq__(self, their): - if their.__class__ == bytes: - if self._value.__class__ == bytes: + if their.__class__ == bytes or their.__class__ == memoryview: + if self._value.__class__ == bytes or their.__class__ == memoryview: return self._value == their return self._value.encode() == their if issubclass(their.__class__, Any): if self.ready and their.ready: - return bytes(self) == bytes(their) + return self.memoryview() == their.memoryview() return self.ready == their.ready return False @@ -5930,8 +5952,17 @@ class Any(Obj): value = self._value if value.__class__ == bytes: return value + if value.__class__ == memoryview: + return bytes(value) return self._value.encode() + def memoryview(self): + self._assert_ready() + value = self._value + if value.__class__ == memoryview: + return memoryview(value) + return memoryview(bytes(self)) + @property def tlen(self): return 0 @@ -5939,20 +5970,20 @@ class Any(Obj): def _encode(self): self._assert_ready() value = self._value - if value.__class__ == bytes: - return value + if value.__class__ == bytes or value.__class__ == memoryview: + return bytes(self) return value.encode() def _encode1st(self, state): self._assert_ready() value = self._value - if value.__class__ == bytes: + if value.__class__ == bytes or value.__class__ == memoryview: return len(value), state return value.encode1st(state) def _encode2nd(self, writer, state_iter): value = self._value - if value.__class__ == bytes: + if value.__class__ == bytes or value.__class__ == memoryview: write_full(writer, value) else: value.encode2nd(writer, state_iter) @@ -5960,7 +5991,7 @@ class Any(Obj): def _encode_cer(self, writer): self._assert_ready() value = self._value - if value.__class__ == bytes: + if value.__class__ == bytes or value.__class__ == memoryview: write_full(writer, value) else: value.encode_cer(writer) @@ -6027,8 +6058,14 @@ class Any(Obj): ) tlvlen = tlen + llen + l v, tail = tlv[:tlvlen], v[l:] + if evgen_mode: + value = None + elif ctx.get("keep_memoryview", False): + value = v + else: + value = v.tobytes() obj = self.__class__( - value=None if evgen_mode else v.tobytes(), + value=value, expl=self._expl, optional=self.optional, _decoded=(offset, 0, tlvlen), @@ -6043,7 +6080,7 @@ class Any(Obj): value = self._value if value is None: pass - elif value.__class__ == bytes: + elif value.__class__ == bytes or value.__class__ == memoryview: value = None else: value = repr(value) @@ -6053,7 +6090,10 @@ class Any(Obj): obj_name=self.__class__.__name__, decode_path=decode_path, value=value, - blob=self._value if self._value.__class__ == bytes else None, + blob=self._value if ( + self._value.__class__ == bytes or + value.__class__ == memoryview + ) else None, optional=self.optional, default=self == self.default, impl=None if self.tag == self.tag_default else tag_decode(self.tag), diff --git a/tests/test_crts.py b/tests/test_crts.py index 92b802d..8ceeb08 100644 --- a/tests/test_crts.py +++ b/tests/test_crts.py @@ -229,7 +229,7 @@ class TestGoSelfSignedVector(TestCase): "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c", "f8d91ede14a5ed76bf116fe360aafa8821490435", ))) - crt = Certificate().decod(raw) + crt = Certificate().decod(raw, ctx={"keep_memoryview": True}) tbs = crt["tbsCertificate"] self.assertEqual(tbs["version"], 0) self.assertFalse(tbs["version"].decoded) @@ -301,6 +301,7 @@ class TestGoSelfSignedVector(TestCase): "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435", ))))) self.assertSequenceEqual(crt.encode(), raw) + crt = Certificate().decod(raw) pprint(crt) repr(crt) pickle_loads(pickle_dumps(crt, pickle_proto)) diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 412f012..ae7b4ef 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -2216,8 +2216,18 @@ class TestOctetString(CommonMixin, TestCase): integers(min_value=0), binary(max_size=5), decode_path_strat, + booleans(), ) - def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path): + def test_symmetric( + self, + values, + value, + tag_expl, + offset, + tail_junk, + decode_path, + keep_memoryview, + ): for klass in (OctetString, OctetStringInherited): _, _, _, _, default, optional, _decoded = values obj = klass( @@ -2245,6 +2255,7 @@ class TestOctetString(CommonMixin, TestCase): obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(), obj_expled_encoded, ) + ctx_dummy["keep_memoryview"] = keep_memoryview ctx_copied = deepcopy(ctx_dummy) obj_decoded, tail = obj_expled.decode( obj_expled_encoded + tail_junk, @@ -2260,6 +2271,10 @@ class TestOctetString(CommonMixin, TestCase): self.assertNotEqual(obj_decoded, obj) self.assertEqual(bytes(obj_decoded), bytes(obj_expled)) self.assertEqual(bytes(obj_decoded), bytes(obj)) + self.assertIsInstance( + obj_decoded._value, + memoryview if keep_memoryview else bytes, + ) self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded) self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl) self.assertEqual(obj_decoded.expl_tlen, len(tag_expl)) @@ -5267,8 +5282,18 @@ class TestAny(CommonMixin, TestCase): integers(min_value=0), binary(max_size=5), decode_path_strat, + booleans(), ) - def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path): + def test_symmetric( + self, + values, + value, + tag_expl, + offset, + tail_junk, + decode_path, + keep_memoryview, + ): for klass in (Any, AnyInherited): _, _, optional, _decoded = values obj = klass(value=value, optional=optional, _decoded=_decoded) @@ -5288,6 +5313,7 @@ class TestAny(CommonMixin, TestCase): list(obj_expled.pps()) pprint(obj_expled, big_blobs=True, with_decode_path=True) obj_expled_encoded = obj_expled.encode() + ctx_dummy["keep_memoryview"] = keep_memoryview ctx_copied = deepcopy(ctx_dummy) obj_decoded, tail = obj_expled.decode( obj_expled_encoded + tail_junk, @@ -5302,6 +5328,10 @@ class TestAny(CommonMixin, TestCase): self.assertEqual(obj_decoded, obj_expled) self.assertEqual(bytes(obj_decoded), bytes(obj_expled)) self.assertEqual(bytes(obj_decoded), bytes(obj)) + self.assertIsInstance( + obj_decoded._value, + memoryview if keep_memoryview else bytes, + ) self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded) self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl) self.assertEqual(obj_decoded.expl_tlen, len(tag_expl)) -- 2.44.0 From 356b9d40299de10ae34d637ca2b4e996da912863 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 24 Mar 2022 10:23:10 +0300 Subject: [PATCH 02/16] Unsupported .memoryview() lint-friendly exception --- VERSION | 2 +- doc/install.rst | 12 ++++++------ doc/news.rst | 7 +++++++ pyderasn.py | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/VERSION b/VERSION index 1a2c355..c3cae12 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9.2 +9.3 diff --git a/doc/install.rst b/doc/install.rst index 41b4cb0..64edda0 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -4,11 +4,11 @@ Install Preferable way is to :ref:`download ` tarball with the signature from `official website `__:: - $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.2.tar.zst - $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.2.tar.zst.sig - $ gpg --verify pyderasn-9.2.tar.zst.sig pyderasn-9.2.tar.zst - $ zstd -d < pyderasn-9.2.tar.zst | tar xf - - $ cd pyderasn-9.2 + $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.3.tar.zst + $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.3.tar.zst.sig + $ gpg --verify pyderasn-9.3.tar.zst.sig pyderasn-9.3.tar.zst + $ zstd -d < pyderasn-9.3.tar.zst | tar xf - + $ cd pyderasn-9.3 $ python setup.py install # or copy pyderasn.py (possibly termcolor.py) to your PYTHONPATH @@ -18,7 +18,7 @@ signature from `official website `__:: You could use pip (**no** OpenPGP authentication is performed!) with PyPI:: - $ echo pyderasn==9.2 --hash=sha256:TO-BE-FILLED > requirements.txt + $ echo pyderasn==9.3 --hash=sha256:TO-BE-FILLED > requirements.txt $ pip install --requirement requirements.txt You have to verify downloaded tarballs integrity and authenticity to be diff --git a/doc/news.rst b/doc/news.rst index ae6db17..92f0646 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -1,6 +1,13 @@ News ==== +.. _release9.3: + +9.3 +--- +* CommonString's ``.memoryview()`` raises ValueError now for + friendliness with linters + .. _release9.2: 9.2 diff --git a/pyderasn.py b/pyderasn.py index 3c84666..99c771c 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -1196,7 +1196,7 @@ except ImportError: # pragma: no cover tzUTC = "missing" -__version__ = "9.2" +__version__ = "9.3" __all__ = ( "agg_octet_string", @@ -4763,7 +4763,7 @@ class CommonString(OctetString): return str(self._value) def memoryview(self): - raise NotImplementedError() + raise ValueError("CommonString does not support .memoryview()") def __repr__(self): return pp_console_row(next(self.pps())) -- 2.44.0 From 8315c9b26523f35214cd429f89ebf36b58a139fb Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Mon, 20 Apr 2020 15:40:31 +0300 Subject: [PATCH 03/16] VP8L has highest compression for screenshots --- doc/browser.webp | Bin 0 -> 23996 bytes doc/features.rst | 4 ++-- doc/index.rst | 4 ++-- doc/pprinting.png | Bin 50795 -> 0 bytes doc/pprinting.webp | Bin 0 -> 18906 bytes 5 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 doc/browser.webp delete mode 100644 doc/pprinting.png create mode 100644 doc/pprinting.webp diff --git a/doc/browser.webp b/doc/browser.webp new file mode 100644 index 0000000000000000000000000000000000000000..6556f0d95691841d910eef46c41571073828fd5f GIT binary patch literal 23996 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 VupeRJ_P7kuP`__. conveniently replace utilities like either ``dumpasn1`` or ``openssl asn1parse`` - .. figure:: pprinting.png + .. figure:: pprinting.webp :alt: Pretty printing example output An example of pretty printed X.509 certificate with automatically parsed DEFINED BY fields. * :ref:`ASN.1 browser ` - .. figure:: browser.png + .. figure:: browser.webp :alt: ASN.1 browser example An example of browser running. diff --git a/doc/index.rst b/doc/index.rst index 60fadae..b9c56a3 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -38,13 +38,13 @@ There are articles about its history and usage: * `Как я написал ASN.1 библиотеку с slots and blobs `__ (on russian) * `Как я добавил big-data поддержку `__ (on russian) -.. figure:: pprinting.png +.. figure:: pprinting.webp :alt: Pretty printing example output An example of pretty printed X.509 certificate with automatically parsed DEFINED BY fields. -.. figure:: browser.png +.. figure:: browser.webp :alt: ASN.1 browser example An example of browser running. diff --git a/doc/pprinting.png b/doc/pprinting.png deleted file mode 100644 index 8f74110e6715c2bccc18540e0979519f8ead1327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50795 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 z 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
@^2}rsafNs#_hM%v*ry_ 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 diff --git a/doc/pprinting.webp b/doc/pprinting.webp new file mode 100644 index 0000000000000000000000000000000000000000..2e94c1ae41108359570de846858d61592979bb9b GIT binary patch literal 18906 zcmX_nV|1iluyt(PwrzCmNynJjw$-sFnb@{%bCOIvv6G24vH9h__pa|xud`0=+EsO) zUR|f2s#cYgmY$OX1JjZc2WkTO6n}lKS$|1Ffg1wQ0CS4BF+yqtFmtU@Wjc8=uF#Jz zA$FAaW6Gy&TPH`N`TcwFXcQA6u4}6)&Q#3_RI;jOP@siHSI>ZEc{Q2el17J0Nks6w5gZjEJmMr&2|_0gl9zX@bhFJ`oAN?euJ#PVIkj4C80 zX!1JOX7{nlKwT+&zZ1Q#3pkx{Z0&KkUvDiDVM+P*FC#_)Vi}OBVejK+&JbhV#)b$E z97L^eY}gKr{7^Hp7j|6VKysM^o@xQc;_eax{F=G?9jVq^sa9JL&e9r+O@D;_8Z@CR z2*qS{3;GcQk81Vjxao08m-ND5cfLfVN9t}H(th2WP_DJrCK*dzwbFf-?b8XM0_5{W z>Rf%`Nh~I5m|L4R%8N3Rf+&NS4fswhlVO_cyS0XE!5b}A7?~$3tqzX=Alv_;l!GzXazKro({Wal ztZHjZY;;L9nB5|IX9!{X-JLM!LV(-5eR=K&Ca51ZyL9e)6q;147mL5Hc?j}+<4Ne_ zt(>{g@kHr|V7#cD?|F!S+LCar%FpH%lBs7^$9eP2Q5FrW<>794{K+W|t#vD{^o#dY z#p7m!_yd}!cAp`TqXu&jR(vudL;Ivj{8?}2Ce=A`sI>TUw)sQ2SoqHJy4Pz~Vs0vBz;tdYQ=Ro&mz3q>u~mA(#BDvH4Y z7Kxs*^JEQ%jg=LMp($3Gh%oj}IZb&L07FZ@@z%+INndOu=F(%w76+aW0D~~f@XjWe zYmiOL7vI9uJp(|;E1o+(jiZ)=(-0;T;NXlT)FH<0We_2=P%HA&KC^3kC85Z(vZ{ zBkWNBfFHUl#6~zf!sHYlEoT>JOXHx{bv?{;D6Eu^P4(Ouw8_)|T;5t+5JSP-KB@lw z?@B@J>{3_6mU9W5ryl*9ztmaXTaiWU!^PuYc@O12QJB-$r~rBglgFz>igYj#f}w>G z;5pFH@V;(LYf!g+jH@e~Rh2a~T z)iV+TfWW1#XA;R!-kv4b4L`JEpT?{q13ylM;^Qo?;)AZaN=ND)xn<0?&+y4Ic^#WU zP%iULPcya49>!oURSqDO%1OEC%{0uK#%=XDVMYt}ktu8-OP#>+%M`IKnboEYmmQmg z;b$hB)FtlTCn!t*G0t0F3F6p@*%3wo{abV?*2L8O!kRZ%InZyGF$*({@1px!-x=E+_IIpNE|*hN|dxyB4tLO zYm+(j<0?vaPsXtBQ?AgF)bo2Zopn8OXHk9eSSsq+_hOTj8%u4jL?mxApufNp#~@T* zEO`g%E1PQ`S{pkq#N#jBCq8stS73b1ZI<@WRBnyT)NDX9CouGKtc8wg`g?XyG{Zrh zpx<0wsi#Q>GjD9A^(5I%Z+KT#!t5ZgMJcJdv?k!9x-KTY~G-pbTCU;uXVh$guM|4t|S#4P_U7)5lIuu3> zl*=mjgm$A>DHvK({{BeUe-Y_V3IQ2xKix>LuTk*VCVzWAd4$3_p+AAn!YV=HF1jIA zRN{!&Je0IpY!2c>hE~n-H$;9P2G`U=1{gxA3Vt_K=7fG)<_fw0L=BW;%$LaxDK_@k z>$U%GJAVJJWL`z~-PLecRS9aM9XM!C&T>@iSwb1=KUI8GLxESbLBk0P*Fe{T4@@zk zQodA1v1aLy`}0?4(uzy3A;xKRan6MPlGJ%GYpS2mu}Fe`6To%;(X_^&MZS9!z4rU~_uV3pi>UwZF|V10Y@LT* zRiy8adH}25Z1IIC`TKhw)H|j7{<+4HW@Agk*FF#m;6IuBP@g=08Tms`d^*4aHgTqp zHDwz+{`Oz-nGn^o0_oCsCaOG;1j8q4=txo|MZpg>(##s1NWYKGiZ=tmxW6LWIWC63 z6$Zf<%95dv^6*Yx747-$yV~=+Q|xzb2IjAQ8HPTE^8LDCmtHY@xc{|)dFS%)<0DVg zd+pi>=?mh>&_{bn1=3O=OJLP-gBO$)`P@lRlhkwcE$Cm; zRqqyAmX*%wUwk>fUZ3Z1$Q%=;(uYQ$>e3|bkRYil!FX-mXPM=E%ks*@zVM6tCeGqv zjIYr^mYT{>+ff3E$m~U9{r7}SqQf#)M*cxIMdwBF`ti{bP!&fk58=Ct8{C4JwgiXF zOIL73c`aviR1)1fXu45 zZ93scXNncG3zRuhe`+MIOPA0SM4Z?Gdto!9#PQ`egU{EA&>nr89?wx*5LZtLU1B&# z0i+bt$D)_~EqkF=3T< zSp5W_RnD3dO3w0oJ)XhY)=l3)sHcc`J{{wUvLmA!8dl<_)~I9uC6M3QDJTT#mWIZ0BY10excadD7nZ!>;jqw> za6yot7WrMZUA2f0{AP;LI?|gFp2*Z~P9mvXzA|URAeum5UkRE|_}Stp?vt0^p>MBO zql^3d6(FZ6e9P&VJCGk4_aX=JE#Q{??(4_kiCA+Rv}nk%^!Pbc*Kg06hCe%ZI?r)A zF=>pIyInxR^Q?NnIR29tal(E;#k7pYvC`p_1#S^3zxf3T<&W{-#T7xmd4pL6^`hkH zeHl1`z66M^#gfwp<()i0wTO1Ue=)q5Om}59`(Vh98mAGY;QPB4vX3gTm!Iw@>9`s? zM`Rup&p!9EQ)*$lAO|;Ow5~q^OTg;sC29LxIa!OndbBH4ifX|Kl8bm04srmkI%j;s z?60UPHBRACruJr7#oyF(745kra@3rT0|1Q&xtfMz1_Gtg7V5lAaLBqIv+6z&sPFfk z<1n&dvzyCKA%;VyKeU-@1wL8^0Q7mztytei(FA{WacV@7EqD0K9U>VQ^NKfs^E*9v z0R}=R9i*xfhJ2XIV8XUJwFM8U@gdP^7Bi8!06)liCFR=HbiCzYpON@l!`#e2#)PNYt5J{RQj z`(+&mWbgYS11DhqL!qOZj42H&mc_$x%rj( z1{xeDot@le2F=|W9w}cM!ulLP`@_jniAVMx+lq=Rwq`I|PzDB1@?cDspc$c}O%4aK zI>CQ}7eJ{5i1k+!3bP61!fSBWR-=Of76G^dpqmO>rUHq6F*8+yCvdeQFakr=+4<_f zh&Og0i$nrG8b3u3c$44aA0IE{f)rcx922#b?6-s+B?A1l_g+3M^P4^`qlHs`;ig|Y z?D~+4O=lCtLP_E*-CubAnXlfC>vG$mwSQsV|M)oif|h}PYj_;mj^8HAd31cozG&%% zRe=k*yC_T7=X>wt2;R7c)5$;S+k04b46UOv#3qo0$=uxkRlybUTSBL+^b=*1KNHM! zTA6Yrv}jNHG9Xw|BA_9Tf7jxJpd<+I&kld02i{heNPf@D%IvCRDk01_NsGE&mCIgu z2j_yz%GI#){uJv&)<|m%6>ER4a;1JcPqTTDnD0G%LDM$M=iyg%E zBZv0%dE^X?&}0`P7goiN$N!Hm^!c20NTOHCp^pyLcfN}hU|TPc1vGJ(tDCeqq=X8K zvwLAR6?tXm(xdi4)}r6}3e=rvWf+Hhzs+39Ed|xenyv(P@KMTV-g5u_z0M+h6q5G+ zy=%W=>%HUl*?8yuozl9j_4(hTr70J$Krqc=^2zb}=b?(eXrF;UN1(uKO(WCkOOP!L zg0@Jzl8C6Ll)k9dRDbBxWZZOR`B_8_emat3)zD~}r~7-h&wU1Lak1^lRY`5$cc|wb zeoU)-r`p;)^*WJx^4p=j&H&B23@krt%hMP7(veVYEcf?*Zb<4iV=X9QSzl0^(w>gK zXqCw81QcCe-0PBaZS5y@*33uFwVePYpY)dG{j`_Q*_oX{SU6d8*>aw~GXkE9UBk|7{se^~ z9Kt?5Kjmv|I6lhVzmDfk~M97zSJ@aFsqK`%_+C(=sj_Z=-uqR(6SnR@tUtVS8m~QL0P(|EA(Lc z0-%>|auho*-J!*0HgIgYjl@Kv!=?Ucjrj*qxScNE@yAA|arboZKEbN&Czct8Q+I;# z$F3LCk+t=poz=5IK3kt1#)QLBeabPu7&{eb9-}Rc0suZA)MMOWu z6OoKwY^KsAW{%>`*=vAD(S=MeG`kgsS(;0%7}G^}6iCCXk4iMdE=FDnhKv5R)F3CX zj^oW4T4mR)gHaX_GSNpYVExIPqpOkgVhV);4)!m!SKRs#j5(~bg(>u#4vC|H!bRKZ zPjuP7V@z__D61eQaTtP_zNQnsZ^dqJfA^FLR^6rg_8@J!-9($# zh$QpMVL9d4<^_djZs=^eN$22&StO3=y`m|^(xY?g9j%qk`AAmHY<(%C#+{>n_MG@N zWGR)UYUVAi;ul!V>sZB1uCD|P)V12dE? zp*C0DRBJ?l`4;mPD{K>`t`b?TYyxo?D{hB81=KOqYQb?zv`uR?%?F*ld(&)}=5|;F zgU5<)Bc-lwLYm=!GX9K~-YSh~7O=!j|F?Vl`ia!~^TUWE>)VhY5sbG(WP(PI9&yFDBum>Y($oV&!uCb%I}>1bZ>@&jzuNF1|}+vNaq zOk2{q9vnQYN^K9btWL-O6FGL#P9X2Z=MhA*6QUpXsq)slr=$utyj8Buw_9I~Mjm#a8D znx{YL1rL|@y=y%|NX$&o(5+;_YwEqB<3^BObiP%0jx(mA|55z?qJR@IIE`w{qrln+ z658b>=2#l_oW5#diy88BXDJ=s>RtARzWGAe%@;Ni3clfW{q%5V|1|(JEBZUnZl~4Y z{=Mk8V%4gf$o%~Ut<*<>a;rtwIa6o8n(7)?3GYf^;8X*YzD%xV;Q9ZW<7PUI^yF~b z-tLp*F}(cnIDAN={oC6I%92rb?s=`W2-q7tyd(E$cvoNj83!{_{nG*$d|-(i>UADm zl-5JUx=2?oBUd?pUnWE)Qt9D7xsWuP^E0jGlpk8FF+!^!`%-1v$wRB?%!#l-&H=nI zAkC)4M-$n}U=_L*hWJNyaFv-<$_5x;ogw?c*3$5^S?unr#Se*RIW%fdu#nS6c*x~8 z;hlN)-}-Dt{?prT_?6|M&VlZ=eo6L{znQO~7J4=4Sc5#>ly7oFzICclw*jylW6tCC z2~hLO6Gbm_8YqP-3~&n7)c`o?+E3O-sZ4LyWE%3bYoV?1Wjpiv-GqQlR))dr_U4mv zxr;EZiPd?povB39$j7&}kjF+5)X&X&nv|mrHO4XhYCC}tkIJaIRS?a{RpLCpJWr0| z>vY6Jl?&H&djnsj2D2Y^b%O+~nn~M#Sh9Jr zh~0UZbF`-AIrn^w!jAQLYqz^6Pfpm2d!-|~PAGnN9>F70*)qpY2|6iTUk;bATmhw}82CC=$^cchBoH&+8vc4_uuO6!EvqRA1L)q~Eu17JN1u!H0B#S(7 zIfi{gn;Rh4i;)QwV*I{->(HCQxT|EDTZ+^ckm9iF@#_~(-7R;ig317Ma;)C z(^pR7U8jU8K~f7b!7zrB3bEdTG8wyWKe#T%#75cgsU!sc^4iQVaZLRRZAZ-Mt45Vt zB{I*Fvp2Su9W;8)XB3G_leyn}>132}tu*3m|S|jS>Fbc zqhlF?KGjITL}Aw~rl|%(v^deg&o4!NZD;=>$2Y0%52rY3%B!4;oMXpdO^xj>B0<%b z*|C!@`T34#tt1&&;>RDZ59Rai=Muzd_5&u{WFP~^gtfoQA8(sRJ&5Tx+G2$Ct$5$? zRyUgP3<11r*ZhA!?pi=beETGsv&d3!URgnR{Ik-R@F*Q+4D+3%PefLxlapg1s2#91 z7J!H);khFKVGg0+nDEdXQsg5r57PdwmwP{V%1Vd%>unZ1?>0%t+CN_l+c9C$l$VbV zl#Wr;%%Hc6A0Ho&suCAE$HCwJV(ZNJ9oWGTka*F1-V@LzP&Gl2C;#}X0W)Xm)NScU z*N;_)H`rd@FbIzYfk3MFhv_nqJPF`#6B)k1hCWuQ_d%artO?|AL?n_WRn@_5#{m*m z+QPB<6o3D{m>bqlCF}v^8VLoqY!L_6kO)ZY{m!C?BMXUp4j+KR2H?eGf};HWNK!xC z2+tF~(C=qlU*4)3sew`;Bij#T4hOn#nnB1O9&p?j4~+8bgjIqE5k`cifDcV37;Dl& zaV2o!h5zU#`(6N;gA@;3@G^di34>b$r(D5|0ozydhOA}-CIWXUUeUaJt0#7)Y_9Sa zMqS;d_G1yS91#qU-kk4zXXMuvN(m3<9)!Z}@xz6J!~wil*7OFQe@iEILdZ*uoh4Gf zf&EtRT;TMa)JAH&?#l@)SU2%Z4U34PvCyb=I0s{zKdKpZHG!qD#(K)mq9?EKln0(t zW?%vk%8q>qpGS9vBdX7@l$NXpswe;Y4p0U%9BVqkVH~E{Ze(2~{O;-9DID z#RPdapWnn~NEXOaSl)n^ZboF_P5e>(GjUywS(`VIo`5EC;P#_n@#wF_THr_-o&DkJ zz-%Q_Dv?7&XiXl?RAs{V7!kCg?lewjG)Q{!>Y&XUiz~Bt>nF4B`ojk&Be~*)vhX7( zKMrjt2s7)ejrX^-oTP(y$|_ViC!Ew0<14Sj{7^HSGh^Cz zkA~&rqg8(IaF9*zQJ_r4nOlgPW+8(ytL-04Kg zQpPO*Pp%hUpe*PeDjO?@eQJIpRtdx|r<*Q@Ht0DC{p)FHDTf>_=jLz8 zRX#1&%}%Wm>3{QOs<-ZHz+V=Mu0{mw zOPu-GMVkM%q|z#9&e@kX=hA{}5))hk2sm2%~+EdgMAX6i~GyHdPH9i>iuH4T~HvRkPd+xe8mEgPm>4s=7uF zW8f025n(x*x$I>}$(iF55C=-x!C_vT`)cR5JB_b_4^FY4T`p6dWtO#xwh5hB~Eh!(mf4epQG;T=L z-l6Sv|6^|FWUJut>^h~-GWqSj3izfL^kQpG106H<9w@f>9-6EwVIt>upfv|IRrmh^ zjMnYL3zv5Og zipglGB*zX`x zB4-}$^x=SUlc({#LKvV%L5xFpQpjnKUv zO|lqP?;NH)CPHDLqw4|anx8fM@#{I)U9Gs(TkQBh3U4@^9F3!Da|UM5Y@XcIkv`e# z5x*kp6E|7p8?7NFw`$)n<_k(Op9-`$qJ&{<<4!gPGR8QPgzYILZ(_Ng=3B!t!Z-Oz`^e7#^Q`aYJ_Y-q0%T z9F80ML0SyuFp8Q@fz|hc_(?bPo)K*~Ooo`WK4R?_CQj;1=U3}Z^8B@C+rQ7$#x*HW zB2WWpth2ORB-j@7b9|`IFFg2BdL-s*s2WRoJ|Q( z4wX|G=cx&lsxrtYSw@6t6u5TXJ7M-xQ&b5QL;OSIfEC)-`Eh@cxJMiygq2wKwz>MN z2aa{_<@er44+I7*&5^J0-K46xNZ-#Uqqs*_8CFBk@Tvfywk7MpGMJ=hv#>u3dt5w^ zP1z~CV8t)#jCFS0B}-TZDYgQ{g#qo;_Gl-2=MYEL1G~QxTg!}7S`i6Lt}kXd{8sL7 zO=x^Hz2%a_t}_3e!W0Spl|}!HRy{o7K~11};tJL*Pr2orJaMAzR)a9aN8O#^p4o_2 zie9IDl&Vq3H4a1hT8+M9dO$x*etH?4=CzP9@`L*Ft~zuMjcdbM!t>)N0AI1m+M zbpk+hd~`L8d}T%FN19xxJX8wQkWaOFvV%+dxsB!<-Iw1D1o?x%jq4RQPf9?PGynvPV1lcp}DxN zJJAcpcG63l^zdJ3Be5jV8e_#h!hdG@1~iMA7jQ$$Cj^U~VQn`~tdUM&;sNANviF2U zBGiJuZpbC35_)JvKD>cYzxxdT%*v9*#$Z4I&Q*Y6KLsH8x$$cMoU8z4=8q5p=dTY! zUy+us+Dq6&#K$C&#deT@5bzzqDMEr~Q^=-FuWgx@2#1I>_(yLD+l?9@0*k~5EQs2P z8z`kaPhA*!0V1c^d z^;`K}SwB(9HM6K8ZLf4DEp=o$YJwrP&E1g6-)sk(I7AXrWk)Y*Hb^CEG6{ejybM8T zc&k`*h@$heXrfb&Ix1*gpApZos(IidhuPmC7giUI-jT%vc)RWU2iwNXaX9SDdO`K34${Z9^ZAwEc1(h1eD7IXz z^wK$Kid>NzgH4Q3qW!pfO2{cjk|k+r#)A)}bt_oGtlCc2O%fpu-?FRF=XM;4yDu0wF5e`q+O{)dEauto(#THm=6Z{c6S z>0hzcAq54E;G+D=ovH+FJ>e#s&c_d*fgng3XX`$~{(2Uu3{5x*aU;!+kbx~Uk56jI zKH*c2K$JmUA;AD_fyiPf%?}T_ydXsJ!KjboKMki$4Df_KiLQ*HsDn=zf0wLH!!gqt zw&08jjWTTJ`I`cqTnxe1YRRqQAAfP4G3G#7!F2^eZ~6T2ARk+I+s(KS!gjg{tw-Hz z>hi*lq1}-t?dOxYcDo3x$F%vDfBIWT-Hh#b2l^mOKN74Ae^YND$zZJ!GHq1++Ue@> zAKTfh4E`@g9$_%F?EP45icU`zwFjU#Q8*m6yr$^2`(3*d7vapSMgO z{0xu1(Vp49eciRXP+*|Bqo1{$8($^};=|)(x1OGGh!;IiK3Hf<=8!^NAoYJul!l*uV**4(dU^Ihvq98)v zNGm!X*kyZH3~Tj}&=w5Kc6Og>=>6<`C})J)53>-q^)Ez;r81g4&wA&a^0K&{`+sCW zjm;-A*hSP=-jeVyQFudK_ss&fdO!`Hmr3=0kB}+xSB_nB)m-roR=) zAPv@SdpFr?A8SeKy(}=a*SKWA?=I(??cK{Uou*++$(rb41NzwF&3U~!6?7vOK-Jv1 zcpqn7V4UTFJVYsatIyS{`!F~vj++MMhFsB4w$WPkfVJYYK@z`MG1v8WsGmPgE0BiH z5Q`JEeXKXS;Eh}7UJvP9k@?XS*ymM4b_ue3-kgfXi`cCFHGVC((rod%yu0<3UeTke zoC=h?X-6<_W`aW|0y&-yJsf@BpuJCR3BKPfH5T%HOY-}KaU}4*ALz;eCo&{$jl-JI zzur3e6d6bAw(ht4p0q)xYS4qW!xfQ^y#3WdrWG~FRvU=PfKe0mKuM8)QpAYyPz-bI zqI)bt`Lli1GjFJ9M;Gg0g-ZfJC+zinArxFgd}xya+s5yb=d2S6zJnhoe_8($c*81x zg^z>Jar&lf;Q!=cVI-R;PF&b$cX=nsx1F12tpf5Y9839h0yS=(Ji6Du3C=`3(LR{N z1SA_fVCJa4QUhih=>2;K;ronDujtXvmya7ha8%1a`3#>+w(w&=X}O(NWvJ=RU+@}8 zy2JU%$)Ptvu8k9~xcq5Bo-?`@{e#@K7wEd_Hsa_cdZK-ad}4uA#{tZyfV4-?ya~W@ zz!qeu92x>XiRs^ucy7tcK5@h+hQ1|r z03;!kAmnG?V+0$p^Gkyy@`ecszkKH(Cz!>+V3eP zV&sU#C1WSoU>d-5`;6Rv2M-gJ6C2G8!mxqgw5c8?aLbccLv2*T!HY~LIIhX-)5y+m zB!}-56{~l#5t|sXt?oJEXx{>UO%Z&35f#yXjwYy_7W?NiL7KDY$s5vJPZm`Ld}ulc z#~WjbJ&wMlUtz(~Nz6I3gg_K6BE4C;_xpAX!f)^3#M4+vfN_)KI z2IlY8STuEE;DA=Bk(%B3U_H7ER|d2SK#2{;`w2Kx6C=+64}1L+qU6rYkMbp zd|#I~$);neH;NY`O~9LAc76PqyzBQKWjxX41ghA>sDAY7H^5yCj?eY9)asB1c2zY# zodln#1dK8UeN8^GV5@%kMkwyfcVCe{MFnw&4d+?_&Mh4UH&dE_?n01h{i#NE!qz+> zkyE4i;S+K{bywcImjbxFG`#fLw24PtnMZ=kZK%&AqCPf>&;7Z+>pq@TKHUb@1@ii;Cl%=ZOZQO!b%L zwfXgr`uEI`0=}xOvh9n{?yg=?9Q|iD%Y5h-{`a6(d?#nT1J0@9H&N`@p|T{>lN(K1 zUH?FP7?M9}AkrfG&jZ2v?IjhkD~V9JuL0YW#A~&}S}>z%`Brsfdzjq0FHjc!C$|M? z%z?|@;9l3IQElm8E(=pV0d>`&Q!djz_T$kG{e_W zA6_)&Pp*s`L&T(S0V~P@vGL`h4l-uN9m$_KvL{EhE#Xh zU??EP_S1{14$xG{QTGd<{4?(?M8Bzle`)GX-@j^nFn*Z+4o~jE&)ndJ*BLwyVRM*9 ze1BG+KzzuZpp`s>1vrb%_t52a?xLMa)6XdE6$*7Y;x;k7*BP+lX`3l9&8nH9Pc0PV zll*s!WNf_)h_eL3Q5^P*3tDtQqPY{dnz+V@XAwZUc+TxylsKR^bjbz=z@WA7)r&)s z60~!1R4IHfO}AWQ;6}w9_00G0=59k>WuD`B1dQ)Dhkypp>G>7jPK5`8U8fuW|Gy+s9i-517Y=}v)ZS1FGqEdpb~>m}=KplDA6Tz(HVbnD~EI;h*gL~4@K zU4vn_qTzbp115 zUuC#q0+at9F~u4gZYl>N?MCD*{0`HOokHTc@(Bz)!Tcx66#O{+z<15#%vOfa_Vt`^ z)1>iE{to=~ImOsD;D)ps0eiwxpnN+ue2q&%5*NYoSw!l;x|Ap(5Zlmb!TnGhd->pf zL^ys%9N-GCtE_={ea#oL;RJ|EQMTuZCLd}Rl?&d%f8?t82N8P-yq(0EjPkB(z)zQW zs2lJY5_<3HWPux}2_NLNsVk7s;F*PDT#e!*sKWidGQ{6%B}I4iLX+P>bO`>If0hRA zL>j1(X|GjG#f39~G-jV+QyIuq@^laoz2Zi>Z+=Od2;u$X#3&{)p`aYWDcW$7^$1>c zdzGc-S#hQFfQ42pdgme%W~xO^O&wYtrR)hpKa=yO_1_MHzqZJ}eeLlq+y!%>^CTzx zfuZ;k?i%{vBf<6YpMndkdGztlO)E4Am4V-SBXs~?giZq$)vPG)4~Al7=#x;$8UWHh z4q$*Z=&9CToS}fYps`>Tt!jurEIKyOJm(#?!wRa?bpK!H5r|j=0P{RrsEEFaaQDT& zM47IbXK4?^(uhwmKz!4~KbM+U$dFGGCE8>GCAQ!Zxzo?Vk4$b zR)$okKFG?3bST}C8-3+-mdyf3D0SwKWbhqIt@(q&`D<^87lg|+oWQCSWrj@8v%_+1 zEQ74$(KZ$V)A(3qv08M$-^K(#EKJ&N3bzfGFFuRL?z0LV6DGd=Ft~B7`;k+UIDeg& z(?F%!ky1r0&X@usvWW|xW0ImahWp(?7|e*5oBPo>8UJ!@tT^Z^aa@d?0W}7%i0v5a zgzqGP*@gSIe&!;G+10zSZICvTu_D~DwQZo4NZLnIvIjfOfmPEQ7Oz$GAF9ys6-E#} zSQ?H%>t+4yMijHlf{#zvG1Q)14`W#WuP+#%N4OK0HYFQXVRP@+Fai7np&RDi+%M2kd9SqH?wx;q{;9`Ax3j&*0ABNho~u)wMrB>dkaAQYI;UC@~cs>faj zvdZZj)1{%XCTZOA+ODK!!Ve!(rEa-13G)}pXZKPMPxk^}VFxOT;c4`>`0RYGxW&=E zmR7zbo&B5mPa^s1`5-12y;7<`;Bz-!+uQESkoP9QrXFEYx!g?OvuO;P>Z7R@7{S6q z5`=S`+&DFkip#>z_|%_o@*OP2-^p_oz6D@CY`~wiV80{RV z6|{#EQ}(zsJtP-~=BIrfOHqzSu0;Z(7*B@aIXmh{IXN7&|B6HbZa7;SJJa!j={>mf zp!pR4@PM9F&h8xoEkIPf`{WZ}~2MIR|3?ndi7wnBh!k1#NPlK^14d z*9TE|e{dhQcx0<>C&mNe{{SKxec=3-cO{d!VZ0PF)ZqE`CxmCwhzk=ijh33%QqC#l z%#!K5XRcUw-_pP2qK7gbQr_hbOqKn~{Y{&>SBX@T)D}2Txm4e0`fP z9XJt>uXZto{k~+C}-f%z* zE;%0fEVVI2m;FL9s=_#qq%iX8l-_AJKz#nZY)H0TdNFo!u_{CZ{rlbr&I4SuvjNU9 z08Wc#29Qw6-<3&mR|#IUrYLvwY%UHpkyf80&EKKg*VEZWyC}Ui7sE=D`_fRz;a9$c z1QIJ+aO}Rgpl`nSZZT9O3ab*y4l-@Mm?gX4DOH&hRuZJVgbPo;R8pOT$+`J}J!~!q)EkG^0EAVO=*fvwgv3+aj{Qu)9tU9giETSvqp?0oCcEdkcx=hBP(+9QlxXXBW&KyQH_3e}|Az5KY{}5dP zE6ZxK^{IJU#f$Y%t5$%dO&AA4yjU!hZj!~b$+q@|3c2ZLIV+ob%6NLtEX6e$3Yads zM#bb-auWIJwfbhiQy%y|vk$N4oxR1;V&gmTJa5{8d|%L@stICw37tSi3%HE!Z~AY& z_04F4?=sKpMcdn-rp0uky;qXUTDCLMZhb}hIhES!#q=G^#Sr$@UIP8{rpJxB^C>Hy z<;n~78|o}>6+Ql@+FwHzcWp;(_d%Fm*I~5P^HF+uRY&MAD?e?V8RBvL&(#jFt{Qf& z_Zr*17{jYzha$(L`uBuqAm`FBeyh4VHjD9!(JL!0O?1?YD&7pM02q#WT4a{Fgu_PH5m&}kF39pRY*%h-)%Wutr@*K{z4#hMEiQ! zT`U*}q8sfkRivEXIlt}<$EO!vBZI1Yk0|nq;JqE7K*%kqK!srcerW0x1g6}3HHHmy z_r3C+&9;#h^L3r0ULp1E*9*?Ygh8Z&ApCKW*@DD`434@IFy&?J2&}&35i-3oguz`p;efvbtJzF~RdOByU3ui@<~#fXgFLJB*DZ{T^TlfDXc=g^!;8w zFqgOW&1Lya8+Zp++57skRZQ+LrRCbqOQT}r?GWJg$jHX(*|*M4I@!R<7H5sQ(zE6} zS?q#hfKxAS^YI4sT8Hez~WKtmKj9e+F)O|AO9%hKkgp`Gdcnnh z6E)K6I>zl^;NHN<23cJlLQJm7QPE1B#gt$8l1P&DTd4oK57MOH3UGkzBv9&rb_o+1 zWf=~VQfbwS==by8DQ4lhWi#c}U1Z<6aivsr3S$t#;b4ppK|mQQX-N#cMMZ68KM&`k z7rVdaUz|Z()61_bTC)I1R!#Mze>o6or~XHjfs9C1d-Ow@aXr84Gd05BQJ^9bRD}&+ zSU(ANPgus&Aidb|S+iI@0|I@DhOr)J29eT&*}$;itmhl}hv(q#n76A4$BKq=Kpuj^ ze9o=!gN7D6mwj0^8gH=CFzpdFQ<{xhSYpdzQvGKs_r7;d28L^r@>C|3Db~g-y!eNc+1@)#gF}iQKbksdQ|i1&)>kaTdS=Zzs8E~2VHe2b z@3dDBZbO$Y-lF#_R$2h8MLduC+(I9#t?%*gsya(@gVUb#xBF70h=1vmf=?FP!1!Q8 ze>^H@3YY<_lt=4MHLVh5b6d*I4w;9tAsJ8l{*^>gCaO&V427htx~-L~l()YyLfVHR z0iPaWf+xv5I@!ZEFqPlff8}cC8TVCwPlMvf5?`hzRR0V52c8(Uhy`&%L8{~{RD~dr)Gmok0YVHfbWnE5hYMJY4YSl4uo(uUQ#6TQQ*p9 z)J4cn&o-O~CE{eSu9#EAo(~FIaWUe|8Bt0EN2%?REgIm#k?=ITlgpx{KwTe#Gpkfm zk{rR&;Rkafk;cVFO#m}yQSrNx!@#tSLSMRmWB_-mV=_32olt)3+_^o-t$`zwOY8(& zpR2*JH(-8O83ae6mWvJz->t@Q6uHxKh7N)`!>GqYG;R+VB@iJ`x*VAX;gAC_9dQzk82m)L8q~iyb2#yz&Z0OT+(Es=bOKB{-Z>7uSl`N(A9`B zu})&3Jw!0nZ(!cnuBYT$C6`i!lL;IQxfMI8{~;;Szv*1=MBMF5Dt0E+H~tye*Juv;4j~e+Lk@pN zdA@(#&Qnru4BD5Z6YWRmB>l950h6Q$ow+lKK1WEL58BUR5lI-Jg@{bPW&j+2CoSFt zCK*u5>|f4QRB{wa`o0eXorShhhuqxhAXZV!5BGBj8h(Ta=rpjKx7C|A&Ns2tzzzi& zK^Rzh11Ee?^{Pf%`L6_dL1R>vi|5Zl>0WucD5L7sog{g@q24mNM74YzXqw|~!0G^+dff|F)yFcvR00@T! zs(`HPf{QbXS1Ozd+$#X~e{oi0of9~R{rc*XRUz6psFetxSs!cAUozd$CP0AFgt3Lk zbOJq1Dje7CgrWvEF3OM8g_xK-ixX=(c=t^~P$ zu99oudD&B;Nf{{RoV<_ z+bD8|i9lKKpdk$Q5YFh2+jB|0S74;^LkO+$hc)$Bi{S0yOc0!5Zf|AwjI5 zvjDT=;TKPmlH`Ei8EHa}#cC21TgmLVInbFbs0lVr=|H8SRMl#=mE<1ZSz0kDF?d*njegE8>cPNcZ0HGUzi6qfTB5P=7zt|Y+ z#WZU3hImmxQKN*;K_lY1CMKy(LipSpsiDNJ*U-&Kt?{_FwpzuNF7$cBI@hiSy7M%CbC@#c#qGHe+p~R+K z-@gN(-2m{r0rVy!1J{grqMU{wOt7=^mpS1j1MQzM>0n?W=AaYF$`dRTMyGCB^_d~? zhXZbG?q}g_TvDAC!WFQ3v8KyB93y5c?7pn@J7g>7Z%C=Fe0}YnWYX+mS|Mj6Zcy$q zCO@ByWJP^{|D|%G9SPH9{c6P}f#Diea%P~_97qFIbQl5)zeK4%t^QQ79T?zjAbABS zyO4~7CF_HQ6_mtQZl3So$m)O^$X;^B4Of-oLL#z}ID1n9CRwa@|9$rVhUq%{`RV_W zMzB==e5@5+oX?Jv^qX0ccLN~j?B~vAofD=Zc@!5?l53a-`tI+28ygQZu;DBtj>!MwKL13_S!7qm%|_ zl=JKnE1@x;{YFF+o3RXCNL5K})qwsGY$gbCX;^3?WlKPi)k(5qEKmjM+3?2HioBD3 z&hIX;w;f239t8p81rb5`TNa@3F9NBWz**=;>JzI0y#laR5i+WAPX9!+Drr3=v%grW zZ!CaI1B4oYgA`7w#X-V%KxY3DG6C7GFJhMLhFxf+_G|+re$&%cP_BQ}%Rt~HSC39Ga l1BXw~_YX8S77qXZ7ZD$J|9O#1K8dkIx!9}B#a?h73ILb|oE-oF literal 0 HcmV?d00001 -- 2.44.0 From 282129d8ecb990e9d51372736d1973e9f4555d89 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 24 Mar 2022 14:43:24 +0300 Subject: [PATCH 04/16] Generate Metalinks --- makedist.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/makedist.sh b/makedist.sh index aaf7fb9..413b15e 100755 --- a/makedist.sh +++ b/makedist.sh @@ -26,9 +26,14 @@ find . -type f -exec chmod 644 {} + chmod 755 pyderasn-"$release"/pyderasn.py tar cvf pyderasn-"$release".tar --uid=0 --gid=0 --numeric-owner pyderasn-"$release" zstd -19 -v pyderasn-"$release".tar -gpg --detach-sign --sign --local-user 04A933D1BA20327A pyderasn-"$release".tar.zst - tarball=pyderasn-"$release".tar.zst +gpg --detach-sign --sign --local-user pyderasn@cypherpunks.ru $tarball +gpg --enarmor < "$tarball".sig | + sed "/^Comment:/d ; s/ARMORED FILE/SIGNATURE/" > "$tarball".asc +meta4-create -file "$tarball" -mtime "$tarball" -sig "$tarball".asc \ + http://www.pyderasn.cypherpunks.ru/download/"$tarball" \ + http://y.www.pyderasn.cypherpunks.ru/download/"$tarball" > "$tarball".meta4 + size=$(( $(stat -f %z $tarball) / 1024 )) hash=$(gpg --print-md SHA256 < $tarball) release_date=$(date "+%Y-%m-%d") @@ -38,14 +43,15 @@ An entry for documentation: * - \`\`pyderasn\`\` :ref:\`$release \` - $release_date - $size KiB - - \`link \`__ - \`sign \`__ + - \`meta4 \`__ + \`link \`__ + \`sig \`__ - \`\`$hash\`\` pyderasn==$release $pip_hash EOF -mv $tmp/$tarball $tmp/"$tarball".sig $cur/doc/download +mv $tmp/$tarball $tmp/"$tarball".sig $tmp/"$tarball".meta4 $cur/doc/download cat < Date: Thu, 24 Mar 2022 14:53:42 +0300 Subject: [PATCH 05/16] Keep mtime to be friendly with rsync --- doc/build.log.do | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build.log.do b/doc/build.log.do index 76ab32d..be6a370 100644 --- a/doc/build.log.do +++ b/doc/build.log.do @@ -1,7 +1,7 @@ rm -fr _build html=_build/html PYTHONPATH=.. ${PYTHON:=python} -msphinx . $html -[ -d download ] && cp -r download $html || echo No download directory, skipping +[ -d download ] && cp -a download $html || echo No download directory, skipping rm -r $html/.doctrees $html/.buildinfo find $html -type d -exec chmod 755 {} + find $html -type f -exec chmod 644 {} + -- 2.44.0 From 9593abc5c5cb776cee1b33f760c3b37e099f5f20 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 3 Aug 2022 12:13:19 +0300 Subject: [PATCH 06/16] Additional signature with my new main key --- PUBKEY.asc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PUBKEY.asc b/PUBKEY.asc index efe5113..0332845 100644 --- a/PUBKEY.asc +++ b/PUBKEY.asc @@ -16,6 +16,8 @@ y8RmHsszF3sJ5wLuGk1vpSh1jgq61RUquQYJa1iE2B8fxpL6Qr+T8IR2Jan4TFIn vzGeBXtCD2yUIeJgSeF/3VoEq8lxJ+rwHwcsIqHF7QdqJCc7S0wviHUEEBEIAB0W IQTPYOiaWSMeduJjZCKuGoEJ5JhX7wUCWcLAIAAKCRCuGoEJ5JhX7+lbAP9+WNA4 Uk0pNH5BAASabuT+zllnHZ5SqZoKWbs7bzWfogD+NWmjTfSJCr7GSZ4Suy3Vw4nn -hUu3L6dceWUU+hAEOBw= -=Qodb +hUu3L6dceWUU+hAEOByIdQQQFgoAHRYhBBKtMmicZg1CaWf9dcuCBWMhB62KBQJi +6jwUAAoJEMuCBWMhB62KYHMBAOQ6VHkVXpBrQAWCNYUEo9LZAvM2CokI6HVpJps1 +7mZNAP0RI3s/4v8N7a4b+ghbaEtxBIWWlXxqlBgDj/Rbnke0Dg== +=0AVp -----END PGP PUBLIC KEY BLOCK----- -- 2.44.0 From 15902ab3a2d6ce16ae0176c153de7e245ebb51c3 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 3 Aug 2022 12:12:29 +0300 Subject: [PATCH 07/16] Trivial alignment --- doc/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install.rst b/doc/install.rst index 64edda0..13ddee5 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -36,6 +36,6 @@ resources. uid PyDERASN releases $ gpg --auto-key-locate dane --locate-keys pyderasn at cypherpunks dot ru - $ gpg --auto-key-locate wkd --locate-keys pyderasn at cypherpunks dot ru + $ gpg --auto-key-locate wkd --locate-keys pyderasn at cypherpunks dot ru .. literalinclude:: ../PUBKEY.asc -- 2.44.0 From 6d97fd1476e2271a9408f03351613c515defb49f Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 7 Dec 2022 17:48:37 +0300 Subject: [PATCH 08/16] tar's T option is portable --- makedist.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makedist.sh b/makedist.sh index 413b15e..0120968 100755 --- a/makedist.sh +++ b/makedist.sh @@ -10,7 +10,7 @@ mkdir $tmp/pyderasn-"$release" echo pyderasn.py echo setup.py find $(perl -lane 'print $F[1]' MANIFEST.in) -} | tar cfI - - | tar xfC - $tmp/pyderasn-"$release" +} | tar cfT - - | tar xfC - $tmp/pyderasn-"$release" PYTHONPATH="$tmp/pyderasn-$release" redo $tmp/pyderasn-"$release"/doc/build.log rm -r $tmp/pyderasn-"$release"/doc/.redo $tmp/pyderasn-"$release"/doc/build.log -- 2.44.0 From 6a6b1eda46287cb2bff3bc572a6e0a0f6c9f540b Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 27 Dec 2022 17:37:49 +0300 Subject: [PATCH 09/16] Raise copyright years --- doc/conf.py | 2 +- pyderasn.py | 2 +- tests/test_cms.py | 2 +- tests/test_crl.py | 2 +- tests/test_crts.py | 2 +- tests/test_pyderasn.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index b422577..382436b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -5,7 +5,7 @@ templates_path = ["_templates"] source_suffix = ".rst" master_doc = "index" project = "pyderasn" -copyright = "2017-2022, Sergey Matveev" +copyright = "2017-2023, Sergey Matveev" author = "Sergey Matveev" version = version release = version diff --git a/pyderasn.py b/pyderasn.py index 99c771c..458491d 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -4,7 +4,7 @@ # pylint: disable=line-too-long,superfluous-parens,protected-access,too-many-lines # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2022 Sergey Matveev +# Copyright (C) 2017-2023 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_cms.py b/tests/test_cms.py index 9ebb195..c92e529 100644 --- a/tests/test_cms.py +++ b/tests/test_cms.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2022 Sergey Matveev +# Copyright (C) 2017-2023 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_crl.py b/tests/test_crl.py index 2779fd8..f9ec4c1 100644 --- a/tests/test_crl.py +++ b/tests/test_crl.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2022 Sergey Matveev +# Copyright (C) 2017-2023 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_crts.py b/tests/test_crts.py index 8ceeb08..13366db 100644 --- a/tests/test_crts.py +++ b/tests/test_crts.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2022 Sergey Matveev +# Copyright (C) 2017-2023 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index ae7b4ef..dbb5f4d 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2022 Sergey Matveev +# Copyright (C) 2017-2023 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as -- 2.44.0 From f9dd5090e9eb8b7852f137ff26b6963a8fae2f1b Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 14 Mar 2023 19:47:40 +0300 Subject: [PATCH 10/16] No PyPI anymore --- doc/install.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/install.rst b/doc/install.rst index 13ddee5..1164126 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -16,11 +16,6 @@ signature from `official website `__:: * ``urwid`` is an optional dependency used for :ref:`interactive browser `. * ``dateutil`` is an optional dependency used for ``.totzdatetime()`` method. -You could use pip (**no** OpenPGP authentication is performed!) with PyPI:: - - $ echo pyderasn==9.3 --hash=sha256:TO-BE-FILLED > requirements.txt - $ pip install --requirement requirements.txt - You have to verify downloaded tarballs integrity and authenticity to be sure that you retrieved trusted and untampered software. `GNU Privacy Guard `__ is used for that purpose. -- 2.44.0 From 42d4a2ffb0e869fe35a2f3eb7d1abc6c4ae816fa Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 14 Mar 2023 19:48:21 +0300 Subject: [PATCH 11/16] Unnecessary .sh extension --- makedist.sh => makedist | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename makedist.sh => makedist (100%) diff --git a/makedist.sh b/makedist similarity index 100% rename from makedist.sh rename to makedist -- 2.44.0 From 096d73081d80681b049b09f59908dc1daa4ff38e Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 14 Mar 2023 19:54:36 +0300 Subject: [PATCH 12/16] No mention of pip's hash, as signature is anyway here --- makedist | 8 -------- 1 file changed, 8 deletions(-) diff --git a/makedist b/makedist index 0120968..12c10f0 100755 --- a/makedist +++ b/makedist @@ -18,8 +18,6 @@ rm -r $tmp/pyderasn-"$release"/doc/.redo $tmp/pyderasn-"$release"/doc/build.log tar xvfC doc/download/termcolor-1.1.0.tar.gz $tmp --include "*/termcolor.py" mv -v $tmp/termcolor-*/termcolor.py $tmp/pyderasn-"$release" -pip_hash=$(pip hash dist/pyderasn-"$release".tar.gz | sed -n '$p') - cd $tmp find . -type d -exec chmod 755 {} + find . -type f -exec chmod 644 {} + @@ -47,8 +45,6 @@ An entry for documentation: \`link \`__ \`sig \`__ - \`\`$hash\`\` - -pyderasn==$release $pip_hash EOF mv $tmp/$tarball $tmp/"$tarball".sig $tmp/"$tarball".meta4 $cur/doc/download @@ -78,10 +74,6 @@ SHA256 hash: $hash GPG key: 2ED6 C846 3051 02DF 5B4E 0383 04A9 33D1 BA20 327A PyDERASN releases -pip'es requirements file: - - pyderasn==$release $pip_hash - Please send questions regarding the use of PyDERASN, bug reports and patches to mailing list: http://lists.cypherpunks.ru/pyderasn_002ddevel.html EOF -- 2.44.0 From 239cddaf3fe37dafea777597af202092496c2d46 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 13 Apr 2023 18:32:55 +0300 Subject: [PATCH 13/16] Hashes are redundantly present in .meta4 --- makedist | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/makedist b/makedist index 12c10f0..84a0a28 100755 --- a/makedist +++ b/makedist @@ -28,12 +28,11 @@ tarball=pyderasn-"$release".tar.zst gpg --detach-sign --sign --local-user pyderasn@cypherpunks.ru $tarball gpg --enarmor < "$tarball".sig | sed "/^Comment:/d ; s/ARMORED FILE/SIGNATURE/" > "$tarball".asc -meta4-create -file "$tarball" -mtime "$tarball" -sig "$tarball".asc \ +meta4-create -fn "$tarball" -mtime "$tarball" -sig "$tarball".asc \ http://www.pyderasn.cypherpunks.ru/download/"$tarball" \ - http://y.www.pyderasn.cypherpunks.ru/download/"$tarball" > "$tarball".meta4 + http://y.www.pyderasn.cypherpunks.ru/download/"$tarball" < "$tarball" > "$tarball".meta4 size=$(( $(stat -f %z $tarball) / 1024 )) -hash=$(gpg --print-md SHA256 < $tarball) release_date=$(date "+%Y-%m-%d") cat <\`__ - \`link \`__ + \`tar \`__ \`sig \`__ - - \`\`$hash\`\` EOF mv $tmp/$tarball $tmp/"$tarball".sig $tmp/"$tarball".meta4 $cur/doc/download @@ -70,7 +68,6 @@ Source code and its signature for that version can be found here: http://www.pyderasn.cypherpunks.ru/download/pyderasn-${release}.tar.zst ($size KiB) http://www.pyderasn.cypherpunks.ru/download/pyderasn-${release}.tar.zst.sig -SHA256 hash: $hash GPG key: 2ED6 C846 3051 02DF 5B4E 0383 04A9 33D1 BA20 327A PyDERASN releases -- 2.44.0 From f36c78c271f51a5e12442186aaea3383b4653bbe Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 3 Aug 2023 17:51:11 +0300 Subject: [PATCH 14/16] Armored signature --- doc/install.rst | 4 ++-- makedist | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/doc/install.rst b/doc/install.rst index 1164126..057f47d 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -5,8 +5,8 @@ Preferable way is to :ref:`download ` tarball with the signature from `official website `__:: $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.3.tar.zst - $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.3.tar.zst.sig - $ gpg --verify pyderasn-9.3.tar.zst.sig pyderasn-9.3.tar.zst + $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.3.tar.zst.asc + $ gpg --verify pyderasn-9.3.tar.zst.asc pyderasn-9.3.tar.zst $ zstd -d < pyderasn-9.3.tar.zst | tar xf - $ cd pyderasn-9.3 $ python setup.py install diff --git a/makedist b/makedist index 84a0a28..3aafd67 100755 --- a/makedist +++ b/makedist @@ -25,9 +25,7 @@ chmod 755 pyderasn-"$release"/pyderasn.py tar cvf pyderasn-"$release".tar --uid=0 --gid=0 --numeric-owner pyderasn-"$release" zstd -19 -v pyderasn-"$release".tar tarball=pyderasn-"$release".tar.zst -gpg --detach-sign --sign --local-user pyderasn@cypherpunks.ru $tarball -gpg --enarmor < "$tarball".sig | - sed "/^Comment:/d ; s/ARMORED FILE/SIGNATURE/" > "$tarball".asc +gpg --armor --detach-sign --sign --local-user pyderasn@cypherpunks.ru $tarball meta4-create -fn "$tarball" -mtime "$tarball" -sig "$tarball".asc \ http://www.pyderasn.cypherpunks.ru/download/"$tarball" \ http://y.www.pyderasn.cypherpunks.ru/download/"$tarball" < "$tarball" > "$tarball".meta4 @@ -42,10 +40,10 @@ An entry for documentation: - $size KiB - \`meta4 \`__ \`tar \`__ - \`sig \`__ + \`sig \`__ EOF -mv $tmp/$tarball $tmp/"$tarball".sig $tmp/"$tarball".meta4 $cur/doc/download +mv $tmp/$tarball $tmp/"$tarball".asc $tmp/"$tarball".meta4 $cur/doc/download cat < -- 2.44.0 From 1b83f0b65aef3fcc044f1e26630a35dea857c1ad Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 3 Aug 2023 17:52:46 +0300 Subject: [PATCH 15/16] Excess option --- doc/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 382436b..a82a7b5 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -9,7 +9,6 @@ copyright = "2017-2023, Sergey Matveev" author = "Sergey Matveev" version = version release = version -language = None exclude_patterns = ["_build"] pygments_style = "sphinx" todo_include_todos = False -- 2.44.0 From 6ed69cded6cde24263d13dd1bdb14aa86641c921 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sun, 7 Jan 2024 11:56:45 +0300 Subject: [PATCH 16/16] Raise copyright years --- pyderasn.py | 2 +- tests/test_cms.py | 2 +- tests/test_crl.py | 2 +- tests/test_crts.py | 2 +- tests/test_pyderasn.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyderasn.py b/pyderasn.py index 458491d..54242a3 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -4,7 +4,7 @@ # pylint: disable=line-too-long,superfluous-parens,protected-access,too-many-lines # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2023 Sergey Matveev +# Copyright (C) 2017-2024 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_cms.py b/tests/test_cms.py index c92e529..fb45580 100644 --- a/tests/test_cms.py +++ b/tests/test_cms.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2023 Sergey Matveev +# Copyright (C) 2017-2024 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_crl.py b/tests/test_crl.py index f9ec4c1..9174e2f 100644 --- a/tests/test_crl.py +++ b/tests/test_crl.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2023 Sergey Matveev +# Copyright (C) 2017-2024 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_crts.py b/tests/test_crts.py index 13366db..e43b4c2 100644 --- a/tests/test_crts.py +++ b/tests/test_crts.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2023 Sergey Matveev +# Copyright (C) 2017-2024 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index dbb5f4d..e8f8bdf 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -1,6 +1,6 @@ # coding: utf-8 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures -# Copyright (C) 2017-2023 Sergey Matveev +# Copyright (C) 2017-2024 Sergey Matveev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as -- 2.44.0