glitchlings 0.5.0__cp311-cp311-win_amd64.whl → 0.5.1__cp311-cp311-win_amd64.whl

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.

Potentially problematic release.


This version of glitchlings might be problematic. Click here for more details.

@@ -0,0 +1,226 @@
1
+ """Homophone substitution glitchling implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import random
7
+ from typing import Any, Iterable, Mapping, Sequence, cast
8
+
9
+ from ._rust_extensions import get_rust_operation
10
+ from ._text_utils import WordToken, collect_word_tokens, split_preserving_whitespace
11
+ from .assets import load_homophone_groups
12
+ from .core import AttackOrder, AttackWave, Glitchling
13
+
14
+ _DEFAULT_RATE = 0.02
15
+ _DEFAULT_WEIGHTING = "flat"
16
+ _VALID_WEIGHTINGS = {_DEFAULT_WEIGHTING}
17
+
18
+ _homophone_groups: tuple[tuple[str, ...], ...] = load_homophone_groups()
19
+
20
+
21
+ def _normalise_group(group: Sequence[str]) -> tuple[str, ...]:
22
+ """Return a tuple of lowercase homophones preserving original order."""
23
+
24
+ # Use dict.fromkeys to preserve the original ordering while de-duplicating.
25
+ return tuple(dict.fromkeys(word.lower() for word in group if word))
26
+
27
+
28
+ def _build_lookup(groups: Iterable[Sequence[str]]) -> Mapping[str, tuple[str, ...]]:
29
+ """Return a mapping from word -> homophone group."""
30
+
31
+ lookup: dict[str, tuple[str, ...]] = {}
32
+ for group in groups:
33
+ normalised = _normalise_group(group)
34
+ if len(normalised) < 2:
35
+ continue
36
+ for word in normalised:
37
+ lookup[word] = normalised
38
+ return lookup
39
+
40
+
41
+ _homophone_lookup = _build_lookup(_homophone_groups)
42
+ _ekkokin_rust = get_rust_operation("ekkokin_homophones")
43
+
44
+
45
+ def _normalise_weighting(weighting: str | None) -> str:
46
+ if weighting is None:
47
+ return _DEFAULT_WEIGHTING
48
+ lowered = weighting.lower()
49
+ if lowered not in _VALID_WEIGHTINGS:
50
+ options = ", ".join(sorted(_VALID_WEIGHTINGS))
51
+ raise ValueError(f"Unsupported weighting '{weighting}'. Expected one of: {options}")
52
+ return lowered
53
+
54
+
55
+ def _apply_casing(template: str, candidate: str) -> str:
56
+ """Return ``candidate`` adjusted to mirror the casing pattern of ``template``."""
57
+
58
+ if not candidate:
59
+ return candidate
60
+ if template.isupper():
61
+ return candidate.upper()
62
+ if template.islower():
63
+ return candidate.lower()
64
+ if template[:1].isupper() and template[1:].islower():
65
+ return candidate.capitalize()
66
+ return candidate
67
+
68
+
69
+ def _choose_alternative(
70
+ *,
71
+ group: Sequence[str],
72
+ source_word: str,
73
+ weighting: str,
74
+ rng: random.Random,
75
+ ) -> str | None:
76
+ """Return a replacement for ``source_word`` drawn from ``group``."""
77
+
78
+ del weighting # Reserved for future weighting strategies.
79
+ lowered = source_word.lower()
80
+ candidates = [candidate for candidate in group if candidate != lowered]
81
+ if not candidates:
82
+ return None
83
+ index = rng.randrange(len(candidates))
84
+ replacement = candidates[index]
85
+ return _apply_casing(source_word, replacement)
86
+
87
+
88
+ def _python_substitute_homophones(
89
+ text: str,
90
+ *,
91
+ rate: float,
92
+ weighting: str,
93
+ rng: random.Random,
94
+ ) -> str:
95
+ """Replace words in ``text`` with curated homophones."""
96
+
97
+ if not text:
98
+ return text
99
+
100
+ if math.isnan(rate):
101
+ return text
102
+
103
+ clamped_rate = max(0.0, min(1.0, rate))
104
+ if clamped_rate <= 0.0:
105
+ return text
106
+
107
+ tokens = split_preserving_whitespace(text)
108
+ word_tokens = collect_word_tokens(tokens)
109
+ if not word_tokens:
110
+ return text
111
+
112
+ mutated = False
113
+ for token in word_tokens:
114
+ replacement = _maybe_replace_token(token, clamped_rate, weighting, rng)
115
+ if replacement is None:
116
+ continue
117
+ tokens[token.index] = replacement
118
+ mutated = True
119
+
120
+ if not mutated:
121
+ return text
122
+ return "".join(tokens)
123
+
124
+
125
+ def _maybe_replace_token(
126
+ token: WordToken,
127
+ rate: float,
128
+ weighting: str,
129
+ rng: random.Random,
130
+ ) -> str | None:
131
+ lookup = _homophone_lookup.get(token.core.lower())
132
+ if lookup is None:
133
+ return None
134
+ if rng.random() >= rate:
135
+ return None
136
+ replacement_core = _choose_alternative(
137
+ group=lookup,
138
+ source_word=token.core,
139
+ weighting=weighting,
140
+ rng=rng,
141
+ )
142
+ if replacement_core is None:
143
+ return None
144
+ return f"{token.prefix}{replacement_core}{token.suffix}"
145
+
146
+
147
+ def substitute_homophones(
148
+ text: str,
149
+ rate: float | None = None,
150
+ seed: int | None = None,
151
+ rng: random.Random | None = None,
152
+ *,
153
+ weighting: str | None = None,
154
+ ) -> str:
155
+ """Replace words in ``text`` with curated homophones."""
156
+
157
+ effective_rate = _DEFAULT_RATE if rate is None else rate
158
+ normalized_weighting = _normalise_weighting(weighting)
159
+
160
+ active_rng = rng if rng is not None else random.Random(seed)
161
+
162
+ clamped_rate = 0.0 if math.isnan(effective_rate) else max(0.0, min(1.0, effective_rate))
163
+ if _ekkokin_rust is not None:
164
+ return cast(
165
+ str,
166
+ _ekkokin_rust(text, clamped_rate, normalized_weighting, active_rng),
167
+ )
168
+ return _python_substitute_homophones(
169
+ text,
170
+ rate=clamped_rate,
171
+ weighting=normalized_weighting,
172
+ rng=active_rng,
173
+ )
174
+
175
+
176
+ class Ekkokin(Glitchling):
177
+ """Glitchling that swaps words for curated homophones."""
178
+
179
+ def __init__(
180
+ self,
181
+ *,
182
+ rate: float | None = None,
183
+ seed: int | None = None,
184
+ weighting: str | None = None,
185
+ ) -> None:
186
+ effective_rate = _DEFAULT_RATE if rate is None else rate
187
+ normalized_weighting = _normalise_weighting(weighting)
188
+ super().__init__(
189
+ name="Ekkokin",
190
+ corruption_function=substitute_homophones,
191
+ scope=AttackWave.WORD,
192
+ order=AttackOrder.EARLY,
193
+ seed=seed,
194
+ pipeline_operation=_build_pipeline_descriptor,
195
+ rate=effective_rate,
196
+ weighting=normalized_weighting,
197
+ )
198
+
199
+ def set_param(self, key: str, value: Any) -> None:
200
+ """Normalise weighting updates before storing them on the glitchling."""
201
+ if key == "weighting":
202
+ value = _normalise_weighting(cast(str | None, value))
203
+ super().set_param(key, value)
204
+
205
+
206
+ def _build_pipeline_descriptor(glitch: Glitchling) -> dict[str, object] | None:
207
+ rate = glitch.kwargs.get("rate")
208
+ if rate is None:
209
+ return None
210
+ weighting = _normalise_weighting(cast(str | None, glitch.kwargs.get("weighting")))
211
+ return {
212
+ "type": "ekkokin",
213
+ "rate": float(rate),
214
+ "weighting": str(weighting),
215
+ }
216
+
217
+
218
+ ekkokin = Ekkokin()
219
+
220
+
221
+ __all__ = [
222
+ "Ekkokin",
223
+ "ekkokin",
224
+ "substitute_homophones",
225
+ "_python_substitute_homophones",
226
+ ]
@@ -0,0 +1,159 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ import re
5
+ from itertools import zip_longest
6
+
7
+ from .core import AttackOrder, AttackWave, Glitchling
8
+
9
+ _CANONICAL_COLOR_MAP: dict[str, str] = {
10
+ "red": "blue",
11
+ "blue": "red",
12
+ "green": "lime",
13
+ "lime": "green",
14
+ "yellow": "purple",
15
+ "purple": "yellow",
16
+ "orange": "cyan",
17
+ "cyan": "orange",
18
+ "magenta": "teal",
19
+ "teal": "magenta",
20
+ "black": "white",
21
+ "white": "black",
22
+ }
23
+
24
+ _VALID_MODES = {"literal", "drift"}
25
+
26
+ _COLOR_PATTERN = re.compile(
27
+ r"\b(?P<color>"
28
+ + "|".join(sorted(_CANONICAL_COLOR_MAP, key=len, reverse=True))
29
+ + r")(?P<suffix>[a-zA-Z]*)\b",
30
+ re.IGNORECASE,
31
+ )
32
+
33
+ _COLOR_ADJACENCY: dict[str, tuple[str, ...]] = {
34
+ "red": ("orange", "magenta", "purple"),
35
+ "blue": ("cyan", "teal", "purple"),
36
+ "green": ("teal", "cyan", "yellow"),
37
+ "lime": ("yellow", "white", "cyan"),
38
+ "yellow": ("orange", "lime", "white"),
39
+ "purple": ("magenta", "red", "blue"),
40
+ "orange": ("red", "yellow", "magenta"),
41
+ "cyan": ("blue", "green", "teal"),
42
+ "magenta": ("purple", "red", "blue"),
43
+ "teal": ("cyan", "green", "blue"),
44
+ "black": ("purple", "blue", "teal"),
45
+ "white": ("yellow", "lime", "cyan"),
46
+ }
47
+
48
+
49
+ def _apply_case(template: str, replacement: str) -> str:
50
+ if not template:
51
+ return replacement
52
+ if template.isupper():
53
+ return replacement.upper()
54
+ if template.islower():
55
+ return replacement.lower()
56
+ if template[0].isupper() and template[1:].islower():
57
+ return replacement.capitalize()
58
+
59
+ characters: list[str] = []
60
+ for repl_char, template_char in zip_longest(replacement, template, fillvalue=""):
61
+ if template_char.isupper():
62
+ characters.append(repl_char.upper())
63
+ elif template_char.islower():
64
+ characters.append(repl_char.lower())
65
+ else:
66
+ characters.append(repl_char)
67
+ return "".join(characters)
68
+
69
+
70
+ def _harmonize_suffix(original: str, replacement: str, suffix: str) -> str:
71
+ if not suffix:
72
+ return suffix
73
+
74
+ if (
75
+ original
76
+ and suffix
77
+ and original[-1].lower() == suffix[0].lower()
78
+ and replacement[-1].lower() != suffix[0].lower()
79
+ ):
80
+ return suffix[1:]
81
+ return suffix
82
+
83
+
84
+ def _normalize_mode(mode: str | None) -> str:
85
+ normalized = "literal" if mode is None else mode.lower()
86
+ if normalized not in _VALID_MODES:
87
+ valid = ", ".join(sorted(_VALID_MODES))
88
+ raise ValueError(f"Unsupported Spectroll mode '{mode}'. Expected one of: {valid}")
89
+ return normalized
90
+
91
+
92
+ def swap_colors(
93
+ text: str,
94
+ *,
95
+ seed: int | None = None,
96
+ mode: str = "literal",
97
+ rng: random.Random | None = None,
98
+ ) -> str:
99
+ """Swap canonical colour words for their partners.
100
+
101
+ Examples:
102
+ >>> swap_colors("red green blue")
103
+ 'blue lime red'
104
+ >>> swap_colors("red green blue", mode="drift", seed=42)
105
+ 'purple teal cyan'
106
+ """
107
+
108
+ normalized_mode = _normalize_mode(mode)
109
+ active_rng = rng if rng is not None else random.Random(seed)
110
+
111
+ def replace(match: re.Match[str]) -> str:
112
+ base = match.group("color")
113
+ suffix = match.group("suffix") or ""
114
+ canonical = base.lower()
115
+
116
+ replacement_base: str | None
117
+ if normalized_mode == "literal":
118
+ replacement_base = _CANONICAL_COLOR_MAP.get(canonical)
119
+ else:
120
+ palette = _COLOR_ADJACENCY.get(canonical)
121
+ if palette:
122
+ replacement_base = active_rng.choice(palette)
123
+ else:
124
+ replacement_base = _CANONICAL_COLOR_MAP.get(canonical)
125
+
126
+ if not replacement_base:
127
+ return match.group(0)
128
+
129
+ suffix_fragment = _harmonize_suffix(base, replacement_base, suffix)
130
+ adjusted = _apply_case(base, replacement_base)
131
+ return f"{adjusted}{suffix_fragment}"
132
+
133
+ return _COLOR_PATTERN.sub(replace, text)
134
+
135
+
136
+ class Spectroll(Glitchling):
137
+ """Glitchling that remaps colour terms to alternate hues."""
138
+
139
+ def __init__(
140
+ self,
141
+ *,
142
+ mode: str = "literal",
143
+ seed: int | None = None,
144
+ ) -> None:
145
+ normalized_mode = _normalize_mode(mode)
146
+ super().__init__(
147
+ name="Spectroll",
148
+ corruption_function=swap_colors,
149
+ scope=AttackWave.WORD,
150
+ order=AttackOrder.NORMAL,
151
+ seed=seed,
152
+ mode=normalized_mode,
153
+ )
154
+
155
+
156
+ spectroll = Spectroll()
157
+
158
+
159
+ __all__ = ["Spectroll", "spectroll", "swap_colors"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glitchlings
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Monsters for your language games.
5
5
  Author: osoleve
6
6
  License: Apache License
@@ -393,11 +393,13 @@ glitchlings --list
393
393
  Apostrofae — scope: Character, order: normal
394
394
  Hokey — scope: Character, order: first
395
395
  Mim1c — scope: Character, order: last
396
+ Ekkokin — scope: Word, order: early
396
397
  Jargoyle — scope: Word, order: normal
397
398
  Adjax — scope: Word, order: normal
398
399
  Reduple — scope: Word, order: normal
399
400
  Rushmore — scope: Word, order: normal
400
401
  Redactyl — scope: Word, order: normal
402
+ Spectroll — scope: Word, order: normal
401
403
  Scannequin — scope: Character, order: late
402
404
  Zeedub — scope: Character, order: last
403
405
  ```
@@ -552,6 +554,18 @@ _Watch your step around here._
552
554
  > - `characters (Sequence[str])`: Optional override for the pool of zero-width strings to inject (default: curated invisibles such as U+200B, U+200C, U+200D, U+FEFF, U+2060).
553
555
  > - `seed (int)`: The random seed for reproducibility (default: 151).
554
556
 
557
+ ### Ekkokin
558
+
559
+ _Did you hear what I heard?_
560
+
561
+ > _**Echo Chamber.**_ Ekkokin swaps words with curated homophones so the text still sounds right while the spelling drifts. Groups are normalised to prevent duplicates and casing is preserved when substitutions fire.
562
+ >
563
+ > Args
564
+ >
565
+ > - `rate (float)`: Maximum proportion of eligible words to replace with homophones (default: 0.02, 2%).
566
+ > - `weighting (str)`: Sampling strategy applied within each homophone set (default: "flat").
567
+ > - `seed (int)`: The random seed for reproducibility (default: 151).
568
+
555
569
  ### Jargoyle
556
570
 
557
571
  _Uh oh. The worst person you know just bought a thesaurus._
@@ -619,7 +633,6 @@ _Oops, that was my black highlighter._
619
633
 
620
634
  ### _Containment procedures pending_
621
635
 
622
- - `ekkokin` substitutes words with homophones (phonetic equivalents).
623
636
  - `nylingual` backtranslates portions of text.
624
637
  - `glothopper` introduces code-switching effects, blending languages or dialects.
625
638
  - `palimpsest` rewrites, but leaves accidental traces of the past.
@@ -1,18 +1,23 @@
1
- glitchlings/__init__.py,sha256=pNL6Vx6ggpRq-vW0CXJjnWOe_LktP6Zz9xNhqDHj3Dw,1301
1
+ glitchlings/__init__.py,sha256=NFlHQWDuMWspkx0dEknAdmQeEMAXzqRfkh5zlgm2ys0,2051
2
2
  glitchlings/__main__.py,sha256=nB7btO_T4wBFOcyawfWpjEindVrUfTqqV5hdeeS1HT8,128
3
- glitchlings/_zoo_rust.cp311-win_amd64.pyd,sha256=N6hPU0Su6nzs6GwBNlelWUNBZovPNsLMZabuw8_Nb2Y,2348544
4
- glitchlings/compat.py,sha256=j4lkWNtyox5sen5j7u0SHfnk8QUn-yicaqvuLlZp1-s,9174
3
+ glitchlings/_zoo_rust.cp311-win_amd64.pyd,sha256=-XknX0NI_NOI6dV2FEP9yVMszVI76FuS5hcYSb6w7tg,2413568
4
+ glitchlings/compat.py,sha256=QAu4PYbBY6WNhk9o68cFIXys67d-_isedtJMIZXGSVE,12437
5
5
  glitchlings/config.py,sha256=00BAHPbfOFnGHvC7FCcz1YpJjdsfpn1ET5SJJdsVQog,12677
6
6
  glitchlings/config.toml,sha256=OywXmEpuOPtyJRbcRt4cwQkHiZ__5axEHoCaX9ye-uA,102
7
7
  glitchlings/main.py,sha256=eCUEFsu8-NLDz1xyKNDIucVm975HNQZJYm6YCv8RIyg,10987
8
+ glitchlings/spectroll.py,sha256=oxV21u_0xZQWl_rURpG40Ojj0ctjY0OvCYJNbxHSPnU,155
9
+ glitchlings/assets/apostrofae_pairs.json,sha256=lPLFLndzn_f7_5wZizxsLMnwBY4O63zsCvDjyJ56MLA,553
10
+ glitchlings/assets/ekkokin_homophones.json,sha256=7_7tsBJdwn8BwUq9-aBTvFyUcg45Hu3Vm8xQQu4Ac1M,19054
11
+ glitchlings/assets/hokey_assets.json,sha256=1GaSEzXwtT1nvf0B9mFyLzHOcqzKbPreibsC6iBWAHA,3083
12
+ glitchlings/assets/ocr_confusions.tsv,sha256=S-IJEYCIXYKT1Uu7Id8Lnvg5pw528yNigTtWUdnMv9k,213
8
13
  glitchlings/dev/__init__.py,sha256=Pr2tXDwfa6SHW1wPseLHRXPINi7lEs6QNClreU0rAiw,147
9
- glitchlings/dev/sync_assets.py,sha256=QgUNrNpNloxqVGTCX0kVYwQMkJ58zGiZd37svteeS5M,4830
14
+ glitchlings/dev/sync_assets.py,sha256=tudnk8nW4Nu6RcDnfUhEAMbQJv3AwGjfsvgvWNjKzt4,3805
10
15
  glitchlings/dlc/__init__.py,sha256=iFDTwkaWl2C0_QUYykIXfmOUzy__oURX_BiJhexf-8o,312
11
16
  glitchlings/dlc/_shared.py,sha256=q1xMclEsbR0KIEn9chwZXRubMnIvU-uIc_0PxCFpmqE,4560
12
17
  glitchlings/dlc/huggingface.py,sha256=6wD4Vu2jp1d8GYSUiAvOAXqCO9w4HBxCOSfbJM8Ylzw,2657
13
18
  glitchlings/dlc/prime.py,sha256=8-Ix8bjKyDKDMyXHDESE-gFDwC6blAP3mPXm1YiP3_U,8861
14
19
  glitchlings/dlc/pytorch.py,sha256=xR-uoeo8f6g-aM2CmQ1cfHKfqn12uwRA9eCebEO5wXA,6399
15
- glitchlings/dlc/pytorch_lightning.py,sha256=EQq7SMlvNoyBLYVW2Vi19H5k8VUqoAiNx8IqkDWqy5I,8214
20
+ glitchlings/dlc/pytorch_lightning.py,sha256=rNC0keSuyMhx0OZnaZE1lDm2EhCVuFgglAd95W8MSPI,8699
16
21
  glitchlings/lexicon/__init__.py,sha256=oSLI1bOMfTpqiI7bMp9beeQ7Vp81G5coXxwdmCIQfV0,6199
17
22
  glitchlings/lexicon/_cache.py,sha256=MRvomTi2Rx0l9FzHm91VrfRkrHqACjS5LG4a4OOCvLY,4180
18
23
  glitchlings/lexicon/metrics.py,sha256=TZAafSKgHpUS4h6vCuhTKGsvu_fru9kMqsXqLID6BTM,4734
@@ -24,7 +29,7 @@ glitchlings/util/adapters.py,sha256=mFhPlE8JaFuO_C-3_aqhgwkqa6isV8Y2ifqVh3Iv9JM,
24
29
  glitchlings/util/hokey_generator.py,sha256=hNWVbscVeKvcqwFtJ1oaWYf2Z0qHSxy0-iMLjht6zuM,4627
25
30
  glitchlings/util/stretch_locator.py,sha256=tM4XsQ_asNXQq2Yee8STybFMCC2HbSKCu9I49G0yJ3c,4334
26
31
  glitchlings/util/stretchability.py,sha256=WWGMN9MTbHhgQIBB_p_cz-JKb51rCHZqyDRjPGkUOjY,13037
27
- glitchlings/zoo/__init__.py,sha256=Ab69SD_RUXfiWUEzqU3wteGWobpm2kkbmwndYLEbv_0,5511
32
+ glitchlings/zoo/__init__.py,sha256=VpZ8LVF0MwdWNDzf9E3KKJ20G8gvevd24Riqq-3BuCw,5759
28
33
  glitchlings/zoo/_ocr_confusions.py,sha256=Kyo3W6w-FGs4C7jXp4bLFHFCaa0RUJWvUrWKqfBOdBk,1171
29
34
  glitchlings/zoo/_rust_extensions.py,sha256=SdU06m-qjf-rRHnqM5OMophx1IacoI4KbyRu2HXrTUc,4354
30
35
  glitchlings/zoo/_sampling.py,sha256=AAPLObjqKrmX882TX8hdvPHReBOcv0Z4pUuW6AxuGgU,1640
@@ -32,6 +37,7 @@ glitchlings/zoo/_text_utils.py,sha256=DRjPuC-nFoxFeA7KIbpuIB5k8DXbvvvcHNJniL_8Ko
32
37
  glitchlings/zoo/adjax.py,sha256=Oz3WGSsa4qpH7HLgBQC0r4JktJYGl3A0vkVknqeSG5I,3249
33
38
  glitchlings/zoo/apostrofae.py,sha256=C9x9_jj9CidYEWL9OEoNJU_Jzr3Vk4UQ8tITThVbwvY,3798
34
39
  glitchlings/zoo/core.py,sha256=tkJFqGwpVa7qQxkUr9lsHOB8zS3lDCo987R6Nvz375U,21257
40
+ glitchlings/zoo/ekkokin.py,sha256=A85MMhIDbooLRYMPL1yT3x1LEzbc-Qo7UwGbVffDxdU,6668
35
41
  glitchlings/zoo/hokey.py,sha256=h-yjCLqYAZFksIYw4fMniuTWUywFw9GU9yUFs_uECHo,5471
36
42
  glitchlings/zoo/jargoyle.py,sha256=2FwL4A_DpI2Lz6pnZo5iSJZzgd8wDNM9bMeOsMVFSmw,11581
37
43
  glitchlings/zoo/mim1c.py,sha256=86lCawTFWRWsO_vH6GMRJfM09TMTUy5MNhO9gsBEkk0,3105
@@ -39,15 +45,13 @@ glitchlings/zoo/redactyl.py,sha256=2BYQfcKwp1WFPwXomQCmh-z0UPN9sNx6Px84WilFs3k,5
39
45
  glitchlings/zoo/reduple.py,sha256=YukTZvLMBoarx96T4LHLGHr_KJVmFkAb0OBsO13ws8A,3911
40
46
  glitchlings/zoo/rushmore.py,sha256=CiVkLlskOmfKtzFanmYe6wxKJkCSMbLeKTWDrwZZaXw,3895
41
47
  glitchlings/zoo/scannequin.py,sha256=s2wno1_7aGebXvG3o9WvDQ5RRwp5Upl2dejbDUGIXkY,4560
48
+ glitchlings/zoo/spectroll.py,sha256=2V9HgWs76ttLww45PpQgLOSKfy1xBHFfoPPrigLmvUY,4635
42
49
  glitchlings/zoo/typogre.py,sha256=B1-kMfOygKtiKXDBQOHJxvheielBWGbbdWk-cgoONgs,6402
43
50
  glitchlings/zoo/zeedub.py,sha256=4x9bNQEq4VSsfol77mYx8jyBRyTugjRQPyk-ANy6gpY,4792
44
- glitchlings/zoo/assets/__init__.py,sha256=6dOYQnMw-Hk9Tb3lChgZ4aoRr9qacZtbXR8ROnDfBq8,1691
45
- glitchlings/zoo/assets/apostrofae_pairs.json,sha256=lPLFLndzn_f7_5wZizxsLMnwBY4O63zsCvDjyJ56MLA,553
46
- glitchlings/zoo/assets/hokey_assets.json,sha256=1GaSEzXwtT1nvf0B9mFyLzHOcqzKbPreibsC6iBWAHA,3083
47
- glitchlings/zoo/assets/ocr_confusions.tsv,sha256=S-IJEYCIXYKT1Uu7Id8Lnvg5pw528yNigTtWUdnMv9k,213
48
- glitchlings-0.5.0.dist-info/licenses/LICENSE,sha256=EFEP1evBfHaxsMTBjxm0sZVRp2wct8QLvHE1saII5FI,11538
49
- glitchlings-0.5.0.dist-info/METADATA,sha256=Nu4n4Oy-LoMko5-2ncvshT_OKMWxr-k9YOm5uMLIHBk,34013
50
- glitchlings-0.5.0.dist-info/WHEEL,sha256=JLOMsP7F5qtkAkINx5UnzbFguf8CqZeraV8o04b0I8I,101
51
- glitchlings-0.5.0.dist-info/entry_points.txt,sha256=kGOwuAsjFDLtztLisaXtOouq9wFVMOJg5FzaAkg-Hto,54
52
- glitchlings-0.5.0.dist-info/top_level.txt,sha256=VHFNBrLjtDwPCYXbGKi6o17Eueedi81eNbR3hBOoST0,12
53
- glitchlings-0.5.0.dist-info/RECORD,,
51
+ glitchlings/zoo/assets/__init__.py,sha256=UP5moOFAd0Nm539c9hwGsXvXY4tZ-e1c0CSAjsH1IRk,2820
52
+ glitchlings-0.5.1.dist-info/licenses/LICENSE,sha256=EFEP1evBfHaxsMTBjxm0sZVRp2wct8QLvHE1saII5FI,11538
53
+ glitchlings-0.5.1.dist-info/METADATA,sha256=KJff7BHDX7a2v-g2DBRUQGGeM6c65bIxN8o97NWwA_U,34580
54
+ glitchlings-0.5.1.dist-info/WHEEL,sha256=JLOMsP7F5qtkAkINx5UnzbFguf8CqZeraV8o04b0I8I,101
55
+ glitchlings-0.5.1.dist-info/entry_points.txt,sha256=kGOwuAsjFDLtztLisaXtOouq9wFVMOJg5FzaAkg-Hto,54
56
+ glitchlings-0.5.1.dist-info/top_level.txt,sha256=VHFNBrLjtDwPCYXbGKi6o17Eueedi81eNbR3hBOoST0,12
57
+ glitchlings-0.5.1.dist-info/RECORD,,
File without changes
File without changes