sverpykit 0.2.12__tar.gz → 0.2.14__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.
- {sverpykit-0.2.12 → sverpykit-0.2.14}/PKG-INFO +1 -1
- {sverpykit-0.2.12 → sverpykit-0.2.14}/pyproject.toml +1 -1
- sverpykit-0.2.14/sverpykit/Objects/Entity.py +117 -0
- sverpykit-0.2.14/sverpykit/Objects/Platform.py +28 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Ui/TextBlock.py +5 -1
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/__init__.py +4 -2
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/core/Config.py +2 -0
- sverpykit-0.2.14/sverpykit/core/FileManager.py +17 -0
- sverpykit-0.2.14/sverpykit/core/Objects.py +17 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/core/Runtime.py +55 -3
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/core/initialize.py +16 -3
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit.egg-info/PKG-INFO +1 -1
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit.egg-info/SOURCES.txt +3 -0
- sverpykit-0.2.12/sverpykit/Objects/Entity.py +0 -68
- {sverpykit-0.2.12 → sverpykit-0.2.14}/LICENSE +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/README.md +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/setup.cfg +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Collide/Collide.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Draw/Draw.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Ui/Button.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Ui/DropDown.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Ui/SearchBar.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit/Ui/Window.py +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit.egg-info/dependency_links.txt +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit.egg-info/requires.txt +0 -0
- {sverpykit-0.2.12 → sverpykit-0.2.14}/sverpykit.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from sverpykit.core import Config, Runtime
|
|
2
|
+
from typing import Callable, Any
|
|
3
|
+
import pygame
|
|
4
|
+
|
|
5
|
+
class Entity:
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
hitbox: pygame.Rect,
|
|
9
|
+
surface: pygame.Surface,
|
|
10
|
+
player_events: dict[str, Callable] | None = None,
|
|
11
|
+
statistics: dict[str, Any] | None = None,
|
|
12
|
+
states: dict[str, Any] | None = None
|
|
13
|
+
):
|
|
14
|
+
player_events = player_events if isinstance(player_events, dict)\
|
|
15
|
+
else {}
|
|
16
|
+
statistics = statistics if isinstance(statistics, dict)\
|
|
17
|
+
else {}
|
|
18
|
+
states = states if isinstance(states, dict)\
|
|
19
|
+
else {}
|
|
20
|
+
self.hitbox = hitbox
|
|
21
|
+
self.surface = surface
|
|
22
|
+
|
|
23
|
+
self.states = {
|
|
24
|
+
"vy": 0,
|
|
25
|
+
"vx": 0,
|
|
26
|
+
"show_hitbox": False
|
|
27
|
+
}
|
|
28
|
+
self.states.update(states)
|
|
29
|
+
|
|
30
|
+
self.stats = {
|
|
31
|
+
"speed": 100,
|
|
32
|
+
"jump_power": 15
|
|
33
|
+
}
|
|
34
|
+
self.stats.update(statistics)
|
|
35
|
+
|
|
36
|
+
self.accepted_events = {
|
|
37
|
+
"key": Entity.key_events,
|
|
38
|
+
"mouse": Entity.mouse_events
|
|
39
|
+
}
|
|
40
|
+
self.accepted_events.update(player_events)
|
|
41
|
+
|
|
42
|
+
def key_events(self, keys: dict):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
def mouse_events(self, button: int, pos: tuple[int, int]):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def draw(self):
|
|
49
|
+
Config.screen.blit(
|
|
50
|
+
self.surface, self.hitbox
|
|
51
|
+
)
|
|
52
|
+
if self.states["show_hitbox"]:
|
|
53
|
+
pygame.draw.rect(
|
|
54
|
+
Config.screen,
|
|
55
|
+
(255, 255, 255),
|
|
56
|
+
self.hitbox,
|
|
57
|
+
width=1
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def events(self):
|
|
61
|
+
self.hitbox.y += self.states["vy"] * Config.delta_time
|
|
62
|
+
self.check_y_collision()
|
|
63
|
+
self.hitbox.x += self.states["vx"] * Config.delta_time
|
|
64
|
+
self.check_x_collision()
|
|
65
|
+
click = pygame.mouse.get_pressed()
|
|
66
|
+
mp = pygame.mouse.get_pos()
|
|
67
|
+
if any(click):
|
|
68
|
+
self.accepted_events["mouse"](self, click, mp)
|
|
69
|
+
keys = pygame.key.get_pressed()
|
|
70
|
+
if any(keys):
|
|
71
|
+
self.accepted_events["key"](self, keys)
|
|
72
|
+
|
|
73
|
+
def check_x_collision(self) -> None:
|
|
74
|
+
"""
|
|
75
|
+
This check should be run after every time you update the x-position of the entity.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
reset_velocity = False
|
|
79
|
+
|
|
80
|
+
for obj in Runtime.game_objects:
|
|
81
|
+
if not hasattr(obj, "collides"):
|
|
82
|
+
continue
|
|
83
|
+
if not obj.collides(self.hitbox):
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
if self.states["vx"] > 0:
|
|
87
|
+
self.hitbox.x = obj.rect.x - self.hitbox.w
|
|
88
|
+
reset_velocity = True
|
|
89
|
+
elif self.states["vx"] < 0:
|
|
90
|
+
self.hitbox.x = obj.rect.x + obj.rect.w
|
|
91
|
+
reset_velocity = True
|
|
92
|
+
|
|
93
|
+
if reset_velocity:
|
|
94
|
+
self.states["vx"] = 0
|
|
95
|
+
|
|
96
|
+
def check_y_collision(self) -> None:
|
|
97
|
+
"""
|
|
98
|
+
This check should be run after every time you update the y-position of the entity.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
reset_velocity = False
|
|
102
|
+
|
|
103
|
+
for obj in Runtime.game_objects:
|
|
104
|
+
if not hasattr(obj, "collides"):
|
|
105
|
+
continue
|
|
106
|
+
if not obj.collides(self.hitbox):
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
if self.states["vy"] > 0:
|
|
110
|
+
self.hitbox.y = obj.rect.y - self.hitbox.h
|
|
111
|
+
reset_velocity = True
|
|
112
|
+
elif self.states["vy"] < 0:
|
|
113
|
+
self.hitbox.y = obj.rect.y + obj.rect.h
|
|
114
|
+
reset_velocity = True
|
|
115
|
+
|
|
116
|
+
if reset_velocity:
|
|
117
|
+
self.states["vy"] = 0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
|
|
3
|
+
class Platform:
|
|
4
|
+
def __init__(
|
|
5
|
+
self,
|
|
6
|
+
rect: pygame.Rect,
|
|
7
|
+
surface: pygame.Surface,
|
|
8
|
+
display: pygame.Surface,
|
|
9
|
+
resize_surface: bool = True
|
|
10
|
+
):
|
|
11
|
+
self.rect = rect
|
|
12
|
+
self.surface = pygame.transform.scale(
|
|
13
|
+
surface, (self.rect.w, self.rect.h)
|
|
14
|
+
) if resize_surface else surface
|
|
15
|
+
self.display = display
|
|
16
|
+
|
|
17
|
+
def draw(self, display: pygame.Surface | None = None):
|
|
18
|
+
display = display if display else self.display
|
|
19
|
+
|
|
20
|
+
display.blit(
|
|
21
|
+
self.surface, self.rect
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def events(self):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
def collides(self, rect: pygame.Rect):
|
|
28
|
+
return self.rect.colliderect(rect)
|
|
@@ -62,7 +62,7 @@ class TextBlock:
|
|
|
62
62
|
mp[1] - self.owner.rect.y - self.rect.y
|
|
63
63
|
)
|
|
64
64
|
else:
|
|
65
|
-
mp (
|
|
65
|
+
mp = (
|
|
66
66
|
mp[0] - self.rect.x,
|
|
67
67
|
mp[1] - self.rect.y
|
|
68
68
|
)
|
|
@@ -120,3 +120,7 @@ class TextBlock:
|
|
|
120
120
|
"hyperlink": hyperlink,
|
|
121
121
|
"newline": newline
|
|
122
122
|
})
|
|
123
|
+
|
|
124
|
+
def reset(self):
|
|
125
|
+
self.text = ""
|
|
126
|
+
self.text_surfs = []
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
import pygame
|
|
3
3
|
pygame.init()
|
|
4
4
|
from .core import Config, Runtime
|
|
5
|
-
from .core.Runtime import add_layer, add_game_object, start, update as run_frame
|
|
5
|
+
from .core.Runtime import add_layer, add_game_object, start, update as run_frame, load_image
|
|
6
6
|
from .core.Config import default_exit as quit_game
|
|
7
7
|
from .core.initialize import set_display, set_frame_method, set_font, set_quit_method, set_tick_method,\
|
|
8
|
-
max_rate
|
|
8
|
+
set_src_path, max_rate
|
|
9
|
+
from .core.FileManager import resource_path
|
|
9
10
|
|
|
10
11
|
# Drawing
|
|
11
12
|
from .Draw.Draw import draw_surface, draw_rect, draw_circle, render_text
|
|
12
13
|
from .Objects.Entity import Entity
|
|
14
|
+
from .Objects.Platform import Platform
|
|
13
15
|
|
|
14
16
|
# Ui parts
|
|
15
17
|
from .Ui.Button import Button
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from sverpykit.core import FileManager
|
|
1
2
|
import pygame, sys
|
|
2
3
|
from typing import Callable
|
|
3
4
|
|
|
@@ -32,6 +33,7 @@ tick_function: Callable = tick
|
|
|
32
33
|
fonts: dict[str, pygame.font.Font] = {
|
|
33
34
|
"default": pygame.font.SysFont("arial",32)
|
|
34
35
|
}
|
|
36
|
+
images: dict[str, pygame.Surface] = {}
|
|
35
37
|
|
|
36
38
|
# Colors
|
|
37
39
|
background_color: pygame.Color | tuple[int, int, int] = (25, 25, 25)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import sys, os, pygame
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
base_path = Path(__file__).resolve().parent
|
|
5
|
+
def spk_resource_path(relative_path: str) -> str:
|
|
6
|
+
if hasattr(sys, '_MEIPASS'):
|
|
7
|
+
return os.path.join(sys._MEIPASS, f"../{relative_path}")
|
|
8
|
+
return os.path.join(base_path, f"../{relative_path}")
|
|
9
|
+
|
|
10
|
+
src_path = ""
|
|
11
|
+
def resource_path(relative_path: str) -> str:
|
|
12
|
+
if not os.path.exists(src_path):
|
|
13
|
+
raise TypeError(f"Please set the src path before you run this function!")
|
|
14
|
+
if hasattr(sys, '_MEIPASS'):
|
|
15
|
+
print("Not supported yet!")
|
|
16
|
+
return os.path.join(sys._MEIPASS, f"{relative_path}")
|
|
17
|
+
return os.path.join(src_path, f"{relative_path}")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
|
|
3
|
+
def create_rect(
|
|
4
|
+
x: int | float,
|
|
5
|
+
y: int | float,
|
|
6
|
+
width: int | float,
|
|
7
|
+
height: int | float
|
|
8
|
+
) -> pygame.Rect:
|
|
9
|
+
"""
|
|
10
|
+
This is the same
|
|
11
|
+
:param x: The x position of the rectangle.
|
|
12
|
+
:param y: The y position of the rectangle.
|
|
13
|
+
:param width: The width of the rectangle.
|
|
14
|
+
:param height: The height of the rectangle.
|
|
15
|
+
:return: Returns a pygame rectangle.
|
|
16
|
+
"""
|
|
17
|
+
return pygame.Rect(x, y, width, height)
|
|
@@ -1,21 +1,73 @@
|
|
|
1
1
|
from sverpykit.Ui.Window import Window
|
|
2
2
|
from sverpykit.Ui.TextBlock import TextBlock
|
|
3
3
|
from sverpykit.core import Config
|
|
4
|
-
import pygame
|
|
4
|
+
import pygame, sys, os
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
ui_layers = []
|
|
7
8
|
game_objects = []
|
|
8
9
|
|
|
10
|
+
def load_image(
|
|
11
|
+
path: str,
|
|
12
|
+
name: str
|
|
13
|
+
) -> pygame.Surface:
|
|
14
|
+
"""
|
|
15
|
+
:param path: The path to your file (Be sure this is a full path!).
|
|
16
|
+
:param name: The name that the image gets stored to.
|
|
17
|
+
:return: Returns the image, but also saves it in sverpykit's cache.
|
|
18
|
+
"""
|
|
19
|
+
img = pygame.image.load(path)
|
|
20
|
+
Config.images[name] = img
|
|
21
|
+
return img
|
|
22
|
+
|
|
23
|
+
def resize_image(
|
|
24
|
+
name: str,
|
|
25
|
+
width: int | float,
|
|
26
|
+
height: int | float,
|
|
27
|
+
save: bool = True
|
|
28
|
+
) -> pygame.Surface:
|
|
29
|
+
"""
|
|
30
|
+
:param name: This is the same name as where you loaded the image.
|
|
31
|
+
:param width: The width of the resized surface.
|
|
32
|
+
:param height: The height of the resized surface.
|
|
33
|
+
:param save: Decides if the image will be cached with or without changes.
|
|
34
|
+
:return: Returns the resized image.
|
|
35
|
+
"""
|
|
36
|
+
img = pygame.transform.scale(Config.images[name], (width, height))
|
|
37
|
+
if save:
|
|
38
|
+
Config.images[name] = img
|
|
39
|
+
return img
|
|
40
|
+
|
|
41
|
+
def rotate_image(
|
|
42
|
+
name: str,
|
|
43
|
+
rotation: float | int,
|
|
44
|
+
save: bool = False
|
|
45
|
+
) -> pygame.Surface:
|
|
46
|
+
"""
|
|
47
|
+
:param name: This is the same name as where you loaded the image.
|
|
48
|
+
:param rotation: The rotation of the new image in degrees.
|
|
49
|
+
:param save: Decides if the image will be cached with or without changes.
|
|
50
|
+
:return: Returns the rotated image.
|
|
51
|
+
"""
|
|
52
|
+
img = pygame.transform.rotate(
|
|
53
|
+
Config.images[name],
|
|
54
|
+
rotation
|
|
55
|
+
)
|
|
56
|
+
if save:
|
|
57
|
+
Config.images[name] = img
|
|
58
|
+
return img
|
|
59
|
+
|
|
9
60
|
def add_layer(
|
|
10
61
|
layer_type: str,
|
|
11
62
|
rectangle: pygame.Rect,
|
|
12
63
|
components: list,
|
|
13
|
-
color: tuple[int, int, int] = (150, 150, 150)
|
|
64
|
+
color: tuple[int, int, int] = (150, 150, 150),
|
|
65
|
+
**kwargs
|
|
14
66
|
) -> Window:
|
|
15
67
|
"""
|
|
16
68
|
:return: Returns nothing.
|
|
17
69
|
"""
|
|
18
|
-
w = Window(ui_layers, rectangle, components, color)
|
|
70
|
+
w = Window(ui_layers, rectangle, components, color, **kwargs)
|
|
19
71
|
for component in w.components:
|
|
20
72
|
if isinstance(component, TextBlock):
|
|
21
73
|
component.owner = w
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from sverpykit.core import Config, Runtime
|
|
1
|
+
from sverpykit.core import Config, Runtime, FileManager
|
|
2
2
|
from typing import Callable, Optional
|
|
3
|
-
import pygame
|
|
3
|
+
import pygame, os
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
# Automatic initialization
|
|
6
7
|
pygame.key.set_repeat(500, 50)
|
|
@@ -12,7 +13,8 @@ def set_display(
|
|
|
12
13
|
flags: int = 0,
|
|
13
14
|
depth: int = 0,
|
|
14
15
|
display: int = 0,
|
|
15
|
-
vsync: int = 0
|
|
16
|
+
vsync: int = 0,
|
|
17
|
+
title: str = "Pygame Window"
|
|
16
18
|
) -> pygame.Surface:
|
|
17
19
|
"""
|
|
18
20
|
:param width: Width of the screen
|
|
@@ -21,11 +23,22 @@ def set_display(
|
|
|
21
23
|
:param depth: How many colors you can use (Most of the time 8-bit is good enough. In which case just leave it blank).
|
|
22
24
|
:param display: Decides which monitor is used for the window.
|
|
23
25
|
:param vsync: Caps framerate to the monitor to avoid screen tearing (Screen tearing is just a visual glitch.)
|
|
26
|
+
:param title: What gets displayed in the title bar.
|
|
24
27
|
:return:
|
|
25
28
|
"""
|
|
26
29
|
Config.screen = pygame.display.set_mode((width, height), flags, depth, display, vsync)
|
|
30
|
+
pygame.display.set_caption(title)
|
|
27
31
|
return Config.screen
|
|
28
32
|
|
|
33
|
+
def set_src_path(src_path: Path) -> None:
|
|
34
|
+
"""
|
|
35
|
+
:param src_path: Use `pathlib.Path(__file__).resolve().parent`.
|
|
36
|
+
:return: Returns nothing.
|
|
37
|
+
"""
|
|
38
|
+
if not os.path.exists(src_path):
|
|
39
|
+
print("WARNING: Src-Path does not exist!")
|
|
40
|
+
FileManager.src_path = src_path
|
|
41
|
+
|
|
29
42
|
def max_rate(
|
|
30
43
|
fps: int | None = None,
|
|
31
44
|
tick: int | None = None
|
|
@@ -10,11 +10,14 @@ sverpykit.egg-info/top_level.txt
|
|
|
10
10
|
sverpykit/Collide/Collide.py
|
|
11
11
|
sverpykit/Draw/Draw.py
|
|
12
12
|
sverpykit/Objects/Entity.py
|
|
13
|
+
sverpykit/Objects/Platform.py
|
|
13
14
|
sverpykit/Ui/Button.py
|
|
14
15
|
sverpykit/Ui/DropDown.py
|
|
15
16
|
sverpykit/Ui/SearchBar.py
|
|
16
17
|
sverpykit/Ui/TextBlock.py
|
|
17
18
|
sverpykit/Ui/Window.py
|
|
18
19
|
sverpykit/core/Config.py
|
|
20
|
+
sverpykit/core/FileManager.py
|
|
21
|
+
sverpykit/core/Objects.py
|
|
19
22
|
sverpykit/core/Runtime.py
|
|
20
23
|
sverpykit/core/initialize.py
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
from sverpykit.core import Config
|
|
2
|
-
from typing import Callable, Any
|
|
3
|
-
import pygame
|
|
4
|
-
|
|
5
|
-
class Entity:
|
|
6
|
-
def __init__(
|
|
7
|
-
self,
|
|
8
|
-
hitbox: pygame.Rect,
|
|
9
|
-
surface: pygame.Surface,
|
|
10
|
-
player_events: dict[str, Callable] | None = None,
|
|
11
|
-
statistics: dict[str, Any] | None = None,
|
|
12
|
-
states: dict[str, Any] | None = None
|
|
13
|
-
):
|
|
14
|
-
player_events = player_events if isinstance(player_events, dict)\
|
|
15
|
-
else {}
|
|
16
|
-
statistics = statistics if isinstance(statistics, dict)\
|
|
17
|
-
else {}
|
|
18
|
-
states = states if isinstance(states, dict)\
|
|
19
|
-
else {}
|
|
20
|
-
self.hitbox = hitbox
|
|
21
|
-
self.surface = surface
|
|
22
|
-
|
|
23
|
-
self.states = {
|
|
24
|
-
"vy": 0,
|
|
25
|
-
"vx": 0,
|
|
26
|
-
"show_hitbox": False
|
|
27
|
-
}
|
|
28
|
-
self.states.update(states)
|
|
29
|
-
|
|
30
|
-
self.stats = {
|
|
31
|
-
"speed": 100,
|
|
32
|
-
"jump_power": 15
|
|
33
|
-
}
|
|
34
|
-
self.stats.update(statistics)
|
|
35
|
-
|
|
36
|
-
self.accepted_events = {
|
|
37
|
-
"key": self.key_events,
|
|
38
|
-
"mouse": self.mouse_events
|
|
39
|
-
}
|
|
40
|
-
self.accepted_events.update(player_events)
|
|
41
|
-
|
|
42
|
-
def key_events(self, keys: dict):
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
def mouse_events(self, button, pos):
|
|
46
|
-
pass
|
|
47
|
-
|
|
48
|
-
def draw(self):
|
|
49
|
-
Config.screen.blit(
|
|
50
|
-
self.surface, self.hitbox
|
|
51
|
-
)
|
|
52
|
-
if self.states["show_hitbox"]:
|
|
53
|
-
pygame.draw.rect(
|
|
54
|
-
Config.screen,
|
|
55
|
-
(255, 255, 255),
|
|
56
|
-
self.hitbox,
|
|
57
|
-
width=1
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
def events(self):
|
|
61
|
-
self.hitbox.y -= self.states["vy"] * Config.delta_time
|
|
62
|
-
click = pygame.mouse.get_pressed()
|
|
63
|
-
mp = pygame.mouse.get_pos()
|
|
64
|
-
if any(click):
|
|
65
|
-
self.accepted_events["mouse"](click, mp)
|
|
66
|
-
keys = pygame.key.get_pressed()
|
|
67
|
-
if any(keys):
|
|
68
|
-
self.accepted_events["key"](keys)
|
|
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
|