prefab 0.4.6__tar.gz → 0.5.0__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.
Files changed (50) hide show
  1. {prefab-0.4.6 → prefab-0.5.0}/PKG-INFO +24 -12
  2. {prefab-0.4.6 → prefab-0.5.0}/README.md +23 -11
  3. prefab-0.5.0/prefab/__main__.py +81 -0
  4. {prefab-0.4.6 → prefab-0.5.0}/prefab/predictor.py +90 -10
  5. {prefab-0.4.6 → prefab-0.5.0}/pyproject.toml +1 -1
  6. {prefab-0.4.6 → prefab-0.5.0}/.devcontainer/devcontainer.json +0 -0
  7. {prefab-0.4.6 → prefab-0.5.0}/.gitattributes +0 -0
  8. {prefab-0.4.6 → prefab-0.5.0}/.github/workflows/python-publish.yml +0 -0
  9. {prefab-0.4.6 → prefab-0.5.0}/.gitignore +0 -0
  10. {prefab-0.4.6 → prefab-0.5.0}/.pylintrc +0 -0
  11. {prefab-0.4.6 → prefab-0.5.0}/LICENSE +0 -0
  12. {prefab-0.4.6 → prefab-0.5.0}/assets/logo.png +0 -0
  13. {prefab-0.4.6 → prefab-0.5.0}/assets/promo_c.png +0 -0
  14. {prefab-0.4.6 → prefab-0.5.0}/assets/promo_p.png +0 -0
  15. {prefab-0.4.6 → prefab-0.5.0}/devices/circles-inverse_512x512.png +0 -0
  16. {prefab-0.4.6 → prefab-0.5.0}/devices/circles_512x512.png +0 -0
  17. {prefab-0.4.6 → prefab-0.5.0}/devices/cross-inverse_16x128_256x256.png +0 -0
  18. {prefab-0.4.6 → prefab-0.5.0}/devices/cross-inverse_32x128_256x256.png +0 -0
  19. {prefab-0.4.6 → prefab-0.5.0}/devices/cross-inverse_64x128_256x256.png +0 -0
  20. {prefab-0.4.6 → prefab-0.5.0}/devices/cross_16x128_256x256.png +0 -0
  21. {prefab-0.4.6 → prefab-0.5.0}/devices/cross_32x128_256x256.png +0 -0
  22. {prefab-0.4.6 → prefab-0.5.0}/devices/cross_64x128_256x256.png +0 -0
  23. {prefab-0.4.6 → prefab-0.5.0}/devices/demux.png +0 -0
  24. {prefab-0.4.6 → prefab-0.5.0}/devices/devices.gds +0 -0
  25. {prefab-0.4.6 → prefab-0.5.0}/devices/fleur.png +0 -0
  26. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_16x256_16_512x512.png +0 -0
  27. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_16x256_32_512x512.png +0 -0
  28. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_16x256_64_512x512.png +0 -0
  29. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_32x256_16_512x512.png +0 -0
  30. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_32x256_32_512x512.png +0 -0
  31. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_32x256_64_512x512.png +0 -0
  32. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_64x256_16_512x512.png +0 -0
  33. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_64x256_32_512x512.png +0 -0
  34. {prefab-0.4.6 → prefab-0.5.0}/devices/grating_64x256_64_512x512.png +0 -0
  35. {prefab-0.4.6 → prefab-0.5.0}/devices/pie_128x128_256x256.png +0 -0
  36. {prefab-0.4.6 → prefab-0.5.0}/devices/rectangle_128x128_256x256.png +0 -0
  37. {prefab-0.4.6 → prefab-0.5.0}/devices/ring_64x128_256x256.png +0 -0
  38. {prefab-0.4.6 → prefab-0.5.0}/devices/star_128x128_256x256.png +0 -0
  39. {prefab-0.4.6 → prefab-0.5.0}/devices/target_16x128_256x256.png +0 -0
  40. {prefab-0.4.6 → prefab-0.5.0}/devices/target_32x128_256x256.png +0 -0
  41. {prefab-0.4.6 → prefab-0.5.0}/devices/target_64x128_256x256.png +0 -0
  42. {prefab-0.4.6 → prefab-0.5.0}/docs/models.md +0 -0
  43. {prefab-0.4.6 → prefab-0.5.0}/examples/1_prediction.ipynb +0 -0
  44. {prefab-0.4.6 → prefab-0.5.0}/examples/2_prediction_gds.ipynb +0 -0
  45. {prefab-0.4.6 → prefab-0.5.0}/examples/3_correction.ipynb +0 -0
  46. {prefab-0.4.6 → prefab-0.5.0}/examples/4_prediction_silicon_nitride.ipynb +0 -0
  47. {prefab-0.4.6 → prefab-0.5.0}/prefab/__init__.py +0 -0
  48. {prefab-0.4.6 → prefab-0.5.0}/prefab/io.py +0 -0
  49. {prefab-0.4.6 → prefab-0.5.0}/prefab/processor.py +0 -0
  50. {prefab-0.4.6 → prefab-0.5.0}/requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prefab
3
- Version: 0.4.6
3
+ Version: 0.5.0
4
4
  Summary: Machine learning based prediction of photonic device fabrication
5
5
  Project-URL: Homepage, https://github.com/PreFab-Photonics/PreFab
6
6
  Author-email: Dusan Gostimirovic <dusan@prefabphotonics.com>
@@ -541,16 +541,16 @@ Description-Content-Type: text/markdown
541
541
 
542
542
  ## Models
543
543
 
544
- `PreFab` accommodates unique _predictor_ and _corrector_ models for each photonic foundry, regularly updated based on recent fabrication data. Current models include (see full list on [`docs/models.md`](docs/models.md)):
544
+ `PreFab` accommodates unique _predictor_ and _corrector_ models for each photonic foundry, regularly updated based on recent fabrication data. Current models include (see full list on [`docs/models.md`](https://github.com/PreFab-Photonics/PreFab/blob/main/docs/models.md)):
545
545
 
546
- | Foundry | Process | Latest Version | Latest Dataset | Model Name | Model Tag | Status |
547
- | --------- | ---------------------------------------------------------------------------------- | --------------- | ---------------- | ------------- | ----------- | ------ |
548
- | ANT | [NanoSOI](https://www.appliednt.com/nanosoi-fabrication-service/) | v5 (Jun 3 2023) | d4 (Apr 12 2023) | ANT_NanoSOI | v5-d4 | Beta |
549
- | ANT | [SiN (Upper Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-upper | Alpha |
550
- | ANT | [SiN (Lower Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-lower | Alpha |
551
- | SiEPICfab | [SOI](https://siepic.ca/fabrication/) | v5 (Jun 3 2023) | d0 (Jun 14 2023) | SiEPICfab_SOI | v5-d0 | Alpha |
546
+ | Foundry | Process | Latest Version | Latest Dataset | Model Name | Model Tag | Status |
547
+ | --------- | ---------------------------------------------------------------------------------- | ---------------- | ---------------- | ------------- | ----------- | ------ |
548
+ | ANT | [NanoSOI](https://www.appliednt.com/nanosoi-fabrication-service/) | v6 (Nov 24 2023) | d7 (Nov 24 2023) | ANT_NanoSOI | v6-d7 | Beta |
549
+ | ANT | [SiN (Upper Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-upper | Alpha |
550
+ | ANT | [SiN (Lower Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-lower | Alpha |
551
+ | SiEPICfab | [SOI](https://siepic.ca/fabrication/) | v5 (Jun 3 2023) | d0 (Jun 14 2023) | SiEPICfab_SOI | v5-d0 | Alpha |
552
552
 
553
- _New models and foundries are regularly added. Usage may change. For additional foundry and process models, feel free to contact us or raise an issue._
553
+ _New models and foundries are to be added. Usage may change. For additional foundry and process models, feel free to contact us or raise an issue._
554
554
 
555
555
  ## Installation
556
556
 
@@ -578,16 +578,28 @@ Use `PreFab` online through GitHub Codespaces:
578
578
 
579
579
  ## Getting Started
580
580
 
581
- Visit [`/examples`](https://github.com/PreFab-Photonics/PreFab/tree/main/examples) for usage notebooks.
581
+ ### Account setup
582
+
583
+ Before you can make PreFab requests, you will need to [create an account](https://www.prefabphotonics.com/login).
584
+
585
+ To link your account, you will need a token. You can do this by running the following command in your terminal. This will open a browser window where you can log in and authenticate your token.
586
+
587
+ ```sh
588
+ python3 -m prefab setup
589
+ ```
590
+
591
+ ### Guides
592
+
593
+ Visit [`/examples`](https://github.com/PreFab-Photonics/PreFab/tree/main/examples) or our [Guides](https://www.prefabphotonics.com/docs/guides/predictions) to get started with your first predictions.
582
594
 
583
595
  ## Performance and Usage
584
596
 
585
597
  `PreFab` models are served via a serverless cloud platform. Please note:
586
598
 
587
- - 🐢 CPU inferencing may result in slower performance. Future updates will introduce GPU inferencing.
599
+ - 🐢 CPU inference may result in slower performance. Future updates will introduce GPU inference.
588
600
  - 🥶 The first prediction may take longer due to cold start server loading. Subsequent predictions will be faster.
589
601
  - 😊 Be considerate of usage. Start small and limit usage during the initial stages. Thank you!
590
602
 
591
603
  ## License
592
604
 
593
- This project is licensed under the LGPL-2.1 license. © 2023 PreFab Photonics.
605
+ This project is licensed under the LGPL-2.1 license. © 2024 PreFab Photonics.
@@ -18,16 +18,16 @@
18
18
 
19
19
  ## Models
20
20
 
21
- `PreFab` accommodates unique _predictor_ and _corrector_ models for each photonic foundry, regularly updated based on recent fabrication data. Current models include (see full list on [`docs/models.md`](docs/models.md)):
21
+ `PreFab` accommodates unique _predictor_ and _corrector_ models for each photonic foundry, regularly updated based on recent fabrication data. Current models include (see full list on [`docs/models.md`](https://github.com/PreFab-Photonics/PreFab/blob/main/docs/models.md)):
22
22
 
23
- | Foundry | Process | Latest Version | Latest Dataset | Model Name | Model Tag | Status |
24
- | --------- | ---------------------------------------------------------------------------------- | --------------- | ---------------- | ------------- | ----------- | ------ |
25
- | ANT | [NanoSOI](https://www.appliednt.com/nanosoi-fabrication-service/) | v5 (Jun 3 2023) | d4 (Apr 12 2023) | ANT_NanoSOI | v5-d4 | Beta |
26
- | ANT | [SiN (Upper Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-upper | Alpha |
27
- | ANT | [SiN (Lower Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-lower | Alpha |
28
- | SiEPICfab | [SOI](https://siepic.ca/fabrication/) | v5 (Jun 3 2023) | d0 (Jun 14 2023) | SiEPICfab_SOI | v5-d0 | Alpha |
23
+ | Foundry | Process | Latest Version | Latest Dataset | Model Name | Model Tag | Status |
24
+ | --------- | ---------------------------------------------------------------------------------- | ---------------- | ---------------- | ------------- | ----------- | ------ |
25
+ | ANT | [NanoSOI](https://www.appliednt.com/nanosoi-fabrication-service/) | v6 (Nov 24 2023) | d7 (Nov 24 2023) | ANT_NanoSOI | v6-d7 | Beta |
26
+ | ANT | [SiN (Upper Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-upper | Alpha |
27
+ | ANT | [SiN (Lower Edge)](https://www.appliednt.com/nanosoi/sys/resources/specs_nitride/) | v5 (Jun 3 2023) | d0 (Jun 1 2023) | ANT_SiN | v5-d0-lower | Alpha |
28
+ | SiEPICfab | [SOI](https://siepic.ca/fabrication/) | v5 (Jun 3 2023) | d0 (Jun 14 2023) | SiEPICfab_SOI | v5-d0 | Alpha |
29
29
 
30
- _New models and foundries are regularly added. Usage may change. For additional foundry and process models, feel free to contact us or raise an issue._
30
+ _New models and foundries are to be added. Usage may change. For additional foundry and process models, feel free to contact us or raise an issue._
31
31
 
32
32
  ## Installation
33
33
 
@@ -55,16 +55,28 @@ Use `PreFab` online through GitHub Codespaces:
55
55
 
56
56
  ## Getting Started
57
57
 
58
- Visit [`/examples`](https://github.com/PreFab-Photonics/PreFab/tree/main/examples) for usage notebooks.
58
+ ### Account setup
59
+
60
+ Before you can make PreFab requests, you will need to [create an account](https://www.prefabphotonics.com/login).
61
+
62
+ To link your account, you will need a token. You can do this by running the following command in your terminal. This will open a browser window where you can log in and authenticate your token.
63
+
64
+ ```sh
65
+ python3 -m prefab setup
66
+ ```
67
+
68
+ ### Guides
69
+
70
+ Visit [`/examples`](https://github.com/PreFab-Photonics/PreFab/tree/main/examples) or our [Guides](https://www.prefabphotonics.com/docs/guides/predictions) to get started with your first predictions.
59
71
 
60
72
  ## Performance and Usage
61
73
 
62
74
  `PreFab` models are served via a serverless cloud platform. Please note:
63
75
 
64
- - 🐢 CPU inferencing may result in slower performance. Future updates will introduce GPU inferencing.
76
+ - 🐢 CPU inference may result in slower performance. Future updates will introduce GPU inference.
65
77
  - 🥶 The first prediction may take longer due to cold start server loading. Subsequent predictions will be faster.
66
78
  - 😊 Be considerate of usage. Start small and limit usage during the initial stages. Thank you!
67
79
 
68
80
  ## License
69
81
 
70
- This project is licensed under the LGPL-2.1 license. © 2023 PreFab Photonics.
82
+ This project is licensed under the LGPL-2.1 license. © 2024 PreFab Photonics.
@@ -0,0 +1,81 @@
1
+ """Main entry point for the Prefab CLI."""
2
+ import argparse
3
+ import os
4
+ import threading
5
+ import webbrowser
6
+ from http.server import BaseHTTPRequestHandler, HTTPServer
7
+
8
+ import toml
9
+
10
+
11
+ def store_jwt_securely(jwt, refresh_token):
12
+ """
13
+ Store the JWT and refresh token securely in a TOML file.
14
+ """
15
+ prefab_file_path = os.path.expanduser("~/.prefab.toml")
16
+ with open(prefab_file_path, "w", encoding="utf-8") as toml_file:
17
+ toml.dump({"access_token": jwt, "refresh_token": refresh_token}, toml_file)
18
+ print(f"Token successfully stored in {prefab_file_path}")
19
+
20
+
21
+ class GracefulHTTPServer(HTTPServer):
22
+ """An HTTPServer that supports graceful shutdown."""
23
+
24
+ def shutdown(self):
25
+ """Stop the serve_forever loop."""
26
+ self._BaseServer__shutdown_request = True
27
+ self.server_close()
28
+
29
+
30
+ class CallbackHandler(BaseHTTPRequestHandler):
31
+ """
32
+ A request handler for the HTTP server that handles the OAuth callback.
33
+ """
34
+
35
+ def do_GET(self):
36
+ if self.path.startswith("/callback"):
37
+ query_params = self.path.split("?")[1]
38
+ params = {
39
+ param.split("=")[0]: param.split("=")[1]
40
+ for param in query_params.split("&")
41
+ }
42
+ jwt_token = params.get("token")
43
+ refresh_token = params.get("refresh_token")
44
+ if jwt_token and refresh_token:
45
+ print("Token verified!")
46
+ store_jwt_securely(jwt_token, refresh_token)
47
+ self.send_response_only(200, "OK")
48
+ self.send_header("Content-type", "text/html")
49
+ self.end_headers()
50
+ self.wfile.write(
51
+ b"Authentication successful, you can close this window."
52
+ )
53
+ threading.Thread(target=self.server.shutdown).start()
54
+ else:
55
+ self.send_error(400, "Bad Request: Missing tokens in callback URL.")
56
+
57
+
58
+ def main():
59
+ parser = argparse.ArgumentParser(description="Prefab CLI")
60
+ parser.add_argument("command", help="The command to run", choices=["setup"])
61
+ parser.add_argument(
62
+ "--port", help="Port number for the HTTP server", type=int, default=8000
63
+ )
64
+
65
+ args = parser.parse_args()
66
+
67
+ if args.command == "setup":
68
+ webbrowser.open("https://www.prefabphotonics.com/token-flow")
69
+ httpd = GracefulHTTPServer(("localhost", args.port), CallbackHandler)
70
+ print("Started token authentication flow on the web browser...")
71
+ try:
72
+ httpd.serve_forever()
73
+ except KeyboardInterrupt:
74
+ pass
75
+ httpd.server_close()
76
+ else:
77
+ print(f"Command {args.command} not recognized.")
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()
@@ -4,9 +4,13 @@ using machine learning models deployed in the cloud.
4
4
  """
5
5
 
6
6
  import base64
7
+ import os
8
+
7
9
  import numpy as np
8
10
  import requests
9
- from cv2 import imencode, imdecode, IMREAD_GRAYSCALE
11
+ import toml
12
+ from cv2 import IMREAD_GRAYSCALE, imdecode, imencode
13
+
10
14
  from prefab.processor import binarize_hard
11
15
 
12
16
 
@@ -49,12 +53,47 @@ def predict(
49
53
  "device": _encode_image(device),
50
54
  "model_name": model_name,
51
55
  "model_tags": model_tags,
56
+ "binary": binarize,
52
57
  }
53
58
 
54
- prediction = _decode_image(
55
- requests.post(function_url, json=predict_data, timeout=200)
59
+ with open(os.path.expanduser("~/.prefab.toml"), "r") as file:
60
+ content = file.readlines()
61
+ for line in content:
62
+ if "access_token" in line:
63
+ access_token = line.split("=")[1].strip().strip('"')
64
+ if "refresh_token" in line:
65
+ refresh_token = line.split("=")[1].strip().strip('"')
66
+ break
67
+
68
+ headers = {
69
+ "Authorization": f"Bearer {access_token}",
70
+ "X-Refresh-Token": refresh_token,
71
+ }
72
+ response = requests.post(
73
+ url=function_url,
74
+ json=predict_data,
75
+ headers=headers,
56
76
  )
57
77
 
78
+ if response.status_code != 200:
79
+ raise ValueError(response.text)
80
+ else:
81
+ response_data = response.json()
82
+ if "error" in response_data:
83
+ raise ValueError(response_data["error"])
84
+ if "prediction" in response_data:
85
+ prediction = _decode_image(response_data["prediction"])
86
+ if "new_refresh_token" in response_data:
87
+ prefab_file_path = os.path.expanduser("~/.prefab.toml")
88
+ with open(prefab_file_path, "w", encoding="utf-8") as toml_file:
89
+ toml.dump(
90
+ {
91
+ "access_token": response_data["new_access_token"],
92
+ "refresh_token": response_data["new_refresh_token"],
93
+ },
94
+ toml_file,
95
+ )
96
+
58
97
  if binarize:
59
98
  prediction = binarize_hard(prediction)
60
99
 
@@ -62,7 +101,11 @@ def predict(
62
101
 
63
102
 
64
103
  def correct(
65
- device: np.ndarray, model_name: str, model_tags: str, binarize: bool = False
104
+ device: np.ndarray,
105
+ model_name: str,
106
+ model_tags: str,
107
+ binarize: bool = True,
108
+ multi_correct: bool = False,
66
109
  ) -> np.ndarray:
67
110
  """
68
111
  Generates a correction for a photonic device using a specified cloud-based ML model.
@@ -84,7 +127,11 @@ def correct(
84
127
  Consult the module's documentation for available tags.
85
128
 
86
129
  binarize : bool, optional
87
- If set to True, the correction will be binarized (default is False).
130
+ If set to True, the correction will be binarized (default is True).
131
+
132
+ multi_correct : bool, optional
133
+ If set to True, the correction will be generated using a iterative approach.
134
+ (default is False).
88
135
 
89
136
  Returns
90
137
  -------
@@ -100,14 +147,47 @@ def correct(
100
147
  "device": _encode_image(device),
101
148
  "model_name": model_name,
102
149
  "model_tags": model_tags,
150
+ "binary": binarize,
151
+ "multi_correct": multi_correct,
103
152
  }
104
153
 
105
- correction = _decode_image(
106
- requests.post(function_url, json=correct_data, timeout=200)
154
+ with open(os.path.expanduser("~/.prefab.toml"), "r") as file:
155
+ content = file.readlines()
156
+ for line in content:
157
+ if "access_token" in line:
158
+ access_token = line.split("=")[1].strip().strip('"')
159
+ if "refresh_token" in line:
160
+ refresh_token = line.split("=")[1].strip().strip('"')
161
+ break
162
+
163
+ headers = {
164
+ "Authorization": f"Bearer {access_token}",
165
+ "X-Refresh-Token": refresh_token,
166
+ }
167
+ response = requests.post(
168
+ url=function_url,
169
+ json=correct_data,
170
+ headers=headers,
107
171
  )
108
172
 
109
- if binarize:
110
- correction = binarize_hard(correction)
173
+ if response.status_code != 200:
174
+ raise ValueError(response.text)
175
+ else:
176
+ response_data = response.json()
177
+ if "error" in response_data:
178
+ raise ValueError(response_data["error"])
179
+ if "correction" in response_data:
180
+ correction = _decode_image(response_data["correction"])
181
+ if "new_refresh_token" in response_data:
182
+ prefab_file_path = os.path.expanduser("~/.prefab.toml")
183
+ with open(prefab_file_path, "w", encoding="utf-8") as toml_file:
184
+ toml.dump(
185
+ {
186
+ "access_token": response_data["new_access_token"],
187
+ "refresh_token": response_data["new_refresh_token"],
188
+ },
189
+ toml_file,
190
+ )
111
191
 
112
192
  return correction
113
193
 
@@ -145,7 +225,7 @@ def _decode_image(encoded_image_base64: str) -> np.ndarray:
145
225
  np.ndarray
146
226
  The decoded image in numpy array format.
147
227
  """
148
- encoded_image = base64.b64decode(encoded_image_base64.json())
228
+ encoded_image = base64.b64decode(encoded_image_base64)
149
229
  decoded_image = np.frombuffer(encoded_image, np.uint8)
150
230
  decoded_image = imdecode(decoded_image, IMREAD_GRAYSCALE) / 255
151
231
  return decoded_image
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "prefab"
7
- version = "0.4.6"
7
+ version = "0.5.0"
8
8
  authors = [
9
9
  {name = "Dusan Gostimirovic", email="dusan@prefabphotonics.com"},
10
10
  ]
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