{"id":120981,"date":"2024-12-14T09:45:59","date_gmt":"2024-12-14T07:45:59","guid":{"rendered":"https:\/\/prohoster.info\/blog\/novosti-interneta\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git"},"modified":"2024-12-14T09:45:59","modified_gmt":"2024-12-14T07:45:59","slug":"mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 an AST-oriented tool for three-way merging in Git","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>The release of the mergiraf project 0.4 has been published, developing a driver for Git with the implementation of three-way merging capabilities. Mergiraf supports resolving various types of merge conflicts and can be used for different programming languages and file formats. It can either be invoked separately for handling conflicts that arise while working with standard Git or replace the merge handler in Git to extend the functionality of commands such as merge, revert, rebase, and cherry-pick. The code is distributed under the GPLv3 license. The new version adds support for Python, TOML, Scala, and Typescript, as well as performance optimizations.    <\/p>\n<p>Below is a detailed description of the issues addressed by mergiraf:    <\/p>\n<p>Software is a prime example of an extremely complex system. Complex systems share one common feature \u2014 they are COMPLEX \u2014 and you cannot expect that the desired complex behavior will arise by itself, by chance. Instead, these systems evolve over time, step by step, and each mutation is carefully checked at every stage. Achieving this requires a well-defined structure and appropriate tools. The evolution of any complex system can be visualized as a directed tree, where the root represents an empty set of functions, and every node \u2014 except for the root \u2014 is the result of applying a mutation to its parent.     <\/p>\n<p>In the context of products, each node is called a 'version', representing a specific set of functions and anti-functions. Any change to this set is considered a mutation, forming an edge in our directed acyclic graph. These functions are inherently abstract; they do not directly reflect how physical systems operate but rather illustrate how rational agents perceive the usefulness of these systems. To translate ideas into real-world implementations, one must roll up their sleeves and dive into *sufficiently* low-level details, in a language that can express and explain exactly how everything works. In software development, these low-level details are typically represented by source code.    <\/p>\n<p>To gradually bring the source code into a state that exhibits the required behavior and to document how they arrived there, programmers present their work in terms of snapshots and changesets. A snapshot represents a specific state of the product with all low-level details, while a changeset denotes the transition between snapshots. Typically, snapshots are generated from individual changesets to their parents, which is why these snapshots almost always bear the marks of the changesets that created them, making these terms often used interchangeably.     <\/p>\n<p>Sometimes snapshots exist as a result of multiple transitions \u2014 commit merges. These can be difficult to work with, so they are usually avoided. Modern open-source version control systems, such as Git, provide quite basic capabilities for managing development workflows. They allow developers to organize snapshots as directed acyclic graphs, annotate them with comments, and change their order if necessary.     <\/p>\n<p>This functionality allows developers to write a semantically meaningful project history, which is critical for debugging and answering questions like, \"Why was this low-level detail (e.g., variable) introduced?\", \"What percentage is my contribution to this project?\", \"Who was hacked by the backdoor implementation and when?\", \"What low-level change broke this function (even though it shouldn't have, we checked everything!?)\"    <\/p>\n<p>Version control systems complement this with the concept of a branch \u2014 a low-level idea that simply means a continuous fragment of low-level project history, semantically significant for the developer. Branches are typically used for specific feature implementations, sometimes multiple branches are created for different candidates of the same feature implementation. By using branching workflows (which are actually mainstream and the standard of development, used everywhere), each individual developer can effectively manage many conflicting project branches, each differing in readiness or quality. This allows developers to combine the results of their own and others' efforts without having to rewrite everything manually each time.     <\/p>\n<p>Typically, a main branch is created to represent the \"official\" product, from which side branches are made for each feature, which are regularly (ideally \u2014 after each commit) synchronized with the main branch, allowing developers to work with the most up-to-date version of the product while simultaneously incorporating features they are currently developing, detecting issues arising from the actions of other developers as early as possible.    <\/p>\n<p>When trying to combine the functions of various snapshots (which simply means finding a common ancestor and applying the changesets it produces sequentially on top of another, this operation is called rebase; merging, on the other hand, is somewhat like rebase but structures the commit graph differently, making it less convenient to manipulate, which is why merging is usually avoided in favor of rebases), issues arise. Modern version control systems (VCS) use internal algorithms to merge changes that break files down into individual lines, considering each line as a symbol and the files as sequences, and then apply algorithms for their merging that originate from bioinformatics.     <\/p>\n<p>Unfortunately, this line-by-line representation of source code has nothing to do with its content. Its only merit is its simplicity and universality. This mismatch leads to conflicts, being a constant source of headaches for developers. Resolving conflicts requires developers to thoroughly review both versions of the code, not just the portions marked as 'modified' or 'conflicting' by the line-by-line comparison algorithm, but possibly the entire project.     <\/p>\n<p>The developer must understand the changes, manually write the merged code, and eliminate any discrepancies. The number of problems increases significantly when the line-by-line tool misidentifies changes, which often happens during major modifications, including trivial ones like code reformatting. If subsequent changes cannot be applied to the manually merged code, the situation turns into a complete nightmare. Despite the horrific cases, in most instances, the line-by-line algorithm works, especially if developers actively try not to create problems for it. One way to minimize such issues is to require source code to be processed by canonicalization tools, such as black.    <\/p>\n<p>Of course, the right solution for terrifying cases (and generally, not only for them, line-by-line algorithms \u2014 this is a heuristic, and can trivially lead to non-working code. For example, one developer renamed a variable while another wrote new code using that variable. There will be no merge\/rebase conflict, but the result can become non-functional) \u2014 is using the correct internal model.     <\/p>\n<p>Despite the fact that research in this area has been ongoing for about 30 years, leading to the creation of several proprietary commercial products, this research had only recently been transformed into practically applicable products with open source. The majority of FOSS solutions began to develop in the early 2010s and were primarily focused on the Java language.    <\/p>\n<p>The most notable free implementation of that period, GumTree, was created by a researcher with an academic background, written in Java, featuring its own abstract internal representation that precedes treesitter. It has backends that are both based on treesitter and other tools for parsing source code into abstract representations. This system can only generate (in the form of a textual event log, with an API that can be trivially called from any programming language that has bindings to Java) and visualize changes. However, it is not suitable out of the box for merging changes or viewing the generated diff files (though it is likely that loading diffs could be implemented through the API).    <\/p>\n<p>A younger and more practically applicable implementation, difftastic, is written in Rust, based on treesitter, and focuses on generating highlighted diffs in the console. This system aims at visualizing diffs and does not target merging changes or applying patches.    <\/p>\n<p>Recently, the mergiraf project has appeared and is actively developing. This tool, written in Rust (takes up 21 MiB!), is also based on treesitter, which has become just as standard for parsing context-free grammars in development tools as LLVM has for optimizing low-level instruction representations. Unlike its competitors, mergiraf provides features not for generating diffs, but for automatically resolving merge conflicts. Under the hood, mergiraf uses an implementation of the algorithm used in GumTree for generating patches, and for applying \u2014 an implementation of the algorithm used in spork, adapted for treesitter structures.     <\/p>\n<p>Unfortunately, the serialization of patches into files that can later be applied has not been implemented (but it is quite likely that it could be achieved by parsing the event logs generated by GumTree). Another promising way to apply differences could be through LSP servers' refactoring capabilities, which may help in detecting conflicts at the project-wide level. Visualization is only supported for conflicts.    <\/p>\n<p>Example of operation:    common ancestor &#171;base.py&#187; (indents with tabs, extra line at the beginning)       foo = 1       def main():          print(foo + 2 + 3)       &#171;a.py&#187; (tabs still for indenting, 2 extra lines at the beginning instead of one, icecream library used for debugging prints, class &#171;baz&#187; added:       from icecream import ic       foo = 1       def main():          ic(foo + 2 + 3)            class baz:                  def __init__(self):                          &#171;&#187;&#187;baz&#187;&#187;&#187;       &#171;b.py&#187; (variable &#171;foo&#187; renamed to &#171;bar&#187;, processed with &#171;black&#187; after changes, resulting indents \u2014 spaces, and extra lines removed):       bar = 1         def main():         print(bar + 2 + 3)        Calling       .\\\/mergiraf merge .\\\/base.py .\\\/a.py .\\\/b.py -x a.py -y b.py -s base.py -o .\\\/res.py      gives the following result       from icecream import ic       bar = 1         def main():         ic(bar + 2 + 3)           class baz:             def __init__(self):                  &#171;&#187;&#187;baz&#187;&#187;&#187;      (the icecream library was used for debugging prints, the variable &#171;foo&#187; was renamed to &#171;bar&#187;, processed with &#171;black&#187; after changes, resulting in indents as spaces and extra lines removed, a mix of tabs and spaces for indentation, but in an allowed form).    <\/p>\n<p>Here we can see a drawback of the tool. The document style is usually configured in the files &#171;.editorconfig&#187;, and global style changes, such as switching tabs to spaces and adopting the black style, as done in &#171;b.py&#187;, are typically accompanied by changes in &#171;.editorconfig&#187;. Therefore, to more accurately implement such changes, the tool should have a concept for a global style &#171;by default&#187; and be able to pull settings from &#171;.editorconfig&#187;.<br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/www.opennet.ru\/opennews\/art.shtml?num=62402\">opennet.ru<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f. Mergiraf \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0438\u0434\u043e\u0432 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043f\u0440\u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u0438 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 mergiraf \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432, \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043e \u0448\u0442\u0430\u0442\u043d\u044b\u043c Git, \u0442\u0430\u043a \u0438 \u0437\u0430\u043c\u0435\u043d\u0430 \u0432 Git \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0439 \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-120981","post","type-post","status-publish","format-standard","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47mergiraf \u2014 AST-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432 Git | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2024-12-14T07:45:59+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2024-12-14T07:45:59+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47mergiraf \u2014 AST-oriented tool for three-way merging in Git | ProHoster","description":"The release of the mergiraf project 0.4 has been published, developing a Git driver with the implementation of three-way merging capability.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47mergiraf \u2014 AST-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432 Git | ProHoster","og:description":"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.","og:url":"https:\/\/prohoster.info\/en\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2024-12-14T07:45:59+00:00","article:modified_time":"2024-12-14T07:45:59+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"120981","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 08:54:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2026-01-23 08:54:19","updated":"2026-01-23 08:54:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}