{"id":17,"date":"2018-04-19T06:00:36","date_gmt":"2018-04-19T04:00:36","guid":{"rendered":"http:\/\/217.182.75.69\/blog_under_construction\/?p=17"},"modified":"2022-10-19T15:40:06","modified_gmt":"2022-10-19T13:40:06","slug":"java-fx","status":"publish","type":"post","link":"https:\/\/blog.michalch.pl\/index.php\/2018\/04\/19\/java-fx\/","title":{"rendered":"Java FX"},"content":{"rendered":"<p><em>Mo\u017cesz skomentowa\u0107 ten wpis w serwisach spo\u0142eczno\u015bciowych: Linkedin (<a href=\"https:\/\/www.linkedin.com\/posts\/michalch-pl_java-fx-activity-6988493064331792384-WKVK\">przejd\u017a<\/a>) lub Facebook (<a href=\"https:\/\/www.facebook.com\/michalchpl\/posts\/pfbid0f26Vhbm6CvcSuxrYVJbU35VUCmsRsTKyAMeTS1f9Xg4ShqemmK9ce1rCeAkRwuMYl\">przejd\u017a<\/a>).<\/em><\/p>\n<p>JavaFX obrazuje mo\u017ce nieco mniej popularne dzi\u015b wykorzystanie j\u0119zyka Java. Jest bibliotek\u0105 s\u0142u\u017c\u0105c\u0105 do tworzenia aplikacji okienkowych. Ma ona zast\u0105pi\u0107 bibliotek\u0105 Swing, kt\u00f3rej pierwsz\u0105 wersj\u0119 opracowano jeszcze w drugiej po\u0142owie lat 90. Swing by\u0142 krytykowany cho\u0107by za to, i\u017c \u015brodowiska developerskie (IDE) generowa\u0142y spor\u0105 cz\u0119\u015b\u0107 kodu, niezb\u0119dn\u0105 do dzia\u0142ania aplikacji. O ile dobrze pami\u0119tam, np. w Netbeans jego edycja by\u0142a wr\u0119cz zablokowana.<\/p>\n<p>JavaFX jest niew\u0105tpliwie nowsz\u0105 technologi\u0105, bazuj\u0105c\u0105 na do\u015bwiadczeniach technologii front-endowych. Pliki widoku s\u0105 zbudowane w formie przypominaj\u0105cej HTML. Mo\u017cliwe jest te\u017c u\u017cywanie CSS w celu poprawienia efekt\u00f3w wizualnych, cho\u0107 nie jest to konieczne.<\/p>\n<p>Postanowi\u0142em wypr\u00f3bowa\u0107 t\u0119 technologi\u0119 i zobaczy\u0107, &#8222;z czym to si\u0119 je&#8221;.<\/p>\n<p><!--more--><\/p>\n<p><span style=\"font-size: 1.5em;\">Prezentacja najciekawszych element\u00f3w technologii<\/span><\/p>\n<p>Rozpoczn\u0119 od tego, w jaki spos\u00f3b przygotowujemy warstw\u0119 widoku (okienka) i jak kontrolki s\u0105 powi\u0105zane z kodem \u017ar\u00f3d\u0142owym aplikacji, tj. jak oprogramujemy np. reakcj\u0119 na klikni\u0119cie przycisku. Najprostszym sposobem zobrazowania, co ma si\u0119 znajdowa\u0107 w oknie naszej aplikacji, jest wykorzystanie plik\u00f3w FXML.<br \/>\nPrzyk\u0142adowe okienko w aplikacji JAVA FX (logowanie do systemu) mo\u017ce wygl\u0105da\u0107 tak:<\/p>\n<p><img loading=\"lazy\" class=\"alignnone size-medium wp-image-19\" src=\"http:\/\/blog.michalch.pl\/wp-content\/uploads\/2018\/04\/okienko-logowania-300x202.jpg\" alt=\"\" width=\"300\" height=\"202\" srcset=\"https:\/\/blog.michalch.pl\/wp-content\/uploads\/2018\/04\/okienko-logowania-300x202.jpg 300w, https:\/\/blog.michalch.pl\/wp-content\/uploads\/2018\/04\/okienko-logowania.jpg 303w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>A oto, jak b\u0119dzie wygl\u0105da\u0142 plik FXML:<\/p>\n<pre>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n\n&lt;?import javafx.geometry.Insets?&gt;\n&lt;?import javafx.scene.control.Button?&gt;\n&lt;?import javafx.scene.control.Label?&gt;\n&lt;?import javafx.scene.control.PasswordField?&gt;\n&lt;?import javafx.scene.control.TextField?&gt;\n&lt;?import javafx.scene.control.ScrollPane?&gt;\n&lt;?import javafx.scene.layout.AnchorPane?&gt;\n&lt;?import javafx.scene.layout.GridPane?&gt;\n\n&lt;AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" xmlns=\"http:\/\/javafx.com\/javafx\/8.0.111\" xmlns:fx=\"http:\/\/javafx.com\/fxml\/1\" fx:controller=\"main.java.controllers.LoginController\"&gt;\n   &lt;ScrollPane AnchorPane.bottomAnchor=\"0\" AnchorPane.leftAnchor=\"0\" AnchorPane.rightAnchor=\"0\" AnchorPane.topAnchor=\"0\"&gt;\n      &lt;GridPane alignment=\"CENTER\" hgap=\"5\" vgap=\"5\"&gt;\n         &lt;padding&gt;\n            &lt;Insets top=\"20\" right=\"20\" bottom=\"20\" left=\"20\" \/&gt;\n         &lt;\/padding&gt;\n         &lt;children&gt;\n            &lt;Label text=\"Nazwa u\u017cytkownika\" GridPane.columnIndex=\"0\" GridPane.rowIndex=\"0\" GridPane.halignment=\"RIGHT\" \/&gt;\n            &lt;TextField fx:id=\"usernameField\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"0\" \/&gt;\n            &lt;Label text=\"Has\u0142o\" GridPane.columnIndex=\"0\" GridPane.rowIndex=\"1\" GridPane.halignment=\"RIGHT\" \/&gt;\n            &lt;PasswordField fx:id=\"passwordField\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"1\" \/&gt;\n            &lt;Button text=\"Zaloguj\" onAction=\"#loginBtnClick\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"2\" GridPane.rowSpan=\"15\" \/&gt;\n         &lt;\/children&gt;\n      &lt;\/GridPane&gt;\n   &lt;\/ScrollPane&gt;\n&lt;\/AnchorPane&gt;<\/pre>\n<p>Ka\u017cdy, kto pozna\u0142 cho\u0107by podstawy tworzenia stron WWW od kuchni, rozpozna podobie\u0144stwo do j\u0119zyka HTML. \u015aci\u015blej rzecz bior\u0105c, FXML zosta\u0142 napisany w j\u0119zyku XML, j\u0119zyku pozwalaj\u0105cym zapisa\u0107 dowolne informacje (wi\u0119cej o XML: http:\/\/webmaster.helion.pl\/starocie\/xml\/xml.htm), na co wskazuje pierwsza liniijka: &lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;.<br \/>\nDalej mamy list\u0119 klas u\u017cywanych w tym okienku, g\u0142\u00f3wnie reprezentacje kontrolek. Tu akurat mo\u017cna doszuka\u0107 si\u0119 podobie\u0144stwa do samej Javy &#8211; jedyn\u0105 r\u00f3\u017cnic\u0105 s\u0105 znaczniki &lt;? i ?&gt; otaczaj\u0105ce ka\u017cdy import.<br \/>\nTrzeci\u0105 i najwa\u017cniejsz\u0105 cz\u0119\u015bci\u0105 FXMLa jest struktura okna. W pierwszym elemencie musimy wskaza\u0107 przestrzenie nazw, aby kompilator potrafi\u0142 rozpozna\u0107 co kryje si\u0119 pod nazwami znacznik\u00f3w i atrybut\u00f3w. Za to w\u0142a\u015bnie odpowiadaj\u0105 dyrektywy xmlns i xmlns:fx. Nie mo\u017cemy tak\u017ce pomin\u0105\u0107 atrybutu fx:controller. Wskazuje on na klas\u0119 Javy, kt\u00f3ra jest kontrolerem naszego okna. JavaFX bazuje bowiem na wzorcu projektowym Model &#8211; View &#8211; Controller. W tej w\u0142a\u015bnie klasie znajd\u0105 si\u0119 metody odpowiadaj\u0105ce za reakcj\u0119 na zdarzenia wykonywane w oknie (kilkni\u0119cie mysz\u0105 w odpowiedni przycisk, zmiana tekstu w formatce itp.). Pozosta\u0142e atrybuty (maxHeight, maxWidth, minHeight i minWidth) odnosz\u0105 si\u0119 ju\u017c do rozmiaru okna i w moim przypadku zosta\u0142y wygenerowane automatycznie.<\/p>\n<p>My\u015bl\u0119, \u017ce w tym miejscu warto wspomnie\u0107 o rodzajach kontrolek w JavaFX. Ka\u017cdy przecie\u017c mo\u017ce je dobiera\u0107 we w\u0142asnym zakresie i nie musi si\u0119 sugerowa\u0107 moim wyborem.<\/p>\n<p><span style=\"font-size: 19px;\">a) Kontenery, czyli elementy grupuj\u0105ce.<\/span><br \/>\nPane &#8211; najprostszy spo\u015br\u00f3d kontener\u00f3w. Aby umie\u015bci\u0107 w nim inne elementy, musimy &#8222;na sztywno&#8221; zdefiniowa\u0107 miejsce, w kt\u00f3rym si\u0119 pojawi\u0105, definiuj\u0105c wsp\u00f3\u0142rz\u0119dne X i Y. Raczej nie do zastosowania w sytuacji, kiedy nie wiemy, jak\u0105 rozdzielczo\u015b\u0107 ekranu ma u\u017cytkownik, nie m\u00f3wi\u0105c ju\u017c o przypadku, gdy zawarto\u015b\u0107 okienka zmienia si\u0119 w trakcie dzia\u0142ania aplikacji (\u017ceby co\u015b przesun\u0105\u0107, musieliby\u015bmy przelicza\u0107 wsp\u00f3\u0142rz\u0119dne).<br \/>\nVBox i HBox &#8211; kontenery te uk\u0142adaj\u0105 kolejno poszczeg\u00f3lne elementy, przy czym VBox robi to wierszami (jeden pod drugim), za\u015b HBox kolumnami (obok siebie). Mo\u017cna zdefiniowa\u0107 odst\u0119p w pikselach jaki ma by\u0107 mi\u0119dzy kolejnymi elementami (atrybut spacing). Domy\u015blnie nie ma odst\u0119pu.<br \/>\nNajbardziej u\u017cyteczne s\u0105 w sytuacji, kiedy mamy list\u0119 jakich\u015b element\u00f3w i dla ka\u017cdego z nich chcemy zdefiniowa\u0107 okre\u015blone kontrolki, na przyk\u0142ad lista u\u017cytkownik\u00f3w kursu, z kt\u00f3rych dla ka\u017cdego chcemy mie\u0107 etykietk\u0119 z imieniem i nazwiskiem oraz przyciski &#8222;Usu\u0144&#8221;, czy &#8222;Zmie\u0144 grup\u0119&#8221;. Ca\u0142\u0105 list\u0119 zgrupowa\u0142em w VBox-ie, a dla ka\u017cdego elementu robi\u0142em HBox, kt\u00f3ry umieszcza\u0142 w jednym wierszu kontrolk\u0119 Label i dwie kontrolki Button.<br \/>\nStackPane &#8211; kontener uk\u0142ada elementy jeden nad drugim (stos). Jedynym zastosowaniem, jakie przysz\u0142o mi do g\u0142owy, jest rysowanie element\u00f3w jak na przyk\u0142adzie tutaj: https:\/\/www.tutorialspoint.com\/javafx\/layout_stackpane.htm . Osobi\u015bcie nie u\u017cywa\u0142em.<br \/>\nBorderPane &#8211; uk\u0142adanie element\u00f3w w okre\u015blonych cz\u0119\u015bciach okna, dost\u0119pne pozycje to: Top, Left, Right, Bottom i Center. Niew\u0105tpliwie przydatne, cho\u0107 b\u0119dziemy potrzebowali je zagnie\u017cd\u017ca\u0107 z innymi kontenerami albo z innymi instancjami BorderPane.<br \/>\nGridPane &#8211; ustawia elementy tak jakby w tabeli. Ka\u017cdy element b\u0119d\u0105cy wewn\u0105trz GridPane powinien mie\u0107 zdefiniowany wiersz i kolumn\u0119 w jakiej ma zosta\u0107 zlokalizowany. Mo\u017cna wi\u0119c go u\u017cy\u0107 zamiennie z BorderPane.<br \/>\nAnchorPane &#8211; elementy wewn\u0105trz niego s\u0105 bezpo\u015brednio &#8222;przyklejone&#8221; do elementu rodzica, z zachowaniem z g\u00f3ry zdefinowanych odst\u0119p\u00f3w.<br \/>\nDost\u0119pne s\u0105 r\u00f3wnie\u017c inne kontenery takie jak: TilePane czy FlowPane.<\/p>\n<p><span style=\"font-size: 19px;\">b) Inne elementy.<\/span><br \/>\nGeneralnie JavaFX udost\u0119pnia zestaw standardowych kontrolek jak np. etykieta tekstowa (Label), pole tekstowe (TextField), elementy wyboru jednokrotnego (RadioButton) lub wielokrotnego (CheckBox) lista rozwijana (ChoiceBox), przycisk (Button), czy te\u017c pasek menu (Menu i MenuItem). S\u0105 te\u017c mniej oczywiste, jak np. edytor tekstowy (HTMLEditor) czy \u0142\u0105cze (Hyperlink). Mo\u017cemy te\u017c rysowa\u0107 r\u00f3\u017cne figury geometryczne.<\/p>\n<p>Je\u015bli samodzielne edytowanie pliku FXML jest dla programisty zbyt skomplikowane lub czasoch\u0142onne, mo\u017ce nam pom\u00f3c program Scene Builder (http:\/\/gluonhq.com\/products\/scene-builder\/). Umo\u017cliwia on tworzenie GUI w formie wizualnej (WYSIWYG: What You See Is What You Get) i sam przetwarza wyniki naszej pracy na tekstowy plik FXML. Istnieje mo\u017cliwo\u015b\u0107 jego integracji z IDE przynajmniej w wypadku IntelliJ (innych nie pr\u00f3bowa\u0142em).<\/p>\n<p>W FXML mo\u017cemy te\u017c definiowa\u0107 widoki cz\u0119\u015bciowe, w postaci kontenera zawieraj\u0105cego kontrolki, kt\u00f3re maj\u0105 si\u0119 pojawi\u0107 na ekranie w wyniku dzia\u0142ania jakiej\u015b operacji, w bie\u017c\u0105cym oknie.<\/p>\n<p>Warto te\u017c doda\u0107, \u017ce wszystkie kontenery i kontrolki mo\u017cemy oczywi\u015bcie definiowa\u0107 bezpo\u015brednio w kodzie Javy, w klasie kontrolera.<\/p>\n<p><span style=\"font-size: 1.5em;\">Zdarzenia i ich realizacja.<\/span><\/p>\n<p>Je\u015bli chcemy je zdefiniowa\u0107 w FXML, powinni\u015bmy przy kontrolce, kt\u00f3rej zdarzenie ma dotyczy\u0107, dopisa\u0107 atrybut onAction, onMouseClicked, itp. zale\u017cnie od zdarzenia, kt\u00f3rego obs\u0142ug\u0119 chcieliby\u015bmy zdefiniowa\u0107. Jako warto\u015b\u0107 atrybutu wpisujemy nazw\u0119 metody w kontrolerze, poprzedzon\u0105 znakiem #. Uwaga, metoda powinna przyjmowa\u0107 jako jedyny argument obiekt typu ActionEvent lub jego obiekt pochodny w zale\u017cno\u015bci od rodzaju zdarzenia. Powinni\u015bmy tak\u017ce oznaczy\u0107 metod\u0119 annotacj\u0105 @FXML, jak r\u00f3wnie\u017c przypisa\u0107 identyfikator do elementu w FXML oraz umie\u015bci\u0107 instancj\u0119 kontrolki jako pole w klasie kontrolera o tej samej nazwie co identyfikator w FXML, jak r\u00f3wnie\u017c opisa\u0107 te pole tak\u017ce annotacj\u0105 @FXML.<\/p>\n<p>Z kolei w przypadku przypisywania akcji w kodzie Javy, z du\u017c\u0105 pomoc\u0105 przychodzi nam Java 8. Gdyby nie wprowadzona w niej mo\u017cliwo\u015b\u0107 przypisywania metody za pomoc\u0105 podw\u00f3jnego dwukropka: control.setOnAction(this::methodName), to dynamiczne wi\u0105zanie reakcji na zdarzenia by\u0142oby mocno utrudnione. Mo\u017cemy r\u00f3wnie\u017c skorzysta\u0107 z interfejsu lambda, np: control.setOnAction(e -&gt; doSomething(parameter1, parameter2)).<\/p>\n<p><span style=\"font-size: 1.5em;\">Mankamenty<\/span><\/p>\n<p>Jest utrudnione bindowanie, czyli wi\u0105zanie warto\u015bci kontrolki ze polem w kontrolerze w niekt\u00f3rych kontrolkach (co czynimy zwykle aby \u0142atwiej odczytywa\u0107 zaznaczony element). Dotyczy to na przyk\u0142ad listy rozwijanej.<br \/>\n\u0179le rozwi\u0105zano sytuacj\u0119, w kt\u00f3rej &#8211; iteruj\u0105c po warto\u015bciach jakiej\u015b listy &#8211; wy\u015bwietlam list\u0119 element\u00f3w tej listy i chc\u0119 mie\u0107 przycisk, kt\u00f3ry co\u015b robi. Chcia\u0142bym \u017ceby wywo\u0142ywa\u0142 metod\u0119 z parametrem wskazuj\u0105cym na identyfikator tego\u017c elementu. Nic z tego, bo wyskoczy: &#8222;variable used in lambda expression should be final or effectively final&#8221;. W AngularJS bez problemu robi\u0142em co\u015b podobnego. Tutaj musia\u0142em si\u0119 uciec do stworzenia kontrolki rozszerzaj\u0105cej kontrolk\u0119 &#8222;Button&#8221; i zawieraj\u0105cej pole typu String na identyfikator. Do tego jeszcze w metodzie obs\u0142uguj\u0105cej zdarzenie musia\u0142em robi\u0107 ma\u0142o estetyczne rzutowanie.<\/p>\n<p>Poni\u017cej kr\u00f3tkie wprowadzenie bardziej techniczne.<\/p>\n<p>Ka\u017cdy, kto ju\u017c pisa\u0142 program w j\u0119zyku Java wie, \u017ce w g\u0142\u00f3wnej klasie naszej aplikacji powinna znale\u017a\u0107 si\u0119 metoda:<\/p>\n<pre style=\"font-size: 12px; font-style: italic;\">public static void main(String[] args) {\n    \/\/ ...\n}<\/pre>\n<p>T\u0119 metod\u0119 uruchamia maszyna wirtualna \u015brodowiska i wykonuje zawarte w niej instrukcje.<\/p>\n<p>JavaFX zastosowa\u0142o klas\u0119 abstrakcyjn\u0105 Application z pakietu javafx.application, kt\u00f3re odpowiada za rozruch naszego programu.<br \/>\nZadaniem programisty jest:<br \/>\na) Poinformowanie kompilatora, \u017ce nasza klasa rozszerza klas\u0119 Application.<br \/>\nb) Umieszczenie w metodzie main() instrukcji launch(args). Metoda &#8222;launch&#8221; zosta\u0142a zaimplementowana w klasie Application i nie musimy si\u0119 ni\u0105 zajmowa\u0107.<br \/>\nc) Umieszczenie oraz implementacja w naszej klasie metody &#8222;start&#8221;:<\/p>\n<pre style=\"font-size: 12px; font-style: italic;\">public void start(Stage primaryStage) throws Exception {\n    \/\/ ...\n}<\/pre>\n<p>To w\u0142a\u015bnie od tego miejsca b\u0119dziemy definiowa\u0107 wy\u015bwietlanie naszych okien i wszystkiego, co b\u0119dzie si\u0119 dzia\u0142o w naszym programie.<\/p>\n<p>Dla niezorientowanych, poni\u017cej szkielet bazowej klasy:<\/p>\n<pre style=\"font-size: 12px; font-style: italic;\">package {nazwa naszego pakietu};\n\nimport javafx.application.Application;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    public static void main(String[] args) {\n        launch(args);\n    }\n\n    public void start(Stage primaryStage) throws Exception {\n        \/\/ implementacja aplikacji\n    }\n\n}<\/pre>\n<p>Klasa Stage, kt\u00f3rej instancja jest argumentem wej\u015bciowym funkcji start() to, w uproszczeniu, reprezentacja okna naszej aplikacji.<\/p>\n<p>Po bardziej szczeg\u00f3\u0142owy tutorial techniczny proponuj\u0119 przej\u015b\u0107 np. na stron\u0119 <a href=\"https:\/\/www.tutorialspoint.com\/javafx\/\">https:\/\/www.tutorialspoint.com\/javafx\/<\/a> (w j\u0119z. ang.)<\/p>\n<p><em>Mo\u017cesz skomentowa\u0107 ten wpis w serwisach spo\u0142eczno\u015bciowych: Linkedin (<a href=\"https:\/\/www.linkedin.com\/posts\/michalch-pl_java-fx-activity-6988493064331792384-WKVK\">przejd\u017a<\/a>) lub Facebook (<a href=\"https:\/\/www.facebook.com\/michalchpl\/posts\/pfbid0f26Vhbm6CvcSuxrYVJbU35VUCmsRsTKyAMeTS1f9Xg4ShqemmK9ce1rCeAkRwuMYl\">przejd\u017a<\/a>).<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mo\u017cesz skomentowa\u0107 ten wpis w serwisach spo\u0142eczno\u015bciowych: Linkedin (przejd\u017a) lub Facebook (przejd\u017a). JavaFX obrazuje mo\u017ce nieco mniej popularne dzi\u015b wykorzystanie j\u0119zyka Java. Jest bibliotek\u0105 s\u0142u\u017c\u0105c\u0105 do tworzenia aplikacji okienkowych. Ma ona zast\u0105pi\u0107 bibliotek\u0105 Swing, kt\u00f3rej pierwsz\u0105 wersj\u0119 opracowano jeszcze w drugiej po\u0142owie lat 90. Swing by\u0142 krytykowany cho\u0107by za to, i\u017c \u015brodowiska developerskie (IDE) generowa\u0142y [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/posts\/17"}],"collection":[{"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/comments?post=17"}],"version-history":[{"count":11,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/posts\/17\/revisions"}],"predecessor-version":[{"id":130,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/posts\/17\/revisions\/130"}],"wp:attachment":[{"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/media?parent=17"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/categories?post=17"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.michalch.pl\/index.php\/wp-json\/wp\/v2\/tags?post=17"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}