plain 0.16.1__tar.gz → 0.17.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 (157) hide show
  1. {plain-0.16.1 → plain-0.17.0}/PKG-INFO +1 -1
  2. {plain-0.16.1 → plain-0.17.0}/plain/http/response.py +5 -30
  3. {plain-0.16.1 → plain-0.17.0}/plain/internal/handlers/wsgi.py +1 -1
  4. {plain-0.16.1 → plain-0.17.0}/plain/internal/middleware/headers.py +1 -1
  5. {plain-0.16.1 → plain-0.17.0}/plain/test/client.py +2 -2
  6. {plain-0.16.1 → plain-0.17.0}/plain/utils/cache.py +5 -5
  7. {plain-0.16.1 → plain-0.17.0}/pyproject.toml +1 -1
  8. {plain-0.16.1 → plain-0.17.0}/uv.lock +1 -1
  9. {plain-0.16.1 → plain-0.17.0}/.gitignore +0 -0
  10. {plain-0.16.1 → plain-0.17.0}/LICENSE +0 -0
  11. {plain-0.16.1 → plain-0.17.0}/README.md +0 -0
  12. {plain-0.16.1 → plain-0.17.0}/plain/README.md +0 -0
  13. {plain-0.16.1 → plain-0.17.0}/plain/__main__.py +0 -0
  14. {plain-0.16.1 → plain-0.17.0}/plain/assets/README.md +0 -0
  15. {plain-0.16.1 → plain-0.17.0}/plain/assets/__init__.py +0 -0
  16. {plain-0.16.1 → plain-0.17.0}/plain/assets/compile.py +0 -0
  17. {plain-0.16.1 → plain-0.17.0}/plain/assets/finders.py +0 -0
  18. {plain-0.16.1 → plain-0.17.0}/plain/assets/fingerprints.py +0 -0
  19. {plain-0.16.1 → plain-0.17.0}/plain/assets/urls.py +0 -0
  20. {plain-0.16.1 → plain-0.17.0}/plain/assets/views.py +0 -0
  21. {plain-0.16.1 → plain-0.17.0}/plain/cli/README.md +0 -0
  22. {plain-0.16.1 → plain-0.17.0}/plain/cli/__init__.py +0 -0
  23. {plain-0.16.1 → plain-0.17.0}/plain/cli/cli.py +0 -0
  24. {plain-0.16.1 → plain-0.17.0}/plain/cli/formatting.py +0 -0
  25. {plain-0.16.1 → plain-0.17.0}/plain/cli/packages.py +0 -0
  26. {plain-0.16.1 → plain-0.17.0}/plain/cli/print.py +0 -0
  27. {plain-0.16.1 → plain-0.17.0}/plain/cli/startup.py +0 -0
  28. {plain-0.16.1 → plain-0.17.0}/plain/csrf/README.md +0 -0
  29. {plain-0.16.1 → plain-0.17.0}/plain/csrf/middleware.py +0 -0
  30. {plain-0.16.1 → plain-0.17.0}/plain/csrf/views.py +0 -0
  31. {plain-0.16.1 → plain-0.17.0}/plain/debug.py +0 -0
  32. {plain-0.16.1 → plain-0.17.0}/plain/exceptions.py +0 -0
  33. {plain-0.16.1 → plain-0.17.0}/plain/forms/README.md +0 -0
  34. {plain-0.16.1 → plain-0.17.0}/plain/forms/__init__.py +0 -0
  35. {plain-0.16.1 → plain-0.17.0}/plain/forms/boundfield.py +0 -0
  36. {plain-0.16.1 → plain-0.17.0}/plain/forms/exceptions.py +0 -0
  37. {plain-0.16.1 → plain-0.17.0}/plain/forms/fields.py +0 -0
  38. {plain-0.16.1 → plain-0.17.0}/plain/forms/forms.py +0 -0
  39. {plain-0.16.1 → plain-0.17.0}/plain/http/README.md +0 -0
  40. {plain-0.16.1 → plain-0.17.0}/plain/http/__init__.py +0 -0
  41. {plain-0.16.1 → plain-0.17.0}/plain/http/cookie.py +0 -0
  42. {plain-0.16.1 → plain-0.17.0}/plain/http/multipartparser.py +0 -0
  43. {plain-0.16.1 → plain-0.17.0}/plain/http/request.py +0 -0
  44. {plain-0.16.1 → plain-0.17.0}/plain/internal/__init__.py +0 -0
  45. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/README.md +0 -0
  46. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/__init__.py +0 -0
  47. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/base.py +0 -0
  48. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/locks.py +0 -0
  49. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/move.py +0 -0
  50. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/temp.py +0 -0
  51. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/uploadedfile.py +0 -0
  52. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/uploadhandler.py +0 -0
  53. {plain-0.16.1 → plain-0.17.0}/plain/internal/files/utils.py +0 -0
  54. {plain-0.16.1 → plain-0.17.0}/plain/internal/handlers/__init__.py +0 -0
  55. {plain-0.16.1 → plain-0.17.0}/plain/internal/handlers/base.py +0 -0
  56. {plain-0.16.1 → plain-0.17.0}/plain/internal/handlers/exception.py +0 -0
  57. {plain-0.16.1 → plain-0.17.0}/plain/internal/middleware/__init__.py +0 -0
  58. {plain-0.16.1 → plain-0.17.0}/plain/internal/middleware/https.py +0 -0
  59. {plain-0.16.1 → plain-0.17.0}/plain/internal/middleware/slash.py +0 -0
  60. {plain-0.16.1 → plain-0.17.0}/plain/json.py +0 -0
  61. {plain-0.16.1 → plain-0.17.0}/plain/logs/README.md +0 -0
  62. {plain-0.16.1 → plain-0.17.0}/plain/logs/__init__.py +0 -0
  63. {plain-0.16.1 → plain-0.17.0}/plain/logs/configure.py +0 -0
  64. {plain-0.16.1 → plain-0.17.0}/plain/logs/loggers.py +0 -0
  65. {plain-0.16.1 → plain-0.17.0}/plain/logs/utils.py +0 -0
  66. {plain-0.16.1 → plain-0.17.0}/plain/packages/README.md +0 -0
  67. {plain-0.16.1 → plain-0.17.0}/plain/packages/__init__.py +0 -0
  68. {plain-0.16.1 → plain-0.17.0}/plain/packages/config.py +0 -0
  69. {plain-0.16.1 → plain-0.17.0}/plain/packages/registry.py +0 -0
  70. {plain-0.16.1 → plain-0.17.0}/plain/paginator.py +0 -0
  71. {plain-0.16.1 → plain-0.17.0}/plain/preflight/README.md +0 -0
  72. {plain-0.16.1 → plain-0.17.0}/plain/preflight/__init__.py +0 -0
  73. {plain-0.16.1 → plain-0.17.0}/plain/preflight/files.py +0 -0
  74. {plain-0.16.1 → plain-0.17.0}/plain/preflight/messages.py +0 -0
  75. {plain-0.16.1 → plain-0.17.0}/plain/preflight/registry.py +0 -0
  76. {plain-0.16.1 → plain-0.17.0}/plain/preflight/security.py +0 -0
  77. {plain-0.16.1 → plain-0.17.0}/plain/preflight/urls.py +0 -0
  78. {plain-0.16.1 → plain-0.17.0}/plain/runtime/README.md +0 -0
  79. {plain-0.16.1 → plain-0.17.0}/plain/runtime/__init__.py +0 -0
  80. {plain-0.16.1 → plain-0.17.0}/plain/runtime/global_settings.py +0 -0
  81. {plain-0.16.1 → plain-0.17.0}/plain/runtime/user_settings.py +0 -0
  82. {plain-0.16.1 → plain-0.17.0}/plain/signals/README.md +0 -0
  83. {plain-0.16.1 → plain-0.17.0}/plain/signals/__init__.py +0 -0
  84. {plain-0.16.1 → plain-0.17.0}/plain/signals/dispatch/__init__.py +0 -0
  85. {plain-0.16.1 → plain-0.17.0}/plain/signals/dispatch/dispatcher.py +0 -0
  86. {plain-0.16.1 → plain-0.17.0}/plain/signals/dispatch/license.txt +0 -0
  87. {plain-0.16.1 → plain-0.17.0}/plain/signing.py +0 -0
  88. {plain-0.16.1 → plain-0.17.0}/plain/templates/README.md +0 -0
  89. {plain-0.16.1 → plain-0.17.0}/plain/templates/__init__.py +0 -0
  90. {plain-0.16.1 → plain-0.17.0}/plain/templates/core.py +0 -0
  91. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/README.md +0 -0
  92. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/__init__.py +0 -0
  93. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/environments.py +0 -0
  94. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/extensions.py +0 -0
  95. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/filters.py +0 -0
  96. {plain-0.16.1 → plain-0.17.0}/plain/templates/jinja/globals.py +0 -0
  97. {plain-0.16.1 → plain-0.17.0}/plain/test/README.md +0 -0
  98. {plain-0.16.1 → plain-0.17.0}/plain/test/__init__.py +0 -0
  99. {plain-0.16.1 → plain-0.17.0}/plain/urls/README.md +0 -0
  100. {plain-0.16.1 → plain-0.17.0}/plain/urls/__init__.py +0 -0
  101. {plain-0.16.1 → plain-0.17.0}/plain/urls/base.py +0 -0
  102. {plain-0.16.1 → plain-0.17.0}/plain/urls/conf.py +0 -0
  103. {plain-0.16.1 → plain-0.17.0}/plain/urls/converters.py +0 -0
  104. {plain-0.16.1 → plain-0.17.0}/plain/urls/exceptions.py +0 -0
  105. {plain-0.16.1 → plain-0.17.0}/plain/urls/resolvers.py +0 -0
  106. {plain-0.16.1 → plain-0.17.0}/plain/utils/README.md +0 -0
  107. {plain-0.16.1 → plain-0.17.0}/plain/utils/__init__.py +0 -0
  108. {plain-0.16.1 → plain-0.17.0}/plain/utils/_os.py +0 -0
  109. {plain-0.16.1 → plain-0.17.0}/plain/utils/connection.py +0 -0
  110. {plain-0.16.1 → plain-0.17.0}/plain/utils/crypto.py +0 -0
  111. {plain-0.16.1 → plain-0.17.0}/plain/utils/datastructures.py +0 -0
  112. {plain-0.16.1 → plain-0.17.0}/plain/utils/dateformat.py +0 -0
  113. {plain-0.16.1 → plain-0.17.0}/plain/utils/dateparse.py +0 -0
  114. {plain-0.16.1 → plain-0.17.0}/plain/utils/dates.py +0 -0
  115. {plain-0.16.1 → plain-0.17.0}/plain/utils/deconstruct.py +0 -0
  116. {plain-0.16.1 → plain-0.17.0}/plain/utils/decorators.py +0 -0
  117. {plain-0.16.1 → plain-0.17.0}/plain/utils/deprecation.py +0 -0
  118. {plain-0.16.1 → plain-0.17.0}/plain/utils/duration.py +0 -0
  119. {plain-0.16.1 → plain-0.17.0}/plain/utils/email.py +0 -0
  120. {plain-0.16.1 → plain-0.17.0}/plain/utils/encoding.py +0 -0
  121. {plain-0.16.1 → plain-0.17.0}/plain/utils/functional.py +0 -0
  122. {plain-0.16.1 → plain-0.17.0}/plain/utils/hashable.py +0 -0
  123. {plain-0.16.1 → plain-0.17.0}/plain/utils/html.py +0 -0
  124. {plain-0.16.1 → plain-0.17.0}/plain/utils/http.py +0 -0
  125. {plain-0.16.1 → plain-0.17.0}/plain/utils/inspect.py +0 -0
  126. {plain-0.16.1 → plain-0.17.0}/plain/utils/ipv6.py +0 -0
  127. {plain-0.16.1 → plain-0.17.0}/plain/utils/itercompat.py +0 -0
  128. {plain-0.16.1 → plain-0.17.0}/plain/utils/module_loading.py +0 -0
  129. {plain-0.16.1 → plain-0.17.0}/plain/utils/regex_helper.py +0 -0
  130. {plain-0.16.1 → plain-0.17.0}/plain/utils/safestring.py +0 -0
  131. {plain-0.16.1 → plain-0.17.0}/plain/utils/text.py +0 -0
  132. {plain-0.16.1 → plain-0.17.0}/plain/utils/timesince.py +0 -0
  133. {plain-0.16.1 → plain-0.17.0}/plain/utils/timezone.py +0 -0
  134. {plain-0.16.1 → plain-0.17.0}/plain/utils/tree.py +0 -0
  135. {plain-0.16.1 → plain-0.17.0}/plain/validators.py +0 -0
  136. {plain-0.16.1 → plain-0.17.0}/plain/views/README.md +0 -0
  137. {plain-0.16.1 → plain-0.17.0}/plain/views/__init__.py +0 -0
  138. {plain-0.16.1 → plain-0.17.0}/plain/views/base.py +0 -0
  139. {plain-0.16.1 → plain-0.17.0}/plain/views/csrf.py +0 -0
  140. {plain-0.16.1 → plain-0.17.0}/plain/views/errors.py +0 -0
  141. {plain-0.16.1 → plain-0.17.0}/plain/views/exceptions.py +0 -0
  142. {plain-0.16.1 → plain-0.17.0}/plain/views/forms.py +0 -0
  143. {plain-0.16.1 → plain-0.17.0}/plain/views/objects.py +0 -0
  144. {plain-0.16.1 → plain-0.17.0}/plain/views/redirect.py +0 -0
  145. {plain-0.16.1 → plain-0.17.0}/plain/views/templates.py +0 -0
  146. {plain-0.16.1 → plain-0.17.0}/plain/wsgi.py +0 -0
  147. {plain-0.16.1 → plain-0.17.0}/tests/.bolt/assets_collected/assets.json +0 -0
  148. {plain-0.16.1 → plain-0.17.0}/tests/.gitignore +0 -0
  149. {plain-0.16.1 → plain-0.17.0}/tests/app/.gitignore +0 -0
  150. {plain-0.16.1 → plain-0.17.0}/tests/app/settings.py +0 -0
  151. {plain-0.16.1 → plain-0.17.0}/tests/app/test/__init__.py +0 -0
  152. {plain-0.16.1 → plain-0.17.0}/tests/app/test/default_settings.py +0 -0
  153. {plain-0.16.1 → plain-0.17.0}/tests/app/urls.py +0 -0
  154. {plain-0.16.1 → plain-0.17.0}/tests/conftest.py +0 -0
  155. {plain-0.16.1 → plain-0.17.0}/tests/test_cli.py +0 -0
  156. {plain-0.16.1 → plain-0.17.0}/tests/test_runtime.py +0 -0
  157. {plain-0.16.1 → plain-0.17.0}/tests/test_wsgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain
3
- Version: 0.16.1
3
+ Version: 0.17.0
4
4
  Summary: A web framework for building products with Python.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -187,27 +187,6 @@ class ResponseBase:
187
187
  else ""
188
188
  )
189
189
 
190
- def __setitem__(self, header, value):
191
- self.headers[header] = value
192
-
193
- def __delitem__(self, header):
194
- del self.headers[header]
195
-
196
- def __getitem__(self, header):
197
- return self.headers[header]
198
-
199
- def has_header(self, header):
200
- """Case-insensitive check for a header."""
201
- return header in self.headers
202
-
203
- __contains__ = has_header
204
-
205
- def items(self):
206
- return self.headers.items()
207
-
208
- def get(self, header, alternate=None):
209
- return self.headers.get(header, alternate)
210
-
211
190
  def set_cookie(
212
191
  self,
213
192
  key,
@@ -272,10 +251,6 @@ class ResponseBase:
272
251
  raise ValueError('samesite must be "lax", "none", or "strict".')
273
252
  self.cookies[key]["samesite"] = samesite
274
253
 
275
- def setdefault(self, key, value):
276
- """Set a header unless it has already been set."""
277
- self.headers.setdefault(key, value)
278
-
279
254
  def set_signed_cookie(self, key, value, salt="", **kwargs):
280
255
  value = signing.get_cookie_signer(salt=key + salt).sign(value)
281
256
  return self.set_cookie(key, value, **kwargs)
@@ -587,14 +562,14 @@ class ResponseRedirectBase(Response):
587
562
 
588
563
  def __init__(self, redirect_to, *args, **kwargs):
589
564
  super().__init__(*args, **kwargs)
590
- self["Location"] = iri_to_uri(redirect_to)
565
+ self.headers["Location"] = iri_to_uri(redirect_to)
591
566
  parsed = urlparse(str(redirect_to))
592
567
  if parsed.scheme and parsed.scheme not in self.allowed_schemes:
593
568
  raise DisallowedRedirect(
594
569
  f"Unsafe redirect to URL with protocol '{parsed.scheme}'"
595
570
  )
596
571
 
597
- url = property(lambda self: self["Location"])
572
+ url = property(lambda self: self.headers["Location"])
598
573
 
599
574
  def __repr__(self):
600
575
  return (
@@ -627,7 +602,7 @@ class ResponseNotModified(Response):
627
602
 
628
603
  def __init__(self, *args, **kwargs):
629
604
  super().__init__(*args, **kwargs)
630
- del self["content-type"]
605
+ del self.headers["content-type"]
631
606
 
632
607
  @Response.content.setter
633
608
  def content(self, value):
@@ -663,14 +638,14 @@ class ResponseNotAllowed(Response):
663
638
 
664
639
  def __init__(self, permitted_methods, *args, **kwargs):
665
640
  super().__init__(*args, **kwargs)
666
- self["Allow"] = ", ".join(permitted_methods)
641
+ self.headers["Allow"] = ", ".join(permitted_methods)
667
642
 
668
643
  def __repr__(self):
669
644
  return "<%(cls)s [%(methods)s] status_code=%(status_code)d%(content_type)s>" % { # noqa: UP031
670
645
  "cls": self.__class__.__name__,
671
646
  "status_code": self.status_code,
672
647
  "content_type": self._content_type_for_repr,
673
- "methods": self["Allow"],
648
+ "methods": self.headers["Allow"],
674
649
  }
675
650
 
676
651
 
@@ -140,7 +140,7 @@ class WSGIHandler(base.BaseHandler):
140
140
 
141
141
  status = "%d %s" % (response.status_code, response.reason_phrase) # noqa: UP031
142
142
  response_headers = [
143
- *response.items(),
143
+ *response.headers.items(),
144
144
  *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()),
145
145
  ]
146
146
  start_response(status, response_headers)
@@ -19,7 +19,7 @@ class DefaultHeadersMiddleware:
19
19
 
20
20
  # Add the Content-Length header to non-streaming responses if not
21
21
  # already set.
22
- if not response.streaming and not response.has_header("Content-Length"):
22
+ if not response.streaming and "Content-Length" not in response.headers:
23
23
  response.headers["Content-Length"] = str(len(response.content))
24
24
 
25
25
  return response
@@ -615,10 +615,10 @@ class ClientMixin:
615
615
 
616
616
  def _parse_json(self, response, **extra):
617
617
  if not hasattr(response, "_json"):
618
- if not JSON_CONTENT_TYPE_RE.match(response.get("Content-Type")):
618
+ if not JSON_CONTENT_TYPE_RE.match(response.headers.get("Content-Type")):
619
619
  raise ValueError(
620
620
  'Content-Type header is "{}", not "application/json"'.format(
621
- response.get("Content-Type")
621
+ response.headers.get("Content-Type")
622
622
  )
623
623
  )
624
624
  response._json = json.loads(
@@ -55,7 +55,7 @@ def patch_cache_control(response, **kwargs):
55
55
  return f"{t[0]}={t[1]}"
56
56
 
57
57
  cc = defaultdict(set)
58
- if response.get("Cache-Control"):
58
+ if response.headers.get("Cache-Control"):
59
59
  for field in cc_delim_re.split(response.headers["Cache-Control"]):
60
60
  directive, value = dictitem(field)
61
61
  if directive == "no-cache":
@@ -102,7 +102,7 @@ def get_max_age(response):
102
102
  Return the max-age from the response Cache-Control header as an integer,
103
103
  or None if it wasn't found or wasn't an integer.
104
104
  """
105
- if not response.has_header("Cache-Control"):
105
+ if "Cache-Control" not in response.headers:
106
106
  return
107
107
  cc = dict(
108
108
  _to_tuple(el) for el in cc_delim_re.split(response.headers["Cache-Control"])
@@ -146,7 +146,7 @@ def _not_modified(request, response=None):
146
146
  "Last-Modified",
147
147
  "Vary",
148
148
  ):
149
- if header in response:
149
+ if header in response.headers:
150
150
  new_response.headers[header] = response.headers[header]
151
151
 
152
152
  # Preserve cookies as per the cookie specification: "If a proxy server
@@ -278,7 +278,7 @@ def patch_response_headers(response, cache_timeout=None):
278
278
  cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
279
279
  if cache_timeout < 0:
280
280
  cache_timeout = 0 # Can't have max-age negative
281
- if not response.has_header("Expires"):
281
+ if "Expires" not in response.headers:
282
282
  response.headers["Expires"] = http_date(time.time() + cache_timeout)
283
283
  patch_cache_control(response, max_age=cache_timeout)
284
284
 
@@ -303,7 +303,7 @@ def patch_vary_headers(response, newheaders):
303
303
  # Note that we need to keep the original order intact, because cache
304
304
  # implementations may rely on the order of the Vary contents in, say,
305
305
  # computing an MD5 hash.
306
- if response.has_header("Vary"):
306
+ if "Vary" in response.headers:
307
307
  vary_headers = cc_delim_re.split(response.headers["Vary"])
308
308
  else:
309
309
  vary_headers = []
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "plain"
3
- version = "0.16.1"
3
+ version = "0.17.0"
4
4
  description = "A web framework for building products with Python."
5
5
  authors = [{name = "Dave Gaeddert", email = "dave.gaeddert@dropseed.dev"}]
6
6
  readme = "README.md"
@@ -102,7 +102,7 @@ wheels = [
102
102
 
103
103
  [[package]]
104
104
  name = "plain"
105
- version = "0.16.1"
105
+ version = "0.17.0"
106
106
  source = { editable = "." }
107
107
  dependencies = [
108
108
  { name = "click" },
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