fastled 1.0.8__py2.py3-none-any.whl → 1.0.10__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,227 +1,277 @@
1
- import io
2
- import shutil
3
- import tempfile
4
- import zipfile
5
- from concurrent.futures import ThreadPoolExecutor, as_completed
6
- from dataclasses import dataclass
7
- from pathlib import Path
8
-
9
- import httpx
10
-
11
- from fastled.build_mode import BuildMode
12
- from fastled.compile_server import SERVER_PORT
13
- from fastled.sketch import get_sketch_files
14
-
15
- DEFAULT_HOST = "https://fastled.onrender.com"
16
- ENDPOINT_COMPILED_WASM = "compile/wasm"
17
- _TIMEOUT = 60 * 4 # 2 mins timeout
18
- _AUTH_TOKEN = "oBOT5jbsO4ztgrpNsQwlmFLIKB"
19
-
20
- _THREAD_POOL = ThreadPoolExecutor(max_workers=8)
21
-
22
-
23
- @dataclass
24
- class TestConnectionResult:
25
- host: str
26
- success: bool
27
- ipv4: bool
28
-
29
-
30
- @dataclass
31
- class WebCompileResult:
32
- success: bool
33
- stdout: str
34
- hash_value: str | None
35
- zip_bytes: bytes
36
-
37
- def __bool__(self) -> bool:
38
- return self.success
39
-
40
-
41
- def _sanitize_host(host: str) -> str:
42
- if host.startswith("http"):
43
- return host
44
- is_local_host = "localhost" in host or "127.0.0.1" in host or "0.0.0.0" in host
45
- use_https = not is_local_host
46
- if use_https:
47
- return host if host.startswith("https://") else f"https://{host}"
48
- return host if host.startswith("http://") else f"http://{host}"
49
-
50
-
51
- _CONNECTION_ERROR_MAP: dict[str, TestConnectionResult] = {}
52
-
53
-
54
- def _test_connection(host: str, use_ipv4: bool) -> TestConnectionResult:
55
- key = f"{host}-{use_ipv4}"
56
- maybe_result: TestConnectionResult | None = _CONNECTION_ERROR_MAP.get(key)
57
- if maybe_result is not None:
58
- return maybe_result
59
- transport = httpx.HTTPTransport(local_address="0.0.0.0") if use_ipv4 else None
60
- try:
61
- with httpx.Client(
62
- timeout=_TIMEOUT,
63
- transport=transport,
64
- ) as test_client:
65
- test_response = test_client.get(
66
- f"{host}/healthz", timeout=3, follow_redirects=True
67
- )
68
- result = TestConnectionResult(
69
- host, test_response.status_code == 200, use_ipv4
70
- )
71
- _CONNECTION_ERROR_MAP[key] = result
72
- except Exception:
73
- result = TestConnectionResult(host, False, use_ipv4)
74
- _CONNECTION_ERROR_MAP[key] = result
75
- return result
76
-
77
-
78
- def zip_files(directory: Path) -> bytes | Exception:
79
- print("Zipping files...")
80
- try:
81
- files = get_sketch_files(directory)
82
- if not files:
83
- raise FileNotFoundError(f"No files found in {directory}")
84
- for f in files:
85
- print(f"Adding file: {f}")
86
- # Create in-memory zip file
87
- zip_buffer = io.BytesIO()
88
- with zipfile.ZipFile(
89
- zip_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
90
- ) as zip_file:
91
- for file_path in files:
92
- relative_path = file_path.relative_to(directory)
93
- zip_file.write(file_path, str(Path("wasm") / relative_path))
94
- return zip_buffer.getvalue()
95
- except Exception as e:
96
- return e
97
-
98
-
99
- def web_compile(
100
- directory: Path,
101
- host: str | None = None,
102
- auth_token: str | None = None,
103
- build_mode: BuildMode | None = None,
104
- profile: bool = False,
105
- ) -> WebCompileResult:
106
- host = _sanitize_host(host or DEFAULT_HOST)
107
- print("Compiling on", host)
108
- auth_token = auth_token or _AUTH_TOKEN
109
-
110
- if not directory.exists():
111
- raise FileNotFoundError(f"Directory not found: {directory}")
112
-
113
- zip_bytes = zip_files(directory)
114
- if isinstance(zip_bytes, Exception):
115
- return WebCompileResult(
116
- success=False, stdout=str(zip_bytes), hash_value=None, zip_bytes=b""
117
- )
118
- archive_size = len(zip_bytes)
119
- print(f"Web compiling on {host}...")
120
- try:
121
-
122
- files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
123
- urls = [host]
124
- domain = host.split("://")[-1]
125
- if ":" not in domain:
126
- urls.append(f"{host}:{SERVER_PORT}")
127
- test_connection_result: TestConnectionResult | None = None
128
-
129
- futures: list = []
130
- ip_versions = [True, False] if "localhost" not in host else [True]
131
- for ipv4 in ip_versions:
132
- for url in urls:
133
- f = _THREAD_POOL.submit(_test_connection, url, ipv4)
134
- futures.append(f)
135
-
136
- succeeded = False
137
- for future in as_completed(futures):
138
- result: TestConnectionResult = future.result()
139
-
140
- if result.success:
141
- print(f"Connection successful to {result.host}")
142
- succeeded = True
143
- # host = test_url
144
- test_connection_result = result
145
- break
146
- else:
147
- print(f"Ignoring {result.host} due to connection failure")
148
-
149
- if not succeeded:
150
- print("Connection failed to all endpoints")
151
- return WebCompileResult(
152
- success=False,
153
- stdout="Connection failed",
154
- hash_value=None,
155
- zip_bytes=b"",
156
- )
157
- assert test_connection_result is not None
158
- ipv4_stmt = "IPv4" if test_connection_result.ipv4 else "IPv6"
159
- transport = (
160
- httpx.HTTPTransport(local_address="0.0.0.0")
161
- if test_connection_result.ipv4
162
- else None
163
- )
164
- with httpx.Client(
165
- transport=transport,
166
- timeout=_TIMEOUT,
167
- ) as client:
168
- headers = {
169
- "accept": "application/json",
170
- "authorization": auth_token,
171
- "build": (
172
- build_mode.value.lower()
173
- if build_mode
174
- else BuildMode.QUICK.value.lower()
175
- ),
176
- "profile": "true" if profile else "false",
177
- }
178
-
179
- url = f"{test_connection_result.host}/{ENDPOINT_COMPILED_WASM}"
180
- print(f"Compiling on {url} via {ipv4_stmt}. Zip size: {archive_size} bytes")
181
- response = client.post(
182
- url,
183
- follow_redirects=True,
184
- files=files,
185
- headers=headers,
186
- timeout=_TIMEOUT,
187
- )
188
-
189
- if response.status_code != 200:
190
- json_response = response.json()
191
- detail = json_response.get("detail", "Could not compile")
192
- return WebCompileResult(
193
- success=False, stdout=detail, hash_value=None, zip_bytes=b""
194
- )
195
-
196
- print(f"Response status code: {response}")
197
- # Create a temporary directory to extract the zip
198
- with tempfile.TemporaryDirectory() as extract_dir:
199
- extract_path = Path(extract_dir)
200
-
201
- # Write the response content to a temporary zip file
202
- temp_zip = extract_path / "response.zip"
203
- temp_zip.write_bytes(response.content)
204
-
205
- # Extract the zip
206
- shutil.unpack_archive(temp_zip, extract_path, "zip")
207
-
208
- # Read stdout from out.txt if it exists
209
- stdout_file = extract_path / "out.txt"
210
- hash_file = extract_path / "hash.txt"
211
- stdout = stdout_file.read_text() if stdout_file.exists() else ""
212
- hash_value = hash_file.read_text() if hash_file.exists() else None
213
-
214
- return WebCompileResult(
215
- success=True,
216
- stdout=stdout,
217
- hash_value=hash_value,
218
- zip_bytes=response.content,
219
- )
220
- except KeyboardInterrupt:
221
- print("Keyboard interrupt")
222
- raise
223
- except httpx.HTTPError as e:
224
- print(f"Error: {e}")
225
- return WebCompileResult(
226
- success=False, stdout=str(e), hash_value=None, zip_bytes=b""
227
- )
1
+ import io
2
+ import json
3
+ import os
4
+ import shutil
5
+ import tempfile
6
+ import zipfile
7
+ from concurrent.futures import ThreadPoolExecutor, 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
+ _THREAD_POOL = ThreadPoolExecutor(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
+ transport = httpx.HTTPTransport(local_address="0.0.0.0") if use_ipv4 else None
56
+ try:
57
+ with httpx.Client(
58
+ timeout=_TIMEOUT,
59
+ transport=transport,
60
+ ) as test_client:
61
+ test_response = test_client.get(
62
+ f"{host}/healthz", timeout=3, follow_redirects=True
63
+ )
64
+ result = ConnectionResult(host, test_response.status_code == 200, use_ipv4)
65
+ except Exception:
66
+ result = ConnectionResult(host, False, use_ipv4)
67
+ return result
68
+
69
+
70
+ def _file_info(file_path: Path) -> str:
71
+ hash_txt = hash_file(file_path)
72
+ file_size = file_path.stat().st_size
73
+ json_str = json.dumps({"hash": hash_txt, "size": file_size})
74
+ return json_str
75
+
76
+
77
+ @dataclass
78
+ class ZipResult:
79
+ zip_bytes: bytes
80
+ zip_embedded_bytes: bytes | None
81
+ success: bool
82
+ error: str | None
83
+
84
+
85
+ def zip_files(directory: Path) -> ZipResult | Exception:
86
+ print("Zipping files...")
87
+ try:
88
+ files = get_sketch_files(directory)
89
+ if not files:
90
+ raise FileNotFoundError(f"No files found in {directory}")
91
+ for f in files:
92
+ print(f"Adding file: {f}")
93
+ # Create in-memory zip file
94
+ has_embedded_zip = False
95
+ zip_embedded_buffer = io.BytesIO()
96
+ zip_buffer = io.BytesIO()
97
+ with zipfile.ZipFile(
98
+ zip_embedded_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
99
+ ) as emebedded_zip_file:
100
+ with zipfile.ZipFile(
101
+ zip_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
102
+ ) as zip_file:
103
+ for file_path in files:
104
+ relative_path = file_path.relative_to(directory)
105
+ achive_path = str(Path("wasm") / relative_path)
106
+ if str(relative_path).startswith("data") and ENABLE_EMBEDDED_DATA:
107
+ _file_info_str = _file_info(file_path)
108
+ zip_file.writestr(
109
+ achive_path + ".embedded.json", _file_info_str
110
+ )
111
+ emebedded_zip_file.write(file_path, relative_path)
112
+ has_embedded_zip = True
113
+ else:
114
+ zip_file.write(file_path, achive_path)
115
+ result = ZipResult(
116
+ zip_bytes=zip_buffer.getvalue(),
117
+ zip_embedded_bytes=(
118
+ zip_embedded_buffer.getvalue() if has_embedded_zip else None
119
+ ),
120
+ success=True,
121
+ error=None,
122
+ )
123
+ return result
124
+ except Exception as e:
125
+ return e
126
+
127
+
128
+ def web_compile(
129
+ directory: Path,
130
+ host: str | None = None,
131
+ auth_token: str | None = None,
132
+ build_mode: BuildMode | None = None,
133
+ profile: bool = False,
134
+ ) -> WebCompileResult:
135
+ host = _sanitize_host(host or DEFAULT_HOST)
136
+ print("Compiling on", host)
137
+ auth_token = auth_token or _AUTH_TOKEN
138
+
139
+ if not directory.exists():
140
+ raise FileNotFoundError(f"Directory not found: {directory}")
141
+
142
+ zip_result = zip_files(directory)
143
+
144
+ if isinstance(zip_result, Exception):
145
+ return WebCompileResult(
146
+ success=False, stdout=str(zip_result), hash_value=None, zip_bytes=b""
147
+ )
148
+ zip_bytes = zip_result.zip_bytes
149
+ archive_size = len(zip_bytes)
150
+ print(f"Web compiling on {host}...")
151
+ try:
152
+
153
+ files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
154
+ urls = [host]
155
+ domain = host.split("://")[-1]
156
+ if ":" not in domain:
157
+ urls.append(f"{host}:{SERVER_PORT}")
158
+ test_connection_result: ConnectionResult | None = None
159
+
160
+ futures: list = []
161
+ ip_versions = [True, False] if "localhost" not in host else [True]
162
+ for ipv4 in ip_versions:
163
+ for url in urls:
164
+ f = _THREAD_POOL.submit(_test_connection, url, ipv4)
165
+ futures.append(f)
166
+
167
+ succeeded = False
168
+ for future in as_completed(futures):
169
+ result: ConnectionResult = future.result()
170
+
171
+ if result.success:
172
+ print(f"Connection successful to {result.host}")
173
+ succeeded = True
174
+ # host = test_url
175
+ test_connection_result = result
176
+ break
177
+ else:
178
+ print(f"Ignoring {result.host} due to connection failure")
179
+
180
+ if not succeeded:
181
+ print("Connection failed to all endpoints")
182
+ return WebCompileResult(
183
+ success=False,
184
+ stdout="Connection failed",
185
+ hash_value=None,
186
+ zip_bytes=b"",
187
+ )
188
+ assert test_connection_result is not None
189
+ ipv4_stmt = "IPv4" if test_connection_result.ipv4 else "IPv6"
190
+ transport = (
191
+ httpx.HTTPTransport(local_address="0.0.0.0")
192
+ if test_connection_result.ipv4
193
+ else None
194
+ )
195
+ with httpx.Client(
196
+ transport=transport,
197
+ timeout=_TIMEOUT,
198
+ ) as client:
199
+ headers = {
200
+ "accept": "application/json",
201
+ "authorization": auth_token,
202
+ "build": (
203
+ build_mode.value.lower()
204
+ if build_mode
205
+ else BuildMode.QUICK.value.lower()
206
+ ),
207
+ "profile": "true" if profile else "false",
208
+ }
209
+
210
+ url = f"{test_connection_result.host}/{ENDPOINT_COMPILED_WASM}"
211
+ print(f"Compiling on {url} via {ipv4_stmt}. Zip size: {archive_size} bytes")
212
+ response = client.post(
213
+ url,
214
+ follow_redirects=True,
215
+ files=files,
216
+ headers=headers,
217
+ timeout=_TIMEOUT,
218
+ )
219
+
220
+ if response.status_code != 200:
221
+ json_response = response.json()
222
+ detail = json_response.get("detail", "Could not compile")
223
+ return WebCompileResult(
224
+ success=False, stdout=detail, hash_value=None, zip_bytes=b""
225
+ )
226
+
227
+ print(f"Response status code: {response}")
228
+ # Create a temporary directory to extract the zip
229
+ with tempfile.TemporaryDirectory() as extract_dir:
230
+ extract_path = Path(extract_dir)
231
+
232
+ # Write the response content to a temporary zip file
233
+ temp_zip = extract_path / "response.zip"
234
+ temp_zip.write_bytes(response.content)
235
+
236
+ # Extract the zip
237
+ shutil.unpack_archive(temp_zip, extract_path, "zip")
238
+
239
+ if zip_result.zip_embedded_bytes:
240
+ # extract the embedded bytes, which were not sent to the server
241
+ temp_zip.write_bytes(zip_result.zip_embedded_bytes)
242
+ shutil.unpack_archive(temp_zip, extract_path, "zip")
243
+
244
+ # we don't need the temp zip anymore
245
+ temp_zip.unlink()
246
+
247
+ # Read stdout from out.txt if it exists
248
+ stdout_file = extract_path / "out.txt"
249
+ hash_file = extract_path / "hash.txt"
250
+ stdout = stdout_file.read_text() if stdout_file.exists() else ""
251
+ hash_value = hash_file.read_text() if hash_file.exists() else None
252
+
253
+ # now rezip the extracted files since we added the embedded json files
254
+ out_buffer = io.BytesIO()
255
+ with zipfile.ZipFile(
256
+ out_buffer, "w", zipfile.ZIP_DEFLATED, compresslevel=9
257
+ ) as out_zip:
258
+ for root, _, _files in os.walk(extract_path):
259
+ for file in _files:
260
+ file_path = Path(root) / file
261
+ relative_path = file_path.relative_to(extract_path)
262
+ out_zip.write(file_path, relative_path)
263
+
264
+ return WebCompileResult(
265
+ success=True,
266
+ stdout=stdout,
267
+ hash_value=hash_value,
268
+ zip_bytes=out_buffer.getvalue(),
269
+ )
270
+ except KeyboardInterrupt:
271
+ print("Keyboard interrupt")
272
+ raise
273
+ except httpx.HTTPError as e:
274
+ print(f"Error: {e}")
275
+ return WebCompileResult(
276
+ success=False, stdout=str(e), hash_value=None, zip_bytes=b""
277
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastled
3
- Version: 1.0.8
3
+ Version: 1.0.10
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -21,6 +21,7 @@ Requires-Dist: filelock
21
21
 
22
22
  Compiles an Arduino/Platformio sketch into a wasm binary that can be run directly in the web browser.
23
23
 
24
+
24
25
  [![Linting](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml)
25
26
  [![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
27
  [![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)
@@ -92,6 +93,8 @@ provide shims for most of the common api points.
92
93
 
93
94
  # Revisions
94
95
 
96
+ * 1.1.10 - Swap large assets with embedded placeholders. This helps video sketches upload and compile instantly. Assets are re-added on after compile artifacts are returned.
97
+ * 1.1.9 - Remove auto server and instead tell the user corrective action to take.
95
98
  * 1.1.8 - Program now knows it's own version which will be displayed with help file. Use `--version` to get it directly.
96
99
  * 1.1.7 - Sketch cache re-enabled, but selectively invalidated on cpp/h updates. Cleaned up deprecated args. Fixed double thread running for containers that was causing slowdown.
97
100
  * 1.1.6 - Use the fast src volume map allow quick updates to fastled when developing on the source code.
@@ -0,0 +1,20 @@
1
+ fastled/__init__.py,sha256=8Zhmsg5KFQ2ogDbb2OFvaS5FPnsi76DJDmIxJh6z5Yg,64
2
+ fastled/app.py,sha256=cRLPDB_GR1WkRNbmHPyyDiG4DAqpiB6MpFIyfa33_c4,12522
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=8avG0mAjdjU0w1ej4LiKVGLgkHi8dZxT48TLuGecj7A,9451
7
+ fastled/docker_manager.py,sha256=WcOKa3EpIPAjICPfTL87CUYuAmX9KYT6L_Hcqbj95eE,9028
8
+ fastled/filewatcher.py,sha256=gwxNINttXQXJk3P4CpCav3-UwO3cbCg9k0ySGWOQYh0,5686
9
+ fastled/open_browser.py,sha256=-VhpGmydwLCcXmrDD2esMEdJPZYcoX2Mt73eb88Nna0,1392
10
+ fastled/paths.py,sha256=VsPmgu0lNSCFOoEC0BsTYzDygXqy15AHUfN-tTuzDZA,99
11
+ fastled/sketch.py,sha256=KhhPFqlFVlBk8YrzFy7-ioe7zEzecgrVLhyFbLpBp7k,1845
12
+ fastled/util.py,sha256=t4M3NFMhnCzfYbLvIyJi0RdFssZqbTN_vVIaej1WV-U,265
13
+ fastled/web_compile.py,sha256=Wl06e4nTAEXcn7N03eM0qLsMy4dPv6_hyZ4r7zyJJ1A,9649
14
+ fastled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
15
+ fastled-1.0.10.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
16
+ fastled-1.0.10.dist-info/METADATA,sha256=XmFMC3Pd1YlhemfA_aGSSetoNLvWnD4YFtOuPsxpRT4,6581
17
+ fastled-1.0.10.dist-info/WHEEL,sha256=0VNUDWQJzfRahYI3neAhz2UVbRCtztpN5dPHAGvmGXc,109
18
+ fastled-1.0.10.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
19
+ fastled-1.0.10.dist-info/top_level.txt,sha256=xfG6Z_ol9V5YmBROkZq2QTRwjbS2ouCUxaTJsOwfkOo,14
20
+ fastled-1.0.10.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- fastled/__init__.py,sha256=jl2oKYN0FYQt0z1v-aHeEqO9DGZIIYf3gUPuYhUrgKE,63
2
- fastled/app.py,sha256=S6hDqYw8gLOOGpXr7pBFJ4opuqY0LhqrJiymajY6FWU,12875
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=8avG0mAjdjU0w1ej4LiKVGLgkHi8dZxT48TLuGecj7A,9451
7
- fastled/docker_manager.py,sha256=WcOKa3EpIPAjICPfTL87CUYuAmX9KYT6L_Hcqbj95eE,9028
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/sketch.py,sha256=KhhPFqlFVlBk8YrzFy7-ioe7zEzecgrVLhyFbLpBp7k,1845
12
- fastled/web_compile.py,sha256=vVQ68lldGo3CaQcYGf3lh9yU6K_A3zP1gNJ29pi5J-E,7857
13
- fastled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
14
- fastled-1.0.8.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
15
- fastled-1.0.8.dist-info/METADATA,sha256=CimvtLSLl7xSQbSxb67Kdk0dRHTkvV-eDfulpjNvr0A,6316
16
- fastled-1.0.8.dist-info/WHEEL,sha256=0VNUDWQJzfRahYI3neAhz2UVbRCtztpN5dPHAGvmGXc,109
17
- fastled-1.0.8.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
18
- fastled-1.0.8.dist-info/top_level.txt,sha256=xfG6Z_ol9V5YmBROkZq2QTRwjbS2ouCUxaTJsOwfkOo,14
19
- fastled-1.0.8.dist-info/RECORD,,