fastled 1.0.15__py2.py3-none-any.whl → 1.1.0__py2.py3-none-any.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.
fastled/web_compile.py CHANGED
@@ -1,291 +1,173 @@
1
- import io
2
- import json
3
- import os
4
- import shutil
5
- import tempfile
6
- import zipfile
7
- from concurrent.futures import Future, ProcessPoolExecutor, as_completed
8
- from dataclasses import dataclass
9
- from pathlib import Path
10
-
11
- import httpx
12
-
13
- from fastled.build_mode import BuildMode
14
- from fastled.compile_server import SERVER_PORT
15
- from fastled.sketch import get_sketch_files
16
- from fastled.util import hash_file
17
-
18
- DEFAULT_HOST = "https://fastled.onrender.com"
19
- ENDPOINT_COMPILED_WASM = "compile/wasm"
20
- _TIMEOUT = 60 * 4 # 2 mins timeout
21
- _AUTH_TOKEN = "oBOT5jbsO4ztgrpNsQwlmFLIKB"
22
- ENABLE_EMBEDDED_DATA = True
23
- _EXECUTOR = ProcessPoolExecutor(max_workers=8)
24
-
25
-
26
- @dataclass
27
- class ConnectionResult:
28
- host: str
29
- success: bool
30
- ipv4: bool
31
-
32
-
33
- @dataclass
34
- class WebCompileResult:
35
- success: bool
36
- stdout: str
37
- hash_value: str | None
38
- zip_bytes: bytes
39
-
40
- def __bool__(self) -> bool:
41
- return self.success
42
-
43
-
44
- def _sanitize_host(host: str) -> str:
45
- if host.startswith("http"):
46
- return host
47
- is_local_host = "localhost" in host or "127.0.0.1" in host or "0.0.0.0" in host
48
- use_https = not is_local_host
49
- if use_https:
50
- return host if host.startswith("https://") else f"https://{host}"
51
- return host if host.startswith("http://") else f"http://{host}"
52
-
53
-
54
- def _test_connection(host: str, use_ipv4: bool) -> ConnectionResult:
55
- # Function static cache
56
- connection_cache = _test_connection.__dict__.setdefault("_CONNECTION_CACHE", {})
57
- key = f"{host}_{use_ipv4}"
58
- cached_result = connection_cache.get(key)
59
- if cached_result is not None:
60
- return cached_result
61
- transport = httpx.HTTPTransport(local_address="0.0.0.0") if use_ipv4 else None
62
- try:
63
- with httpx.Client(
64
- timeout=_TIMEOUT,
65
- transport=transport,
66
- ) as test_client:
67
- test_response = test_client.get(
68
- f"{host}/healthz", timeout=3, follow_redirects=True
69
- )
70
- result = ConnectionResult(host, test_response.status_code == 200, use_ipv4)
71
- except Exception:
72
- result = ConnectionResult(host, False, use_ipv4)
73
- connection_cache[key] = result
74
- return result
75
-
76
-
77
- def _file_info(file_path: Path) -> str:
78
- hash_txt = hash_file(file_path)
79
- file_size = file_path.stat().st_size
80
- json_str = json.dumps({"hash": hash_txt, "size": file_size})
81
- return json_str
82
-
83
-
84
- @dataclass
85
- class ZipResult:
86
- zip_bytes: bytes
87
- zip_embedded_bytes: bytes | None
88
- success: bool
89
- error: str | None
90
-
91
-
92
- def zip_files(directory: Path, build_mode: BuildMode) -> ZipResult | Exception:
93
- print("Zipping files...")
94
- try:
95
- files = get_sketch_files(directory)
96
- if not files:
97
- raise FileNotFoundError(f"No files found in {directory}")
98
- for f in files:
99
- print(f"Adding file: {f}")
100
- # Create in-memory zip file
101
- has_embedded_zip = False
102
- zip_embedded_buffer = io.BytesIO()
103
- zip_buffer = io.BytesIO()
104
- with zipfile.ZipFile(
105
- zip_embedded_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
106
- ) as emebedded_zip_file:
107
- with zipfile.ZipFile(
108
- zip_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
109
- ) as zip_file:
110
- for file_path in files:
111
- relative_path = file_path.relative_to(directory)
112
- achive_path = str(Path("wasm") / relative_path)
113
- if str(relative_path).startswith("data") and ENABLE_EMBEDDED_DATA:
114
- _file_info_str = _file_info(file_path)
115
- zip_file.writestr(
116
- achive_path + ".embedded.json", _file_info_str
117
- )
118
- emebedded_zip_file.write(file_path, relative_path)
119
- has_embedded_zip = True
120
- else:
121
- zip_file.write(file_path, achive_path)
122
- # write build mode into the file as build.txt so that sketches are fingerprinted
123
- # based on the build mode. Otherwise the same sketch with different build modes
124
- # will have the same fingerprint.
125
- zip_file.writestr(
126
- str(Path("wasm") / "build_mode.txt"), build_mode.value
127
- )
128
- result = ZipResult(
129
- zip_bytes=zip_buffer.getvalue(),
130
- zip_embedded_bytes=(
131
- zip_embedded_buffer.getvalue() if has_embedded_zip else None
132
- ),
133
- success=True,
134
- error=None,
135
- )
136
- return result
137
- except Exception as e:
138
- return e
139
-
140
-
141
- def find_good_connection(
142
- urls: list[str], filter_out_bad=True, use_ipv6: bool = True
143
- ) -> ConnectionResult | None:
144
- futures: list[Future] = []
145
- for url in urls:
146
- f = _EXECUTOR.submit(_test_connection, url, use_ipv4=True)
147
- futures.append(f)
148
- if use_ipv6:
149
- f_v6 = _EXECUTOR.submit(_test_connection, url, use_ipv4=False)
150
- futures.append(f_v6)
151
-
152
- try:
153
- # Return first successful result
154
- for future in as_completed(futures):
155
- result: ConnectionResult = future.result()
156
- if result.success or not filter_out_bad:
157
- return result
158
- finally:
159
- # Cancel any remaining futures
160
- for future in futures:
161
- future.cancel()
162
- return None
163
-
164
-
165
- def web_compile(
166
- directory: Path,
167
- host: str | None = None,
168
- auth_token: str | None = None,
169
- build_mode: BuildMode | None = None,
170
- profile: bool = False,
171
- ) -> WebCompileResult:
172
- host = _sanitize_host(host or DEFAULT_HOST)
173
- build_mode = build_mode or BuildMode.QUICK
174
- print("Compiling on", host)
175
- auth_token = auth_token or _AUTH_TOKEN
176
- if not directory.exists():
177
- raise FileNotFoundError(f"Directory not found: {directory}")
178
- zip_result = zip_files(directory, build_mode=build_mode)
179
- if isinstance(zip_result, Exception):
180
- return WebCompileResult(
181
- success=False, stdout=str(zip_result), hash_value=None, zip_bytes=b""
182
- )
183
- zip_bytes = zip_result.zip_bytes
184
- archive_size = len(zip_bytes)
185
- print(f"Web compiling on {host}...")
186
- try:
187
- urls = [host]
188
- domain = host.split("://")[-1]
189
- if ":" not in domain:
190
- urls.append(f"{host}:{SERVER_PORT}")
191
-
192
- connection_result = find_good_connection(urls)
193
- if connection_result is None:
194
- print("Connection failed to all endpoints")
195
- return WebCompileResult(
196
- success=False,
197
- stdout="Connection failed",
198
- hash_value=None,
199
- zip_bytes=b"",
200
- )
201
-
202
- ipv4_stmt = "IPv4" if connection_result.ipv4 else "IPv6"
203
- transport = (
204
- httpx.HTTPTransport(local_address="0.0.0.0")
205
- if connection_result.ipv4
206
- else None
207
- )
208
- with httpx.Client(
209
- transport=transport,
210
- timeout=_TIMEOUT,
211
- ) as client:
212
- headers = {
213
- "accept": "application/json",
214
- "authorization": auth_token,
215
- "build": (
216
- build_mode.value.lower()
217
- if build_mode
218
- else BuildMode.QUICK.value.lower()
219
- ),
220
- "profile": "true" if profile else "false",
221
- }
222
-
223
- url = f"{connection_result.host}/{ENDPOINT_COMPILED_WASM}"
224
- print(f"Compiling on {url} via {ipv4_stmt}. Zip size: {archive_size} bytes")
225
- files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
226
- response = client.post(
227
- url,
228
- follow_redirects=True,
229
- files=files,
230
- headers=headers,
231
- timeout=_TIMEOUT,
232
- )
233
-
234
- if response.status_code != 200:
235
- json_response = response.json()
236
- detail = json_response.get("detail", "Could not compile")
237
- return WebCompileResult(
238
- success=False, stdout=detail, hash_value=None, zip_bytes=b""
239
- )
240
-
241
- print(f"Response status code: {response}")
242
- # Create a temporary directory to extract the zip
243
- with tempfile.TemporaryDirectory() as extract_dir:
244
- extract_path = Path(extract_dir)
245
-
246
- # Write the response content to a temporary zip file
247
- temp_zip = extract_path / "response.zip"
248
- temp_zip.write_bytes(response.content)
249
-
250
- # Extract the zip
251
- shutil.unpack_archive(temp_zip, extract_path, "zip")
252
-
253
- if zip_result.zip_embedded_bytes:
254
- # extract the embedded bytes, which were not sent to the server
255
- temp_zip.write_bytes(zip_result.zip_embedded_bytes)
256
- shutil.unpack_archive(temp_zip, extract_path, "zip")
257
-
258
- # we don't need the temp zip anymore
259
- temp_zip.unlink()
260
-
261
- # Read stdout from out.txt if it exists
262
- stdout_file = extract_path / "out.txt"
263
- hash_file = extract_path / "hash.txt"
264
- stdout = stdout_file.read_text() if stdout_file.exists() else ""
265
- hash_value = hash_file.read_text() if hash_file.exists() else None
266
-
267
- # now rezip the extracted files since we added the embedded json files
268
- out_buffer = io.BytesIO()
269
- with zipfile.ZipFile(
270
- out_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
271
- ) as out_zip:
272
- for root, _, _files in os.walk(extract_path):
273
- for file in _files:
274
- file_path = Path(root) / file
275
- relative_path = file_path.relative_to(extract_path)
276
- out_zip.write(file_path, relative_path)
277
-
278
- return WebCompileResult(
279
- success=True,
280
- stdout=stdout,
281
- hash_value=hash_value,
282
- zip_bytes=out_buffer.getvalue(),
283
- )
284
- except KeyboardInterrupt:
285
- print("Keyboard interrupt")
286
- raise
287
- except httpx.HTTPError as e:
288
- print(f"Error: {e}")
289
- return WebCompileResult(
290
- success=False, stdout=str(e), hash_value=None, zip_bytes=b""
291
- )
1
+ import shutil
2
+ import tempfile
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+
6
+ import httpx
7
+
8
+ from fastled.build_mode import BuildMode
9
+
10
+ DEFAULT_HOST = "https://fastled.onrender.com"
11
+ ENDPOINT_COMPILED_WASM = "compile/wasm"
12
+ _TIMEOUT = 60 * 4 # 2 mins timeout
13
+ _AUTH_TOKEN = "oBOT5jbsO4ztgrpNsQwlmFLIKB"
14
+
15
+
16
+ @dataclass
17
+ class WebCompileResult:
18
+ success: bool
19
+ stdout: str
20
+ hash_value: str | None
21
+ zip_bytes: bytes
22
+
23
+ def __bool__(self) -> bool:
24
+ return self.success
25
+
26
+
27
+ def _sanitize_host(host: str) -> str:
28
+ if host.startswith("http"):
29
+ return host
30
+ is_local_host = "localhost" in host or "127.0.0.1" in host or "0.0.0.0" in host
31
+ use_https = not is_local_host
32
+ if use_https:
33
+ return host if host.startswith("https://") else f"https://{host}"
34
+ return host if host.startswith("http://") else f"http://{host}"
35
+
36
+
37
+ _CONNECTION_ERROR_MAP: dict[str, bool] = {}
38
+
39
+
40
+ def web_compile(
41
+ directory: Path,
42
+ host: str | None = None,
43
+ auth_token: str | None = None,
44
+ build_mode: BuildMode | None = None,
45
+ profile: bool = False,
46
+ ) -> WebCompileResult:
47
+ host = _sanitize_host(host or DEFAULT_HOST)
48
+ auth_token = auth_token or _AUTH_TOKEN
49
+ # zip up the files
50
+ print("Zipping files...")
51
+
52
+ # Create a temporary zip file
53
+ with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as tmp_zip:
54
+ # Create temporary directory for organizing files
55
+ with tempfile.TemporaryDirectory() as temp_dir:
56
+ # Create wasm subdirectory
57
+ wasm_dir = Path(temp_dir) / "wasm"
58
+
59
+ # Copy all files from source to wasm subdirectory, excluding fastled_js
60
+ def ignore_fastled_js(dir: str, files: list[str]) -> list[str]:
61
+ if "fastled_js" in dir:
62
+ return files
63
+ if dir.startswith("."):
64
+ return files
65
+ return []
66
+
67
+ shutil.copytree(directory, wasm_dir, ignore=ignore_fastled_js)
68
+ # Create zip archive from the temp directory
69
+ shutil.make_archive(tmp_zip.name[:-4], "zip", temp_dir)
70
+
71
+ print(f"Web compiling on {host}...")
72
+
73
+ try:
74
+ with open(tmp_zip.name, "rb") as zip_file:
75
+ files = {"file": ("wasm.zip", zip_file, "application/x-zip-compressed")}
76
+
77
+ tested = host in _CONNECTION_ERROR_MAP
78
+ if not tested:
79
+ test_url = f"{host}/healthz"
80
+ print(f"Testing connection to {test_url}")
81
+ timeout = 10
82
+ with httpx.Client(
83
+ transport=httpx.HTTPTransport(local_address="0.0.0.0"),
84
+ timeout=timeout,
85
+ ) as test_client:
86
+ test_response = test_client.get(test_url, timeout=timeout)
87
+ if test_response.status_code != 200:
88
+ print(f"Connection to {test_url} failed")
89
+ _CONNECTION_ERROR_MAP[host] = True
90
+ return WebCompileResult(
91
+ success=False,
92
+ stdout="Connection failed",
93
+ hash_value=None,
94
+ zip_bytes=b"",
95
+ )
96
+ _CONNECTION_ERROR_MAP[host] = False
97
+
98
+ ok = not _CONNECTION_ERROR_MAP[host]
99
+ if not ok:
100
+ return WebCompileResult(
101
+ success=False,
102
+ stdout="Connection failed",
103
+ hash_value=None,
104
+ zip_bytes=b"",
105
+ )
106
+ print(f"Connection to {host} successful")
107
+ with httpx.Client(
108
+ transport=httpx.HTTPTransport(local_address="0.0.0.0"), # forces IPv4
109
+ timeout=_TIMEOUT,
110
+ ) as client:
111
+ url = f"{host}/{ENDPOINT_COMPILED_WASM}"
112
+ headers = {
113
+ "accept": "application/json",
114
+ "authorization": auth_token,
115
+ "build": (
116
+ build_mode.value.lower()
117
+ if build_mode
118
+ else BuildMode.QUICK.value.lower()
119
+ ),
120
+ "profile": "true" if profile else "false",
121
+ }
122
+ print(f"Compiling on {url}")
123
+ response = client.post(
124
+ url,
125
+ files=files,
126
+ headers=headers,
127
+ timeout=_TIMEOUT,
128
+ )
129
+
130
+ if response.status_code != 200:
131
+ json_response = response.json()
132
+ detail = json_response.get("detail", "Could not compile")
133
+ return WebCompileResult(
134
+ success=False, stdout=detail, hash_value=None, zip_bytes=b""
135
+ )
136
+
137
+ print(f"Response status code: {response}")
138
+ # Create a temporary directory to extract the zip
139
+ with tempfile.TemporaryDirectory() as extract_dir:
140
+ extract_path = Path(extract_dir)
141
+
142
+ # Write the response content to a temporary zip file
143
+ temp_zip = extract_path / "response.zip"
144
+ temp_zip.write_bytes(response.content)
145
+
146
+ # Extract the zip
147
+ shutil.unpack_archive(temp_zip, extract_path, "zip")
148
+
149
+ # Read stdout from out.txt if it exists
150
+ stdout_file = extract_path / "out.txt"
151
+ hash_file = extract_path / "hash.txt"
152
+ stdout = stdout_file.read_text() if stdout_file.exists() else ""
153
+ hash_value = hash_file.read_text() if hash_file.exists() else None
154
+
155
+ return WebCompileResult(
156
+ success=True,
157
+ stdout=stdout,
158
+ hash_value=hash_value,
159
+ zip_bytes=response.content,
160
+ )
161
+ except KeyboardInterrupt:
162
+ print("Keyboard interrupt")
163
+ raise
164
+ except httpx.HTTPError as e:
165
+ print(f"Error: {e}")
166
+ return WebCompileResult(
167
+ success=False, stdout=str(e), hash_value=None, zip_bytes=b""
168
+ )
169
+ finally:
170
+ try:
171
+ Path(tmp_zip.name).unlink()
172
+ except PermissionError:
173
+ print("Warning: Could not delete temporary zip file")
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.1
2
+ Name: fastled
3
+ Version: 1.1.0
4
+ Summary: FastLED Wasm Compiler
5
+ Home-page: https://github.com/zackees/fastled-wasm
6
+ Maintainer: Zachary Vorhies
7
+ License: BSD 3-Clause License
8
+ Keywords: template-python-cmd
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: docker
14
+ Requires-Dist: httpx
15
+ Requires-Dist: watchdog
16
+ Requires-Dist: livereload
17
+ Requires-Dist: download
18
+ Requires-Dist: filelock
19
+
20
+ # FastLED wasm compiler
21
+
22
+ Compiles an Arduino/Platformio sketch into a wasm binary that can be run directly in the web browser.
23
+
24
+ [![Linting](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml)
25
+ [![Build and Push Multi Docker Image](https://github.com/zackees/fastled-wasm/actions/workflows/build_multi_docker_image.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/build_multi_docker_image.yml)
26
+ [![MacOS_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_macos.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_macos.yml)
27
+ [![Ubuntu_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_ubuntu.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_ubuntu.yml)
28
+ [![Win_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_win.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_win.yml)
29
+
30
+
31
+
32
+ # About
33
+
34
+ This python app will compile your FastLED style sketches into html/js/wasm output that runs directly in the browser.
35
+
36
+ Compile times are extremely fast - I've seen as low as 5 seconds but 8-15 seconds is typical.
37
+
38
+ This works on Windows/Linux/Mac(arm/x64).
39
+
40
+ Docker is required.
41
+
42
+ https://github.com/user-attachments/assets/64ae0e6c-5f8b-4830-ab87-dcc25bc61218
43
+
44
+ # Demo
45
+
46
+ https://zackees.github.io/fastled-wasm/
47
+
48
+
49
+
50
+ # Install
51
+
52
+ ```bash
53
+ pip install fastled-wasm
54
+ ```
55
+
56
+ **Note that you may need to install x86 docker emulation on Mac-m1 and later, as this is an x86 only image at the prsent.**
57
+
58
+ # Use
59
+
60
+ Change to the directory where the sketch lives and run
61
+
62
+ ```bash
63
+ cd <SKETCH-DIRECTORY>
64
+ fastled-wasm
65
+ ```
66
+
67
+ Or if you don't have docker then use our web compiler
68
+
69
+ ```bash
70
+ cd <SKETCH-DIRECTORY>
71
+ fastled-wasm --web
72
+ ```
73
+
74
+ After compilation a web browser windows will pop up.
75
+
76
+ # Hot reload by default
77
+
78
+ Once launched, the compiler will remain open, listening to changes and recompiling as necessary and hot-reloading the sketch into the current browser.
79
+
80
+ This style of development should be familiar to those doing web development.
81
+
82
+ # Data
83
+
84
+ If you want to embed data, then do so in the `data/` directory at the project root. The files will appear in the `data/` director of any spawned FileSystem or SDCard.
85
+
86
+
87
+ ### About the compilation.
88
+
89
+ Pre-processing is done to your source files. A fake Arduino.h will be inserted into your source files that will
90
+ provide shims for most of the common api points.
91
+
92
+
93
+ # Revisions
94
+
95
+ * 1.1.0 - Use `fastled` as the command for the wasm compiler.
96
+ * 1.0.17 - Pulls updates when necessary. Removed dependency on keyring.
97
+ * 1.0.16 - `fastled-wasm` package name has been changed to `fled`
98
+ * 1.0.15 - `fled` is an alias of `fastled-wasm` and will eventually replace it. `--web-host` was folded into `--web`, which if unspecified will attempt to run a local docker server and fallback to the cloud server if that fails. Specifying `--web` with no arguments will default to the cloud server while an argument (like `localhost`) will cause it to bind to that already running server for compilation.
99
+ * 1.0.14 - For non significant changes (comments, whitespace) in C++/ino/*.h files, compilation is skipped. This significantly reduces load on the server and prevents unnecessary local client browser refreshes.
100
+ * 1.0.13 - Increase speed of local compiles by running the server version of the compiler so it can keep it's cache and not have to pay docker startup costs because now it's a persistant server until exit.
101
+ * 1.0.12 - Added suppport for compile modes. Pass in `--release`, `--quick`, `--debug` for different compile options. We also support `--profile` to profile the build process.
102
+ * 1.0.11 - `--web` compile will automatically be enabled if the local build using docker fails.
103
+ * 1.0.10 - Watching files is now available for `--web`
104
+ * 1.0.9 - Enabled web compile. Access it with `--web` or `--web-host`
105
+ * 1.0.8 - Allow more than one fastled-wasm browser instances to co-exist by searching for unused ports after 8081.
106
+ * 1.0.7 - Docker multi image build implemented, tool now points to new docker image compile.
107
+ * 1.0.6 - Removed `--no-open` and `--watch`, `--watch` is now assumed unless `--just-compile` is used.
108
+ * 1.0.5 - Implemented `--update` to update the compiler image from the docker registry.
109
+ * 1.0.4 - Implemented `--watch` which will watch for changes and then re-launch the compilation step.
110
+ * 1.0.3 - Integrated `live-server` to launch when available.
111
+ * 1.0.2 - Small bug with new installs.
112
+ * 1.0.1 - Re-use is no longer the default, due to problems.
113
+ * 1.0.0 - Initial release.
@@ -0,0 +1,18 @@
1
+ fastled/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ fastled/app.py,sha256=N4a-XXteQMTmODxRmEuicUuXKyfP9OS6rGxT36aVAWs,11380
3
+ fastled/build_mode.py,sha256=joMwsV4K1y_LijT4gEAcjx69RZBoe_KmFmHZdPYbL_4,631
4
+ fastled/check_cpp_syntax.py,sha256=YxRJm7cFPv4bdhL1v_KOkBz8RL86ihayoJYvclr69ms,1024
5
+ fastled/cli.py,sha256=CNR_pQR0sNVPNuv8e_nmm-0PI8sU-eUBUgnWgWkzW9c,237
6
+ fastled/compile_server.py,sha256=_tpHpOgxcizgb9Lis8RVTDsLKLtCaaH3upVH65z0XhA,7994
7
+ fastled/docker_manager.py,sha256=eEc12bmQEER7xf-7ehfYJgQua9cDB1IlLVuuw_9eflI,8934
8
+ fastled/filewatcher.py,sha256=SHKx9Dnt4EJiT-iPYakdPZBRIL1gsJGN9tY8FJW2myU,5079
9
+ fastled/open_browser.py,sha256=-VhpGmydwLCcXmrDD2esMEdJPZYcoX2Mt73eb88Nna0,1392
10
+ fastled/paths.py,sha256=VsPmgu0lNSCFOoEC0BsTYzDygXqy15AHUfN-tTuzDZA,99
11
+ fastled/web_compile.py,sha256=xHy4ndEy5Xr5-WCINFrgvPgfk7XPm5_MhveiOElJKb0,6372
12
+ fastled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
13
+ fastled-1.1.0.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
14
+ fastled-1.1.0.dist-info/METADATA,sha256=C5bl7UjYlsgO2a-Xf6qi9-Dwcg6ctrYWlhZMB86GSSs,5294
15
+ fastled-1.1.0.dist-info/WHEEL,sha256=0VNUDWQJzfRahYI3neAhz2UVbRCtztpN5dPHAGvmGXc,109
16
+ fastled-1.1.0.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
17
+ fastled-1.1.0.dist-info/top_level.txt,sha256=xfG6Z_ol9V5YmBROkZq2QTRwjbS2ouCUxaTJsOwfkOo,14
18
+ fastled-1.1.0.dist-info/RECORD,,