codext 1.16.1__tar.gz → 1.16.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codext-1.16.1 → codext-1.16.3}/.github/workflows/python-package.yml +1 -1
- {codext-1.16.1 → codext-1.16.3}/PKG-INFO +3 -1
- {codext-1.16.1 → codext-1.16.3}/README.md +2 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/crypto.md +43 -0
- codext-1.16.3/src/codext/VERSION.txt +1 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/_base.py +6 -1
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/base45.py +5 -2
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/__init__.py +2 -0
- codext-1.16.3/src/codext/crypto/phillips.py +130 -0
- codext-1.16.3/src/codext/crypto/vic.py +142 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/PKG-INFO +3 -1
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/SOURCES.txt +2 -0
- {codext-1.16.1 → codext-1.16.3}/tests/test_base.py +22 -1
- codext-1.16.1/src/codext/VERSION.txt +0 -1
- {codext-1.16.1 → codext-1.16.3}/.coveragerc +0 -0
- {codext-1.16.1 → codext-1.16.3}/.github/ISSUE_TEMPLATE/add-encoding.yml +0 -0
- {codext-1.16.1 → codext-1.16.3}/.github/copilot-instructions.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/.github/prompts/add_codec.prompt.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/.github/pull_request_template.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/.gitignore +0 -0
- {codext-1.16.1 → codext-1.16.3}/.readthedocs.yml +0 -0
- {codext-1.16.1 → codext-1.16.3}/LICENSE +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/coverage.svg +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/mkdocs.yml +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/cli.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/css/extra.css +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/demos/using-bases.gif +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/demos/using-codext.gif +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/demos/using-debase.gif +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/base.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/binary.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/common.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/compressions.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/hashing.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/languages.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/others.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/stegano.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/enc/web.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/features.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/guessing.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/howto.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/img/banner.png +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/img/icon.png +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/img/logo.png +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/index.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/pages/manipulations.md +0 -0
- {codext-1.16.1 → codext-1.16.3}/docs/requirements.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/pyproject.toml +0 -0
- {codext-1.16.1 → codext-1.16.3}/pytest.ini +0 -0
- {codext-1.16.1 → codext-1.16.3}/requirements.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/setup.cfg +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/__common__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/__info__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/_base2n.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/base100.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/base122.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/base85.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/base91.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/base/baseN.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/baudot.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/bcd.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/excess3.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/gray.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/manchester.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/binary/rotate.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/checksums/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/checksums/adler.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/checksums/crc.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/checksums/luhn.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/a1z26.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/cases.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/dummy.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/octal.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/common/ordinal.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/compressions/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/compressions/gzipp.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/compressions/lz77.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/compressions/lz78.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/compressions/pkzip.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/affine.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/atbash.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/bacon.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/barbie.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/citrix.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/polybius.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/railfence.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/rot.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/scytale.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/shift.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/vigenere.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/crypto/xor.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/blake.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/crypt.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/md.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/mmh3.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/sha.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/hashing/shake.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/braille.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/galactic.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/ipsum.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/leetspeak.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/morse.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/navajo.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/radio.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/southpark.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/tap.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/languages/tomtom.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/macros.json +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/dna.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/kbshift.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/letters.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/markdown.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/others/uuencode.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/hexagram.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/klopf.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/resistor.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/rick.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/sms.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/stegano/whitespace.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/web/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/web/html.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext/web/url.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/dependency_links.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/entry_points.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/requires.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/src/codext.egg-info/top_level.txt +0 -0
- {codext-1.16.1 → codext-1.16.3}/tests/__init__.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/tests/test_common.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/tests/test_generated.py +0 -0
- {codext-1.16.1 → codext-1.16.3}/tests/test_manual.py +0 -0
|
@@ -65,7 +65,7 @@ jobs:
|
|
|
65
65
|
- uses: actions/checkout@v5
|
|
66
66
|
with:
|
|
67
67
|
fetch-depth: 0
|
|
68
|
-
ref: ${{ github.
|
|
68
|
+
ref: ${{ (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && github.event.pull_request.head.sha || github.sha }}
|
|
69
69
|
- name: Set up Python ${{ env.python_version }}
|
|
70
70
|
uses: actions/setup-python@v6
|
|
71
71
|
with:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codext
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.3
|
|
4
4
|
Summary: Native codecs extension
|
|
5
5
|
Author-email: Alexandre D'Hondt <alexandre.dhondt@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -1034,12 +1034,14 @@ This category also contains `ascii85`, `adobe`, `[x]btoa`, `zeromq` with the `ba
|
|
|
1034
1034
|
- [X] `barbie-N`: aka Barbie Typewriter (*N* belongs to [1, 4])
|
|
1035
1035
|
- [X] `beaufort`: aka Beaufort Cipher (variant of Vigenere Cipher)
|
|
1036
1036
|
- [X] `citrix`: aka Citrix CTX1 password encoding
|
|
1037
|
+
- [X] `phillips`: aka Phillips Cipher (polyalphabetic block cipher with 8 key squares)
|
|
1037
1038
|
- [X] `polybius`: aka Polybius Square Cipher
|
|
1038
1039
|
- [X] `railfence`: aka Rail Fence Cipher
|
|
1039
1040
|
- [X] `rotN`: aka Caesar cipher (*N* belongs to [1,25])
|
|
1040
1041
|
- [X] `scytaleN`: encrypts using the number of letters on the rod (*N* belongs to [1,[)
|
|
1041
1042
|
- [X] `shiftN`: shift ordinals (*N* belongs to [1,255])
|
|
1042
1043
|
- [X] `trithemius`: aka Trithemius Cipher (variant of Vigenere Cipher)
|
|
1044
|
+
- [X] `vic`: aka VIC Cipher
|
|
1043
1045
|
- [X] `vigenere`: aka Vigenere Cipher
|
|
1044
1046
|
- [X] `xorN`: XOR with a single byte (*N* belongs to [1,255])
|
|
1045
1047
|
|
|
@@ -336,12 +336,14 @@ This category also contains `ascii85`, `adobe`, `[x]btoa`, `zeromq` with the `ba
|
|
|
336
336
|
- [X] `barbie-N`: aka Barbie Typewriter (*N* belongs to [1, 4])
|
|
337
337
|
- [X] `beaufort`: aka Beaufort Cipher (variant of Vigenere Cipher)
|
|
338
338
|
- [X] `citrix`: aka Citrix CTX1 password encoding
|
|
339
|
+
- [X] `phillips`: aka Phillips Cipher (polyalphabetic block cipher with 8 key squares)
|
|
339
340
|
- [X] `polybius`: aka Polybius Square Cipher
|
|
340
341
|
- [X] `railfence`: aka Rail Fence Cipher
|
|
341
342
|
- [X] `rotN`: aka Caesar cipher (*N* belongs to [1,25])
|
|
342
343
|
- [X] `scytaleN`: encrypts using the number of letters on the rod (*N* belongs to [1,[)
|
|
343
344
|
- [X] `shiftN`: shift ordinals (*N* belongs to [1,255])
|
|
344
345
|
- [X] `trithemius`: aka Trithemius Cipher (variant of Vigenere Cipher)
|
|
346
|
+
- [X] `vic`: aka VIC Cipher
|
|
345
347
|
- [X] `vigenere`: aka Vigenere Cipher
|
|
346
348
|
- [X] `xorN`: XOR with a single byte (*N* belongs to [1,255])
|
|
347
349
|
|
|
@@ -162,6 +162,25 @@ This implements the Citrix CTX1 password encoding algorithm.
|
|
|
162
162
|
|
|
163
163
|
-----
|
|
164
164
|
|
|
165
|
+
### Phillips Cipher
|
|
166
|
+
|
|
167
|
+
This implements Phillips cipher, a polyalphabetic code using 8 grids generated with one keyword.
|
|
168
|
+
|
|
169
|
+
**Codec** | **Conversions** | **Aliases** | **Comment**
|
|
170
|
+
:---: | :---: | --- | ---
|
|
171
|
+
`phillips` | text <-> phillips ciphertext | `phillips-key`, `phillips_password`, ... |
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
>>> codext.encode("this is a test", "phillips_mysuperkey")
|
|
175
|
+
'ZCNM NM E XKMVZ'
|
|
176
|
+
>>> codext.encode("Another Test String", "phillips-PaSsWoRd")
|
|
177
|
+
'SMEZKBE LBON OLEHQHV'
|
|
178
|
+
>>> codext.decode("SMEZKBE LBON OLEHQHV", "phillips-password")
|
|
179
|
+
'ANOTHER TEST STRINGX'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
-----
|
|
183
|
+
|
|
165
184
|
### Polybius Square Cipher
|
|
166
185
|
|
|
167
186
|
This implements the well-known Polybius Square cipher, using the square with the alphabet in normal order as the default. It can be used dynamically with a custom alphabet.
|
|
@@ -255,6 +274,30 @@ This is a variant of the [Vigenere Cipher](#vigenere-cipher) with key `"ABCDEFGH
|
|
|
255
274
|
|
|
256
275
|
-----
|
|
257
276
|
|
|
277
|
+
### VIC Cipher
|
|
278
|
+
|
|
279
|
+
The VIC cipher combines a straddling checkerboard substitution (converting letters to a stream of digits) and an over-encryption based on a modulo-10 sum with eventually a conversion from digits to text.
|
|
280
|
+
|
|
281
|
+
**Codec** | **Conversions** | **Aliases** | **Comment**
|
|
282
|
+
:---: | :---: | --- | ---
|
|
283
|
+
`vic` | text <-> VIC digit/text ciphertext | `vic-keyword`, `vic-key-12`, `vic-^-26-0248`, `vic-*-73-534T` | optional checkerboard keyword or alphabet marker, blank positions (exactly 2 distinct digits), over-encryption key (digits), "`T`" marker for text conversion
|
|
284
|
+
|
|
285
|
+
Alphabet markers:
|
|
286
|
+
- `*`: uses "`ABC[...]XYZ./`" (uppercase letters + "`./`")
|
|
287
|
+
- `^`: uses "`./ZYX[...]CBA`" ("`./`" + reversed uppercase letters)
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
>>> import codext
|
|
291
|
+
>>> codext.encode("VICTOR", "vic-^-26-0248T")
|
|
292
|
+
'VVXYWYY.XYJ'
|
|
293
|
+
>>> codext.decode("VVXYWYY.XYJ", "vic-^-26-0248T")
|
|
294
|
+
'VICTOR2' # trailing superfluous letter because of text conversion
|
|
295
|
+
>>> codext.encode("LONGTESTSTRING", "vic-^-85-72564")
|
|
296
|
+
'5031237844273727064454072378'
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
-----
|
|
300
|
+
|
|
258
301
|
### Vigenere Cipher
|
|
259
302
|
|
|
260
303
|
This is a dynamic encoding, that is, it holds the key. There is no default key, meaning that `vigenere` as the encoding scheme throws a `LookupError` indicating that the _key must be a non-empty alphabetic string_.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.16.3
|
|
@@ -130,6 +130,10 @@ def base_encode(input, charset, errors="strict", exc=BaseEncodeError):
|
|
|
130
130
|
while i > 0:
|
|
131
131
|
i, c = divmod(i, n)
|
|
132
132
|
r = charset[c] + r
|
|
133
|
+
# preserve leading zero bytes: big-integer bases such as Base58 map each
|
|
134
|
+
# leading null byte of the input to a leading charset[0] character
|
|
135
|
+
if not isinstance(input, int):
|
|
136
|
+
r = charset[0] * (len(input) - len(input.lstrip("\x00"))) + r
|
|
133
137
|
return r
|
|
134
138
|
|
|
135
139
|
|
|
@@ -151,7 +155,8 @@ def base_decode(input, charset, errors="strict", exc=BaseDecodeError):
|
|
|
151
155
|
i = i * n + charset.index(c)
|
|
152
156
|
except ValueError:
|
|
153
157
|
handle_error("base", errors, exc, decode=True)(c, k, dec(i), "base%d" % n)
|
|
154
|
-
|
|
158
|
+
# restore the leading zero bytes encoded as leading charset[0] characters
|
|
159
|
+
return chr(0) * (len(input) - len(input.lstrip(charset[0]))) + dec(i)
|
|
155
160
|
|
|
156
161
|
|
|
157
162
|
# base codec factory functions
|
|
@@ -34,7 +34,10 @@ def base45_encode(mode):
|
|
|
34
34
|
b45 = _get_charset(B45, mode)
|
|
35
35
|
def encode(text, errors="strict"):
|
|
36
36
|
t, s = b(text), ""
|
|
37
|
-
|
|
37
|
+
# iterate over the byte sequence (t), not len(text): when the input
|
|
38
|
+
# holds non-ASCII characters, b(text) is longer than text and using
|
|
39
|
+
# len(text) silently drops the trailing bytes
|
|
40
|
+
for i in range(0, len(t), 2):
|
|
38
41
|
n = 256 * __ord(t[i])
|
|
39
42
|
try:
|
|
40
43
|
n += __ord(t[i+1])
|
|
@@ -54,7 +57,7 @@ def base45_decode(mode):
|
|
|
54
57
|
def decode(text, errors="strict"):
|
|
55
58
|
t, s = b(text), ""
|
|
56
59
|
ehandler = handle_error("base45", errors, decode=True)
|
|
57
|
-
for i in range(0, len(
|
|
60
|
+
for i in range(0, len(t), 3):
|
|
58
61
|
try:
|
|
59
62
|
n = b45[__chr(t[i])]
|
|
60
63
|
except KeyError:
|
|
@@ -4,11 +4,13 @@ from .atbash import *
|
|
|
4
4
|
from .bacon import *
|
|
5
5
|
from .barbie import *
|
|
6
6
|
from .citrix import *
|
|
7
|
+
from .phillips import *
|
|
7
8
|
from .polybius import *
|
|
8
9
|
from .railfence import *
|
|
9
10
|
from .rot import *
|
|
10
11
|
from .scytale import *
|
|
11
12
|
from .shift import *
|
|
13
|
+
from .vic import *
|
|
12
14
|
from .vigenere import *
|
|
13
15
|
from .xor import *
|
|
14
16
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
"""Phillips Cipher Codec - phillips content encoding.
|
|
3
|
+
|
|
4
|
+
The Phillips cipher is a polyalphabetic substitution cipher using 8 key squares. The first square is a 5×5 grid built
|
|
5
|
+
from a keyword (I and J share one cell). Seven additional squares are derived by sequentially swapping adjacent rows
|
|
6
|
+
in a descending bubble pattern. Plaintext is divided into blocks of T letters (default 5); each letter is individually
|
|
7
|
+
enciphered by shifting its grid position right by DH columns and down by DV rows (both default to 1), wrapping
|
|
8
|
+
around with toroidal topology. J is treated as I.
|
|
9
|
+
|
|
10
|
+
Parameters:
|
|
11
|
+
key -- keyword used to seed the initial 5×5 grid (required)
|
|
12
|
+
block_size -- number of letters per grid-cycle block, 1–25 (default 5)
|
|
13
|
+
dh -- horizontal (column) shift for encryption, 1–4 (default 1)
|
|
14
|
+
dv -- vertical (row) shift for encryption, 1–4 (default 1)
|
|
15
|
+
|
|
16
|
+
This codec:
|
|
17
|
+
- en/decodes strings from str to str
|
|
18
|
+
- en/decodes strings from bytes to bytes
|
|
19
|
+
- decodes file content to str (read)
|
|
20
|
+
- encodes file content from str to bytes (write)
|
|
21
|
+
|
|
22
|
+
Reference: https://www.dcode.fr/phillips-cipher
|
|
23
|
+
"""
|
|
24
|
+
from ..__common__ import *
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
__examples__ = {
|
|
28
|
+
'enc(phillips)': None,
|
|
29
|
+
'enc(phillips-key)': {'ATTACK': "HUUHLL", 'TESTME': "UFZUSM", 'ABCDEF': "HCLMFA"},
|
|
30
|
+
'enc(phillips-key-5-1-2)': {'This is a Test String': "KPVBVHTCRHCHCGQBT"},
|
|
31
|
+
'dec(phillips-key-5-1-2)': {'KPVBVHTCRHCHCGQBT': "THISISATESTSTRING"},
|
|
32
|
+
'enc-dec(phillips-key)': ["ATTACK", "TESTME", "ABCDEF"],
|
|
33
|
+
'enc-dec(phillips-secret)': ["HELLOWORLD", "ATTACKATDAWN"],
|
|
34
|
+
'enc-dec(phillips-key-2)': ["ATTACK", "TESTME"],
|
|
35
|
+
'enc-dec(phillips-key-5-2)': ["ATTACK"],
|
|
36
|
+
'enc-dec(phillips-key-5-1-2)': ["ATTACK"],
|
|
37
|
+
}
|
|
38
|
+
__guess__ = ["phillips-key", "phillips-secret", "phillips-password"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_ALPHABET = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def __make_grids(key):
|
|
45
|
+
"""Return all 8 grids built by a descending bubble-swap row permutation."""
|
|
46
|
+
seen, letters = set(), []
|
|
47
|
+
for c in key.upper().replace("J", "I") + _ALPHABET:
|
|
48
|
+
if c in set(_ALPHABET) and c not in seen:
|
|
49
|
+
letters.append(c)
|
|
50
|
+
seen.add(c)
|
|
51
|
+
grid = [letters[i * 5:(i + 1) * 5] for i in range(5)]
|
|
52
|
+
grids = [grid]
|
|
53
|
+
for k in range(7):
|
|
54
|
+
r = k % 4
|
|
55
|
+
grid = [row[:] for row in grid]
|
|
56
|
+
grid[r], grid[r + 1] = grid[r + 1], grid[r]
|
|
57
|
+
grids.append(grid)
|
|
58
|
+
return grids
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _shift_text(text, grids, block_size, dh, dv, errors, decode=False):
|
|
62
|
+
t = ensure_str(text).upper().replace("J", "I")
|
|
63
|
+
pos_maps = [
|
|
64
|
+
{ch: (r, c) for r, row in enumerate(grid) for c, ch in enumerate(row)}
|
|
65
|
+
for grid in grids
|
|
66
|
+
]
|
|
67
|
+
_h = handle_error("phillips", errors, decode=decode)
|
|
68
|
+
r, i = "", 0
|
|
69
|
+
for pos, c in enumerate(t):
|
|
70
|
+
if c == " ":
|
|
71
|
+
continue
|
|
72
|
+
if c not in set(_ALPHABET):
|
|
73
|
+
r += _h(c, pos, r)
|
|
74
|
+
continue
|
|
75
|
+
grid_idx = (i // block_size) % 8
|
|
76
|
+
grid = grids[grid_idx]
|
|
77
|
+
s, col = pos_maps[grid_idx][c]
|
|
78
|
+
r += grid[(s + dv) % 5][(col + dh) % 5]
|
|
79
|
+
i += 1
|
|
80
|
+
return r, len(text)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _make_cipher(key, block_size, dh, dv):
|
|
84
|
+
_key = (key or "").strip()
|
|
85
|
+
try:
|
|
86
|
+
block_size = int(block_size) if block_size else 5
|
|
87
|
+
except (ValueError, TypeError):
|
|
88
|
+
raise LookupError(f"Bad parameter for encoding 'phillips': block_size must be an integer, got {block_size}")
|
|
89
|
+
if not (1 <= block_size <= 25):
|
|
90
|
+
raise LookupError("Bad parameter for encoding 'phillips': block_size must be between 1 and 25, got "
|
|
91
|
+
f"{block_size}")
|
|
92
|
+
try:
|
|
93
|
+
dh = int(dh) if dh else 1
|
|
94
|
+
except (ValueError, TypeError):
|
|
95
|
+
raise LookupError(f"Bad parameter for encoding 'phillips': dh must be an integer, got {dh}")
|
|
96
|
+
if not (1 <= dh <= 4):
|
|
97
|
+
raise LookupError(f"Bad parameter for encoding 'phillips': dh must be between 1 and 4, got {dh}")
|
|
98
|
+
try:
|
|
99
|
+
dv = int(dv) if dv else 1
|
|
100
|
+
except (ValueError, TypeError):
|
|
101
|
+
raise LookupError(f"Bad parameter for encoding 'phillips': dv must be an integer, got {dv}")
|
|
102
|
+
if not (1 <= dv <= 4):
|
|
103
|
+
raise LookupError(f"Bad parameter for encoding 'phillips': dv must be between 1 and 4, got {dv}")
|
|
104
|
+
return _key, block_size, dh, dv, __make_grids(_key) if _key and _key.isalpha() else None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def phillips_encode(key, block_size=None, dh=None, dv=None):
|
|
108
|
+
_key, block_size, dh, dv, grids = _make_cipher(key, block_size, dh, dv)
|
|
109
|
+
def encode(text, errors="strict"):
|
|
110
|
+
if grids is None:
|
|
111
|
+
raise LookupError("Bad parameter for encoding 'phillips': "
|
|
112
|
+
"key must be a non-empty alphabetic string")
|
|
113
|
+
return _shift_text(text, grids, block_size, dh, dv, errors)
|
|
114
|
+
return encode
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def phillips_decode(key, block_size=None, dh=None, dv=None):
|
|
118
|
+
_key, block_size, dh, dv, grids = _make_cipher(key, block_size, dh, dv)
|
|
119
|
+
def decode(text, errors="strict"):
|
|
120
|
+
if grids is None:
|
|
121
|
+
raise LookupError("Bad parameter for decoding 'phillips': "
|
|
122
|
+
"key must be a non-empty alphabetic string")
|
|
123
|
+
return _shift_text(text, grids, block_size, -dh, -dv, errors, True)
|
|
124
|
+
return decode
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
add("phillips", phillips_encode, phillips_decode,
|
|
128
|
+
r"^phillips(?:[-_]cipher)?(?:[-_]([a-zA-Z]+))?(?:[-_]([1-9]|1[0-9]|2[0-5]))?(?:[-_]([1-4]))?(?:[-_]([1-4]))?$",
|
|
129
|
+
printables_rate=1., penalty=.1)
|
|
130
|
+
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
"""Vic Cipher Codec - vic content encoding.
|
|
3
|
+
|
|
4
|
+
This codec:
|
|
5
|
+
- en/decodes strings from str to str
|
|
6
|
+
- en/decodes strings from bytes to bytes
|
|
7
|
+
- decodes file content to str (read)
|
|
8
|
+
- encodes file content from str to bytes (write)
|
|
9
|
+
"""
|
|
10
|
+
from itertools import cycle
|
|
11
|
+
from string import ascii_uppercase as UC
|
|
12
|
+
|
|
13
|
+
from ..__common__ import *
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__examples__ = {
|
|
17
|
+
'dec(vic-test-33)': None,
|
|
18
|
+
'dec(vic-*-12-1234T': {'BBXMBDMBCBBHEMC': "THISISATEST"},
|
|
19
|
+
'dec(vic-^-26-0248T)': {'VVXYWYY.XYJ': "VICTOR2"}, # '2' because of superfluous extra letter from substitution
|
|
20
|
+
'enc(vic-test-12-ABC)': None,
|
|
21
|
+
'enc(vic-*-12-1234T': {'This is a Test': "BBXMBDMBCBBHEMC"},
|
|
22
|
+
'enc(vic-^-26-0248)': {'VICTOR': "88547440546"},
|
|
23
|
+
'enc(vic-^-26-0248T)': {'VICTOR': "VVXYWYY.XYJ"},
|
|
24
|
+
'enc-dec(vic-^-26)': ["TEST", "LONGTESTSTRING", "VICTOR"],
|
|
25
|
+
'enc-dec(vic-^-85-72564)': ["TEST", "LONGTESTSTRING", "VICTOR"],
|
|
26
|
+
'enc-dec(vic-^-85-54321T)': ["TEST", "LONGTESTSTRING", "VICTOR"],
|
|
27
|
+
}
|
|
28
|
+
__guess__ = ["vic"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def __build_alphabet(key, alphabet=UC, reverse=False):
|
|
32
|
+
"""Return the 28-letter alphabet derived from the input key."""
|
|
33
|
+
seen, result = set(), ""
|
|
34
|
+
for c in (key or "").upper():
|
|
35
|
+
if c.isalpha() and c not in seen:
|
|
36
|
+
result += c
|
|
37
|
+
seen.add(c)
|
|
38
|
+
for c in (alphabet[::-1] if reverse else alphabet):
|
|
39
|
+
if c not in seen:
|
|
40
|
+
result += c
|
|
41
|
+
return "./" + result if reverse else result + "./"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def __build_checkerboard(alphabet, blank1=1, blank2=2):
|
|
45
|
+
"""Build encode/decode lookup tables for the straddling checkerboard.
|
|
46
|
+
|
|
47
|
+
Layout with digit1=2 and digit2=6:
|
|
48
|
+
0 1 [2] 3 4 5 [6] 7 8 9
|
|
49
|
+
0: * * * * * * * *
|
|
50
|
+
2: * * * * * * * * * *
|
|
51
|
+
6: * * * * * * * * * *
|
|
52
|
+
"""
|
|
53
|
+
if blank1 == blank2:
|
|
54
|
+
raise LookupError(f"Bad parameter for encoding 'vic': blank1 and blank2 cannot be identical")
|
|
55
|
+
enc, dec, i = {}, {}, 0
|
|
56
|
+
# top row
|
|
57
|
+
for col in range(10):
|
|
58
|
+
if col not in (blank1, blank2):
|
|
59
|
+
enc[alphabet[i]] = str(col)
|
|
60
|
+
i += 1
|
|
61
|
+
# second row ; header digit is 'blank1'
|
|
62
|
+
for col in range(10):
|
|
63
|
+
enc[alphabet[i]] = str(blank1) + str(col)
|
|
64
|
+
i += 1
|
|
65
|
+
# third row ; header digit is 'blank2'
|
|
66
|
+
for col in range(10):
|
|
67
|
+
enc[alphabet[i]] = str(blank2) + str(col)
|
|
68
|
+
i += 1
|
|
69
|
+
return enc, {v: k for k, v in enc.items()}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def __set_params(key, blanks, numeric_key):
|
|
73
|
+
return (UC if key == "*" else UC[::-1] if key == "^" else key).upper(), \
|
|
74
|
+
tuple(map(int, str(blanks) or "12")), \
|
|
75
|
+
str(numeric_key or "").rstrip("T"), \
|
|
76
|
+
key == "^", \
|
|
77
|
+
str(numeric_key or " ")[-1] == "T"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def vic_encode(key=None, blanks=None, numeric_key=None):
|
|
81
|
+
key, blanks, numeric_key, rev, txt = __set_params(key, blanks, numeric_key)
|
|
82
|
+
enc_map, dec_map = __build_checkerboard(__build_alphabet(key, reverse=rev), blanks[0], blanks[1])
|
|
83
|
+
def _encode(text, errors="strict"):
|
|
84
|
+
_h = handle_error("vic", errors)
|
|
85
|
+
digits, nk_i, nk_l = [], 0, len(numeric_key or "")
|
|
86
|
+
for pos, c in enumerate(ensure_str(text).upper().replace(" ", "")):
|
|
87
|
+
# 1) encode with the straddling checkerboard
|
|
88
|
+
c = enc_map[c] if c in enc_map else _h(c, pos, "".join(digits))
|
|
89
|
+
# 2) if numeric_key is defined, over-encrypt digits
|
|
90
|
+
if numeric_key and c.isdigit():
|
|
91
|
+
for ci in c:
|
|
92
|
+
digits.append(str((int(ci) + int(numeric_key[nk_i % nk_l])) % 10))
|
|
93
|
+
nk_i += 1
|
|
94
|
+
else:
|
|
95
|
+
digits.append(c)
|
|
96
|
+
r = "".join(d for d in digits if d)
|
|
97
|
+
# 3) if text mode, convert digits to text
|
|
98
|
+
if txt:
|
|
99
|
+
i, r0, l, r = 0, r, len(r), ""
|
|
100
|
+
while i < len(r0):
|
|
101
|
+
if int(r0[i]) in blanks:
|
|
102
|
+
r += dec_map[r0[i] + ("0" if i == l - 1 else r0[i+1])]
|
|
103
|
+
i += 1
|
|
104
|
+
else:
|
|
105
|
+
r += dec_map[r0[i]]
|
|
106
|
+
i += 1
|
|
107
|
+
return r, len(r)
|
|
108
|
+
return _encode
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def vic_decode(key=None, blanks=None, numeric_key=None):
|
|
112
|
+
key, blanks, numeric_key, rev, txt = __set_params(key, blanks, numeric_key)
|
|
113
|
+
enc_map, dec_map = __build_checkerboard(__build_alphabet(key, reverse=rev), blanks[0], blanks[1])
|
|
114
|
+
def _decode(text, errors="strict"):
|
|
115
|
+
_h = handle_error("vic", errors, decode=True)
|
|
116
|
+
# 1) if text mode, convert text to digits
|
|
117
|
+
text = "".join(enc_map[c] for c in ensure_str(text)) if txt else ensure_str(text)
|
|
118
|
+
# 2) if numeric_key is defined, over-decrypt
|
|
119
|
+
digits, nk_i, nk_l = [], 0, len(numeric_key or "")
|
|
120
|
+
for pos, c in enumerate(text):
|
|
121
|
+
if numeric_key and c.isdigit():
|
|
122
|
+
for ci in c:
|
|
123
|
+
digits.append(str((int(c) - int(numeric_key[nk_i % nk_l])) % 10))
|
|
124
|
+
nk_i += 1
|
|
125
|
+
else:
|
|
126
|
+
digits.append(c if c.isdigit() else _h(c, pos, "".join(digits)))
|
|
127
|
+
# 3) decode with the straddling checkerboard
|
|
128
|
+
i, r, r0 = 0, "", "".join(d for d in digits if d)
|
|
129
|
+
while i < (l := len(r0)):
|
|
130
|
+
if int(r0[i]) in blanks:
|
|
131
|
+
r += r0[i] if i == l - 1 else dec_map[r0[i] + r0[i+1]]
|
|
132
|
+
i += 1
|
|
133
|
+
else:
|
|
134
|
+
r += dec_map[r0[i]] if r0[i] in dec_map else _h(r0[i], i, r)
|
|
135
|
+
i += 1
|
|
136
|
+
return r, len(r)
|
|
137
|
+
return _decode
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
add("vic", vic_encode, vic_decode, r"vic(?:[-_]([\^*./a-zA-Z]+))?(?:[-_]([0-9]{2}))?(?:[-_]([0-9]+T?))?$",
|
|
141
|
+
printables_rate=1., penalty=.1)
|
|
142
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codext
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.3
|
|
4
4
|
Summary: Native codecs extension
|
|
5
5
|
Author-email: Alexandre D'Hondt <alexandre.dhondt@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -1034,12 +1034,14 @@ This category also contains `ascii85`, `adobe`, `[x]btoa`, `zeromq` with the `ba
|
|
|
1034
1034
|
- [X] `barbie-N`: aka Barbie Typewriter (*N* belongs to [1, 4])
|
|
1035
1035
|
- [X] `beaufort`: aka Beaufort Cipher (variant of Vigenere Cipher)
|
|
1036
1036
|
- [X] `citrix`: aka Citrix CTX1 password encoding
|
|
1037
|
+
- [X] `phillips`: aka Phillips Cipher (polyalphabetic block cipher with 8 key squares)
|
|
1037
1038
|
- [X] `polybius`: aka Polybius Square Cipher
|
|
1038
1039
|
- [X] `railfence`: aka Rail Fence Cipher
|
|
1039
1040
|
- [X] `rotN`: aka Caesar cipher (*N* belongs to [1,25])
|
|
1040
1041
|
- [X] `scytaleN`: encrypts using the number of letters on the rod (*N* belongs to [1,[)
|
|
1041
1042
|
- [X] `shiftN`: shift ordinals (*N* belongs to [1,255])
|
|
1042
1043
|
- [X] `trithemius`: aka Trithemius Cipher (variant of Vigenere Cipher)
|
|
1044
|
+
- [X] `vic`: aka VIC Cipher
|
|
1043
1045
|
- [X] `vigenere`: aka Vigenere Cipher
|
|
1044
1046
|
- [X] `xorN`: XOR with a single byte (*N* belongs to [1,255])
|
|
1045
1047
|
|
|
@@ -85,11 +85,13 @@ src/codext/crypto/atbash.py
|
|
|
85
85
|
src/codext/crypto/bacon.py
|
|
86
86
|
src/codext/crypto/barbie.py
|
|
87
87
|
src/codext/crypto/citrix.py
|
|
88
|
+
src/codext/crypto/phillips.py
|
|
88
89
|
src/codext/crypto/polybius.py
|
|
89
90
|
src/codext/crypto/railfence.py
|
|
90
91
|
src/codext/crypto/rot.py
|
|
91
92
|
src/codext/crypto/scytale.py
|
|
92
93
|
src/codext/crypto/shift.py
|
|
94
|
+
src/codext/crypto/vic.py
|
|
93
95
|
src/codext/crypto/vigenere.py
|
|
94
96
|
src/codext/crypto/xor.py
|
|
95
97
|
src/codext/hashing/__init__.py
|
|
@@ -172,7 +172,15 @@ class TestCodecsBase(TestCase):
|
|
|
172
172
|
self.assertEqual(codecs.decode(B58, "base58-fl"), STR)
|
|
173
173
|
self.assertEqual(codecs.encode(STR, "base58-short-url"), B58)
|
|
174
174
|
self.assertEqual(codecs.encode(STR, "base58-url"), B58)
|
|
175
|
-
|
|
175
|
+
# leading null bytes must be preserved as leading charset[0] ('1')
|
|
176
|
+
self.assertEqual(codecs.encode("\x00abc", "base58"), "1ZiCa")
|
|
177
|
+
self.assertEqual(codecs.encode("\x00", "base58"), "1")
|
|
178
|
+
self.assertEqual(codecs.encode("\x00\x00abc", "base58"), "11ZiCa")
|
|
179
|
+
self.assertEqual(codecs.decode("1ZiCa", "base58"), "\x00abc")
|
|
180
|
+
self.assertEqual(codecs.decode("11ZiCa", "base58"), "\x00\x00abc")
|
|
181
|
+
self.assertEqual(codecs.encode(b("\x00abc"), "base58"), b("1ZiCa"))
|
|
182
|
+
self.assertEqual(codecs.decode(b("1ZiCa"), "base58"), b("\x00abc"))
|
|
183
|
+
|
|
176
184
|
def test_codec_base62(self):
|
|
177
185
|
for b62, enc in zip(["CsoB4HQ5gmgMyCenF7E", "M2yLERaFqwqW8MoxPHO"], ["base62", "base62-inv"]):
|
|
178
186
|
self.assertEqual(codecs.encode(STR, enc), b62)
|
|
@@ -211,6 +219,19 @@ class TestCodecsBase(TestCase):
|
|
|
211
219
|
self.assertRaises(ValueError, codecs.decode, b(B100)[1:], "base100")
|
|
212
220
|
self.assertIsNotNone(codecs.decode(b(B100) + b"\n", "base100", "ignore"))
|
|
213
221
|
|
|
222
|
+
def test_codec_base45(self):
|
|
223
|
+
# RFC 9285 test vectors
|
|
224
|
+
for s, b45 in [("AB", "BB8"), ("Hello!!", "%69 VD92EX0"), ("base-45", "UJCLQE7W581")]:
|
|
225
|
+
self.assertEqual(codecs.encode(s, "base45"), b45)
|
|
226
|
+
self.assertEqual(codecs.encode(b(s), "base45"), b(b45))
|
|
227
|
+
self.assertEqual(codecs.decode(b45, "base45"), s)
|
|
228
|
+
self.assertEqual(codecs.decode(b(b45), "base45"), b(s))
|
|
229
|
+
# a trailing non-ASCII byte must not be dropped (byte length, not str length, drives encoding)
|
|
230
|
+
self.assertEqual(codecs.encode(b"\xcf\xb1\x1b", "base45"), b"OBQR0")
|
|
231
|
+
self.assertEqual(codecs.decode(b"OBQR0", "base45"), b"\xcf\xb1\x1b")
|
|
232
|
+
for data in [b"\xff\xfe", b"hello", b"\x00", b"\x80\x81\x82\x83\x84"]:
|
|
233
|
+
self.assertEqual(codecs.decode(codecs.encode(data, "base45"), "base45"), data)
|
|
234
|
+
|
|
214
235
|
def test_codec_base_generic(self):
|
|
215
236
|
for n in range(2, 255):
|
|
216
237
|
bn = "base{}_generic".format(n)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.16.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|