Manual:Creating parametric objects/pl: Difference between revisions

From FreeCAD Documentation
(Updating to match new version of source page)
(Created page with "{{Docnav/pl |Tworzenie i obróbka geometrii |Tworzenie narzędzi interfejsu |Podręcznik:Słowo wstępne |IconC=Crystal Clear manual.png }}")
 
(24 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<languages/>
<languages/>


{{Docnav/pl
{{Docnav|[[Manual:Creating and manipulating geometry|Creating and manipulating geometry]]|[[Manual:Creating interface tools|Creating interface tools]]|[[Manual:Introduction|Manual start]]|IconC=Crystal Clear manual.png}}
|[[Manual:Creating and manipulating geometry/pl|Tworzenie i obróbka geometrii]]
|[[Manual:Creating interface tools/pl|Tworzenie narzędzi interfejsu]]
|[[Manual:Introduction/pl|Podręcznik:Słowo wstępne]]
|IconC=Crystal Clear manual.png
}}


{{Manual:TOC}}
{{Manual:TOC}}


In the [[Manual:Creating and manipulating geometry|previous chapter]], we saw how to create Part geometry, and how to display it on screen, by attaching it to a "dumb" (non-parametric) document object. This is tedious when we want to change the shape of that object. We would need to create a new shape, then attribute it again to our object.
W rozdziale [[Manual:Creating and manipulating geometry/pl|Tworzenie i obróbka geometrii]] widzieliśmy, jak tworzyć geometrię części i jak wyświetlać na ekranie, dołączając do "pospolitego" ''(nieparametrycznego)'' obiektu dokumentu. Jest to uciążliwe, gdy chcemy zmienić kształt tego obiektu. Musielibyśmy utworzyć nowy kształt, a następnie ponownie przypisać go do naszego obiektu.


Jednak we wszystkich poprzednich rozdziałach tego podręcznika widzieliśmy również, jak potężne są obiekty parametryczne. Wystarczy zmienić tylko jedną właściwość, a kształt zostanie przeliczony w locie.
However, we also saw in all the preceding chapters of this manual how parametric objects are powerful. We only need to change one property, and the shape is recalculated on-the-fly.


Wewnętrznie obiekty parametryczne nie robią nic innego niż przed chwilą: Ponownie obliczają zawartość swojej właściwości Kształt, w kółko, za każdym razem, gdy zmieni się inna właściwość.
Internally, parametric objects don't do anything different than we just did: They recalculate the contents of their Shape property, over and over, each time another property has changed.


FreeCAD zapewnia bardzo wygodny system do budowania takich w pełni parametrycznych obiektów w Pythonie. Składają się one z prostej klasy Python, która definiuje wszystkie właściwości potrzebne obiektowi i co się stanie, gdy jedna z tych właściwości ulegnie zmianie. Struktura takiego obiektu parametrycznego jest bardzo prosta:
FreeCAD provides a very convenient system to build such parametric objects fully in Python. They consist of a simple Python class, which defines all the properties that the object needs, and what will happen when one of these properties changes. The structure of such parametric object is as simple as this:


{{Code|code=
{{Code|code=
Line 28: Line 33:
}}
}}


Wszystkie klasy Pythona zazwyczaj posiadają metodę __init__. To, co znajduje się wewnątrz tej metody, jest wykonywane, gdy klasa jest instancjonowana (co oznacza, w slangu programistycznym, że obiekt Pythona jest tworzony z tej klasy. Potraktuj klasę jako "szablon" do tworzenia jej żywych kopii). W naszej funkcji __init__ robimy dwie ważne rzeczy: <br>1- przechowujemy naszą klasę w atrybucie "Proxy" naszego obiektu dokumentu FreeCAD, co oznacza, że obiekt dokumentu FreeCAD będzie przenosił ten kod wewnątrz siebie, oraz <br>2- tworzymy wszystkie właściwości, których potrzebuje nasz obiekt. Dostępnych jest wiele rodzajów właściwości, pełną listę można uzyskać, wpisując ten kod:
All Python classes usually have an __init__ method. What is inside that method is executed when that class is instantiated (which means, in programming slang, that a Python Object is created from that class. Think of a class as a "template" to create live copies of it). In our __init__ function here, we do two important things: 1- store our class itself into the "Proxy" attribute of our FreeCAD document object, that is, the FreeCAD document object will carry this code, inside itself, and 2- create all the properties our object needs. There are many types of properties available, you can get the full list by typing this code:


{{Code|code=
{{Code|code=
Line 34: Line 39:
}}
}}


Drugą ważną częścią jest metoda execute. Każdy kod w tej metodzie zostanie wykonany, gdy obiekt zostanie oznaczony do ponownego obliczenia, co nastąpi, gdy właściwość zostanie zmieniona. To już wszystko. Wewnątrz execute musisz zrobić wszystko, co trzeba, czyli obliczyć nowy kształt i przypisać go do samego obiektu za pomocą czegoś takiego jak obj.Shape = myNewShape. Dlatego właśnie metoda execute przyjmuje argument "obj", który będzie samym obiektem dokumentu FreeCAD, dzięki czemu możemy nim manipulować wewnątrz naszego kodu Python.
Then, the second important part is the execute method. Any code in this method will be executed when the object is marked to be recomputed, which will happen when a property has been changed. That is all there is to it. Inside execute, you need to do all that needs to be done, that is, calculating a new shape, and attributing to the object itself with something like obj.Shape = myNewShape. That is why the execute method takes an "obj" argument, which will be the FreeCAD document object itself, so we can manipulate it inside our python code.


Ostatnia rzecz jest ważna do zapamiętania: Podczas tworzenia takich obiektów parametrycznych w dokumencie FreeCAD, po zapisaniu pliku, powyższy kod Python nie jest przechowywany wewnątrz pliku. Wynika to ze względów bezpieczeństwa, gdyby plik FreeCAD zawierał kod, ktoś mógłby rozpowszechniać pliki FreeCAD zawierające złośliwy kod, który mógłby uszkodzić komputery innych osób. Tak więc, jeśli dystrybuujesz plik, który zawiera obiekty wykonane przy użyciu powyższego kodu, taki kod musi być również obecny na komputerze, który otworzy plik. Najłatwiejszym sposobem na osiągnięcie tego jest zazwyczaj zapisanie powyższego kodu w makrze i rozpowszechnianie makra wraz z plikiem FreeCAD lub udostępnienie makra na [[Macros_recipes/pl|Repozytorium makr FreeCAD]], skąd każdy może je pobrać.
One last thing is important to remember: When you create such parametric objects in a FreeCAD document, when you save the file, the python code above is not stored inside the file. This is for security reasons, if a FreeCAD file contained code, it would be possible for someone to distribute FreeCAD files containing malicious code that could harm other people's computers. So, if you distribute a file that contains objects made with the above code, such code must also be present on the computer that will open the file. The easiest way to achieve that is usually to save the code above in a macro, and distribute the macro together with your FreeCAD file, or share your macro on the [[Macros_recipes|FreeCAD macros repository]] where anybody can download it.


Below, we will do a small exercise, building a parametric object that is a simple parametric rectangular face. More complex examples are available on the [[Scripted_objects|parametric object example]] and in the [https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/TemplatePyMod/FeaturePython.py FreeCAD source code] itself.
Poniżej wykonamy małe ćwiczenie, budując obiekt parametryczny, który jest prostą parametryczną prostokątną powierzchnią. Bardziej złożone przykłady dostępne na stronie [[Scripted_objects/pl|Obiekty tworzone skryptami]] oraz w samym kodzie źródłowym [https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/TemplatePyMod/FeaturePython.py FreeCAD].


Nadamy naszemu obiektowi dwie właściwości: Długość i Szerokość, które wykorzystamy do skonstruowania prostokąta. Następnie, ponieważ nasz obiekt będzie już miał wstępnie zbudowaną właściwość Umiejscowienie (wszystkie obiekty geometryczne mają ją domyślnie, nie trzeba jej dodawać samodzielnie), przesuniemy nasz prostokąt do lokalizacji / obrotu ustawionego w Placement, dzięki czemu użytkownik będzie mógł przenieść prostokąt w dowolne miejsce, edytując właściwość Umiejscowienie.
We will give our object two properties: Length and Width, which we will use to construct a rectangle. Then, since our object will already have a pre-built Placement property (all geometric object have one by default, no need to add it ourselves), we will displace our rectangle to the location/rotation set in the Placement, so the user will be able to move the rectangle anywhere by editing the Placement property.


{{Code|code=
{{Code|code=
Line 88: Line 93:
}}
}}


Instead of pasting the above code in the Python console, we'd better save it somewhere, so we can reuse and modify it later. For example in a new macro (menu Tools -> Macros -> Create). Name it, for example, "ParamRectangle". However, FreeCAD macros are saved with a .FCMacro extension, which Python doesn't recognize when using import . So, before using the above code, we will need to rename the ParamRectangle.FCMacro file to ParamRectangle.py. This can be done simply from your file explorer, by navigating to the Macros folder indicated in menu Tools -> Macros.
Zamiast wklejać powyższy kod w konsoli Python, lepiej zapiszmy go gdzieś, abyśmy mogli go później ponownie wykorzystać i zmodyfikować. Na przykład w postaci nowej makrodefinicji ''(menu Przybory Makrodefinicje Utwórz)''. Nazwij je na przykład "ParamRectangle". Jednak makra FreeCAD zapisywane z rozszerzeniem .FCMacro, którego Python nie rozpoznaje podczas importowania . Tak więc, przed użyciem powyższego kodu, będziemy musieli zmienić nazwę pliku ParamRectangle.FCMacro na ParamRectangle.py. Można to zrobić z poziomu eksploratora plików, przechodząc do folderu Macros wskazanego w menu Przybory Makrodefinicje.


Once that is done, we can now do this in the Python Console:
Gdy to zrobimy, możemy teraz zrobić to w konsoli Python:


{{Code|code=
{{Code|code=
Line 96: Line 101:
}}
}}


By exploring the contents of ParamRectangle, we can verify that it contains our ParametricRectangle class.
Badając zawartość ParamRectangle, możemy sprawdzić, czy zawiera ona naszą klasę ParametricRectangle.


Aby utworzyć nowy obiekt parametryczny przy użyciu naszej klasy ParametricRectangle, użyjemy następującego kodu. Zauważ, że używamy Part::FeaturePython zamiast Part::Feature, którego używaliśmy w poprzednich rozdziałach ''(wersja Python pozwala na zdefiniowanie własnego zachowania parametrycznego)'':
To create a new parametric object using our ParametricRectangle class, we will use the following code. Observe that we use Part::FeaturePython instead of Part::Feature that we have been using in the previous chapters (The Python version allows to define our own parametric behaviour):


{{Code|code=
{{Code|code=
Line 107: Line 112:
}}
}}


Nic nie pojawi się jeszcze na ekranie, ponieważ właściwości Długość i Szerokość mają wartość 0, co spowoduje uruchomienie naszego warunku "do-nothing" wewnątrz execute. Musimy tylko zmienić wartości Długość i Szerokość, a nasz obiekt w magiczny sposób pojawi się i zostanie ponownie przeliczony w locie.
Nothing will appear on screen just yet, because the Length and Width properties are 0, which will trigger our "do-nothing" condition inside execute. We just need to change the values of Length and Width, and our object will magically appear and be recalculated on-the-fly.


Of course it would be tedious to have to type these 4 lines of Python code each time we want to create a new parametric rectangle. A very simple way to solve this is placing the 4 lines above inside our ParamRectangle.py file, at the end, after the end of the ParametricRectange class (We can do this from the Macro editor).
Oczywiście uciążliwe byłoby wpisywanie tych 4 linijek kodu Python za każdym razem, gdy chcemy utworzyć nowy parametryczny prostokąt. Bardzo prostym sposobem na rozwiązanie tego problemu jest umieszczenie powyższych 4 linijek wewnątrz naszego pliku ParamRectangle.py, na końcu, po zakończeniu klasy ParametricRectange ''(możemy to zrobić z poziomu edytora makrodefinicji)''.


Now, when we type import ParamRectangle , a new parametric rectangle will automatically be created. Even better, we can add a toolbar button that will do just that:
Teraz, gdy wpiszemy import ParamRectangle , automatycznie zostanie utworzony nowy prostokąt parametryczny. Co więcej, możemy dodać przycisk na pasku narzędzi, który właśnie to zrobi:


* Open menu '''Tools -> Customize'''
* Otwórz menu '''Przybory Dostosuj'''
* Under the "Macros" tab, select our ParamRectangle.py macro, fill in the details as you wish, and press "Add":
* W zakładce "Makra" wybierz nasze makro ParamRectangle.py, wypełnij szczegóły według własnego uznania i naciśnij "Dodaj":
[[Image:Exercise_python_04.jpg]]
[[Image:Exercise_python_04.jpg]]


* W zakładce Paski narzędzi utwórz nowy niestandardowy pasek narzędzi w wybranym środowisku pracy ''(lub globalnie)'', wybierz makrodefinicję i dodaj je do paska narzędzi:
* Under the Toolbars tab, create a new custom toolbar in the workbench of your choice (or globally), select your macro and add it to the toolbar:


[[Image:Exercise_python_05.jpg]]
[[Image:Exercise_python_05.jpg]]


* To wszystko, mamy teraz nowy przycisk paska narzędzi, który po kliknięciu utworzy parametryczny prostokąt.
* That's it, we now have a new toolbar button which, when clicked, will create a parametric rectangle.


Pamiętaj, że jeśli chcesz rozpowszechniać pliki utworzone za pomocą tego nowego narzędzia innym osobom, muszą one również mieć zainstalowaną makrodefinicję ParamRectangle.py na swoim komputerze.
Remember, if you want to distribute files created with this new tool to other people, they must have the ParamRectangle.py macro installed on their computer too.


'''Read more'''
'''Więcej informacji:'''


* [[Macros_recipes|The FreeCAD macros repository]]
* [[Macros_recipes/pl|Przepisy na makropolecenia]]
* [[Scripted_objects|Parametric object example]]
* [[Scripted_objects/pl|Obiekty tworzone skryptami]]
* [https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/TemplatePyMod/FeaturePython.py More examples in the FreeCAD code]
* [https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/TemplatePyMod/FeaturePython.py Więcej przykładów kodu FreeCAD]



{{Docnav|[[Manual:Creating and manipulating geometry|Creating and manipulating geometry]]|[[Manual:Creating interface tools|Creating interface tools]]|[[Manual:Introduction|Manual start]]|IconC=Crystal Clear manual.png}}
{{Docnav/pl
|[[Manual:Creating and manipulating geometry/pl|Tworzenie i obróbka geometrii]]
|[[Manual:Creating interface tools/pl|Tworzenie narzędzi interfejsu]]
|[[Manual:Introduction/pl|Podręcznik:Słowo wstępne]]
|IconC=Crystal Clear manual.png
}}


{{Powerdocnavi{{#translation:}}}}
{{Powerdocnavi{{#translation:}}}}

Latest revision as of 13:04, 6 March 2024

W rozdziale Tworzenie i obróbka geometrii widzieliśmy, jak tworzyć geometrię części i jak wyświetlać ją na ekranie, dołączając ją do "pospolitego" (nieparametrycznego) obiektu dokumentu. Jest to uciążliwe, gdy chcemy zmienić kształt tego obiektu. Musielibyśmy utworzyć nowy kształt, a następnie ponownie przypisać go do naszego obiektu.

Jednak we wszystkich poprzednich rozdziałach tego podręcznika widzieliśmy również, jak potężne są obiekty parametryczne. Wystarczy zmienić tylko jedną właściwość, a kształt zostanie przeliczony w locie.

Wewnętrznie obiekty parametryczne nie robią nic innego niż przed chwilą: Ponownie obliczają zawartość swojej właściwości Kształt, w kółko, za każdym razem, gdy zmieni się inna właściwość.

FreeCAD zapewnia bardzo wygodny system do budowania takich w pełni parametrycznych obiektów w Pythonie. Składają się one z prostej klasy Python, która definiuje wszystkie właściwości potrzebne obiektowi i co się stanie, gdy jedna z tych właściwości ulegnie zmianie. Struktura takiego obiektu parametrycznego jest bardzo prosta:

class myParametricObject:

    def __init__(self, obj):
        obj.Proxy = self
        obj.addProperty("App::PropertyFloat", "MyLength")
        ...

    def execute(self,obj):
        print ("Recalculating the shape...")
        print ("The value of MyLength is:")
        print (obj.MyLength)
        ...

Wszystkie klasy Pythona zazwyczaj posiadają metodę __init__. To, co znajduje się wewnątrz tej metody, jest wykonywane, gdy klasa jest instancjonowana (co oznacza, w slangu programistycznym, że obiekt Pythona jest tworzony z tej klasy. Potraktuj klasę jako "szablon" do tworzenia jej żywych kopii). W naszej funkcji __init__ robimy dwie ważne rzeczy:
1- przechowujemy naszą klasę w atrybucie "Proxy" naszego obiektu dokumentu FreeCAD, co oznacza, że obiekt dokumentu FreeCAD będzie przenosił ten kod wewnątrz siebie, oraz
2- tworzymy wszystkie właściwości, których potrzebuje nasz obiekt. Dostępnych jest wiele rodzajów właściwości, pełną listę można uzyskać, wpisując ten kod:

FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "dummy").supportedProperties()

Drugą ważną częścią jest metoda execute. Każdy kod w tej metodzie zostanie wykonany, gdy obiekt zostanie oznaczony do ponownego obliczenia, co nastąpi, gdy właściwość zostanie zmieniona. To już wszystko. Wewnątrz execute musisz zrobić wszystko, co trzeba, czyli obliczyć nowy kształt i przypisać go do samego obiektu za pomocą czegoś takiego jak obj.Shape = myNewShape. Dlatego właśnie metoda execute przyjmuje argument "obj", który będzie samym obiektem dokumentu FreeCAD, dzięki czemu możemy nim manipulować wewnątrz naszego kodu Python.

Ostatnia rzecz jest ważna do zapamiętania: Podczas tworzenia takich obiektów parametrycznych w dokumencie FreeCAD, po zapisaniu pliku, powyższy kod Python nie jest przechowywany wewnątrz pliku. Wynika to ze względów bezpieczeństwa, gdyby plik FreeCAD zawierał kod, ktoś mógłby rozpowszechniać pliki FreeCAD zawierające złośliwy kod, który mógłby uszkodzić komputery innych osób. Tak więc, jeśli dystrybuujesz plik, który zawiera obiekty wykonane przy użyciu powyższego kodu, taki kod musi być również obecny na komputerze, który otworzy plik. Najłatwiejszym sposobem na osiągnięcie tego jest zazwyczaj zapisanie powyższego kodu w makrze i rozpowszechnianie makra wraz z plikiem FreeCAD lub udostępnienie makra na Repozytorium makr FreeCAD, skąd każdy może je pobrać.

Poniżej wykonamy małe ćwiczenie, budując obiekt parametryczny, który jest prostą parametryczną prostokątną powierzchnią. Bardziej złożone przykłady są dostępne na stronie Obiekty tworzone skryptami oraz w samym kodzie źródłowym FreeCAD.

Nadamy naszemu obiektowi dwie właściwości: Długość i Szerokość, które wykorzystamy do skonstruowania prostokąta. Następnie, ponieważ nasz obiekt będzie już miał wstępnie zbudowaną właściwość Umiejscowienie (wszystkie obiekty geometryczne mają ją domyślnie, nie trzeba jej dodawać samodzielnie), przesuniemy nasz prostokąt do lokalizacji / obrotu ustawionego w Placement, dzięki czemu użytkownik będzie mógł przenieść prostokąt w dowolne miejsce, edytując właściwość Umiejscowienie.

class ParametricRectangle:

    def __init__(self,obj):
        obj.Proxy = self
        obj.addProperty("App::PropertyFloat", "Length")
        obj.addProperty("App::PropertyFloat", "Width")

    def execute(self, obj):
        # We need to import the FreeCAD module here too, because we might be running out of the Console
        # (in a macro, for example) where the FreeCAD module has not been imported automatically:
        import FreeCAD
        import Part

        # First we need to make sure the values of Length and Width are not 0
        # otherwise Part.LineSegment will complain that both points are equal:
        if (obj.Length == 0) or (obj.Width == 0):
            # If yes, exit this method without doing anything:
            return

        # We create 4 points for the 4 corners:
        v1 = FreeCAD.Vector(0, 0, 0)
        v2 = FreeCAD.Vector(obj.Length, 0, 0)
        v3 = FreeCAD.Vector(obj.Length,obj.Width, 0)
        v4 = FreeCAD.Vector(0, obj.Width, 0)

        # We create 4 edges:
        e1 = Part.LineSegment(v1, v2).toShape()
        e2 = Part.LineSegment(v2, v3).toShape()
        e3 = Part.LineSegment(v3, v4).toShape()
        e4 = Part.LineSegment(v4, v1).toShape()

        # We create a wire:
        w = Part.Wire([e1, e2, e3, e4])

        # We create a face:
        f = Part.Face(w)

        # All shapes have a Placement too. We give our shape the value of the placement
        # set by the user. This will move/rotate the face automatically.
        f.Placement = obj.Placement

        # All done, we can attribute our shape to the object!
        obj.Shape = f

Zamiast wklejać powyższy kod w konsoli Python, lepiej zapiszmy go gdzieś, abyśmy mogli go później ponownie wykorzystać i zmodyfikować. Na przykład w postaci nowej makrodefinicji (menu Przybory → Makrodefinicje → Utwórz). Nazwij je na przykład "ParamRectangle". Jednak makra FreeCAD są zapisywane z rozszerzeniem .FCMacro, którego Python nie rozpoznaje podczas importowania . Tak więc, przed użyciem powyższego kodu, będziemy musieli zmienić nazwę pliku ParamRectangle.FCMacro na ParamRectangle.py. Można to zrobić z poziomu eksploratora plików, przechodząc do folderu Macros wskazanego w menu Przybory → Makrodefinicje.

Gdy to zrobimy, możemy teraz zrobić to w konsoli Python:

import ParamRectangle

Badając zawartość ParamRectangle, możemy sprawdzić, czy zawiera ona naszą klasę ParametricRectangle.

Aby utworzyć nowy obiekt parametryczny przy użyciu naszej klasy ParametricRectangle, użyjemy następującego kodu. Zauważ, że używamy Part::FeaturePython zamiast Part::Feature, którego używaliśmy w poprzednich rozdziałach (wersja Python pozwala na zdefiniowanie własnego zachowania parametrycznego):

myObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Rectangle")
ParamRectangle.ParametricRectangle(myObj)
myObj.ViewObject.Proxy = 0 # This is mandatory unless we code the ViewProvider too.
FreeCAD.ActiveDocument.recompute()

Nic nie pojawi się jeszcze na ekranie, ponieważ właściwości Długość i Szerokość mają wartość 0, co spowoduje uruchomienie naszego warunku "do-nothing" wewnątrz execute. Musimy tylko zmienić wartości Długość i Szerokość, a nasz obiekt w magiczny sposób pojawi się i zostanie ponownie przeliczony w locie.

Oczywiście uciążliwe byłoby wpisywanie tych 4 linijek kodu Python za każdym razem, gdy chcemy utworzyć nowy parametryczny prostokąt. Bardzo prostym sposobem na rozwiązanie tego problemu jest umieszczenie powyższych 4 linijek wewnątrz naszego pliku ParamRectangle.py, na końcu, po zakończeniu klasy ParametricRectange (możemy to zrobić z poziomu edytora makrodefinicji).

Teraz, gdy wpiszemy import ParamRectangle , automatycznie zostanie utworzony nowy prostokąt parametryczny. Co więcej, możemy dodać przycisk na pasku narzędzi, który właśnie to zrobi:

  • Otwórz menu Przybory → Dostosuj
  • W zakładce "Makra" wybierz nasze makro ParamRectangle.py, wypełnij szczegóły według własnego uznania i naciśnij "Dodaj":

  • W zakładce Paski narzędzi utwórz nowy niestandardowy pasek narzędzi w wybranym środowisku pracy (lub globalnie), wybierz makrodefinicję i dodaj je do paska narzędzi:

  • To wszystko, mamy teraz nowy przycisk paska narzędzi, który po kliknięciu utworzy parametryczny prostokąt.

Pamiętaj, że jeśli chcesz rozpowszechniać pliki utworzone za pomocą tego nowego narzędzia innym osobom, muszą one również mieć zainstalowaną makrodefinicję ParamRectangle.py na swoim komputerze.

Więcej informacji: