{"id":24815,"date":"2018-06-07T01:00:55","date_gmt":"2018-06-06T16:00:55","guid":{"rendered":"https:\/\/jirak.net\/wp\/c-console-uwp-applications\/"},"modified":"2018-06-07T01:34:51","modified_gmt":"2018-06-06T16:34:51","slug":"c-console-uwp-applications","status":"publish","type":"post","link":"https:\/\/jirak.net\/wp\/c-console-uwp-applications\/","title":{"rendered":"C# Console UWP Applications"},"content":{"rendered":"<p>C# Console UWP Applications<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jirak.net\/wp\/wp-content\/uploads\/2018\/06\/94a598fc5167d0f5f199578d8a5436e7.png\" width=\"1122\" height=\"788\"><\/p>\n<p>We\u2019ve just published an update to the Console UWP App project templates on the Visual Studio marketplace\u00a0<strong><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=AndrewWhitechapelMSFT.ConsoleAppUniversal\">here<\/a>.<\/strong> The latest version (v1.5) adds support for C#. The C# template code only works with Visual Studio 2017 version 15.7 or later.\u00a0In\u00a0<a href=\"https:\/\/blogs.windows.com\/buildingapps\/2018\/05\/18\/console-uwp-applications-and-file-system-access\/\">a previous post<\/a>,\u00a0I\u00a0described how to build a simple\u00a0findstr\u00a0UWP app using the C++ Console templates. In this post, we\u2019ll look at how to achieve the same with C#, and call out a few additional wrinkles you should be aware of.<\/p>\n<p>Having installed the updated VSIX, you can now choose a C# Console\u00a0UWP\u00a0App from the New Project dialog:<\/p>\n<p><a href=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/94a598fc5167d0f5f199578d8a5436e7.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-52734\" src=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/94a598fc5167d0f5f199578d8a5436e7.png\" alt=\"choose a C# Console UWP App from the New Project dialog\" width=\"1122\" height=\"788\" \/><\/a><\/p>\n<p><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">N<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">ote that C# console apps are only supported from version 10.0.17134.0 of the platform. You should therefore specify a version &gt;= 10.0.17134 for the\u00a0<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">minimum platform version\u00a0<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">when you create your project.<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">\u00a0If you forget this step, you can\u00a0<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">fix it<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">\u00a0at any time later by manually editing your .<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"SpellingError SCXW85428201\">csproj<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">\u00a0and updating the\u00a0<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"SpellingError SCXW85428201\">TargetPlatformMinVersion<\/span><\/span><span class=\"TextRun SCXW85428201\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW85428201\">\u00a0value.<\/span><\/span><span class=\"EOP SCXW85428201\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/72e149197dac2673ae9225282ed726a3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-52737\" src=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/72e149197dac2673ae9225282ed726a3.png\" alt=\"If you forget this step, you can fix it at any time later by manually editing your .csproj and updating the TargetPlatformMinVersion value. \" width=\"956\" height=\"340\" \/><\/a><\/p>\n<p>Also note that with the C# template, you might get the error message &#8220;<i>Output type &#8216;Console Application&#8217; is not supported by one or more of the project&#8217;s targets.<\/i>&#8221; You can\u00a0safely\u00a0ignore this message\u00a0\u2013 even though it is flagged as an error, it doesn\u2019t actually make any difference to anything and\u00a0doesn\u2019t prevent the project from building correctly.<\/p>\n<p>As with the C++ template, the generated code includes a Main method. One difference you\u2019ll notice with the C# version is that the command-line arguments are passed directly into Main.\u00a0Recall that in the C++ version, you don\u2019t get the arguments into main, but instead\u00a0you\u00a0need to use the global __argc\u00a0and __argv\u00a0variables.\u00a0Notice that you can also now use the\u00a0System.Console\u00a0APIs just as you would in a non-UWP console app.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\">\r\n\r\nstatic void Main(string[] args) \r\n{ \r\n    if (args.Length == 0) \r\n    { \r\n        Console.WriteLine(&amp;quot;Hello - no args&amp;quot;); \r\n    } \r\n    else \r\n    { \r\n        for (int i = 0; i &amp;lt; args.Length; i++) \r\n        { \r\n            Console.WriteLine($&amp;quot;arg[{i}] = {args[i]}&amp;quot;); \r\n        } \r\n    } \r\n    Console.WriteLine(&amp;quot;Press a key to continue: &amp;quot;); \r\n    Console.ReadLine(); \r\n} \r\n\r\n<\/pre>\n<p><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">As\u00a0<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">before,\u00a0<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">for the file-handling behavior needed for the\u00a0<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"SpellingError SCXW134957106\">findstr<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">\u00a0app, you<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">\u00a0need to add the\u00a0<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"SpellingError SCXW134957106\">broadFileSystemAccess<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">\u00a0restricted capability. Adding this will cause your app to get some extra scrutiny when you submit it to the Store<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">. Y<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">ou will need to describe how you int<\/span><\/span><span class=\"TextRun SCXW134957106\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW134957106\">end to use the feature, and show that your usage is reasonable and legitimate.<\/span><\/span><span class=\"EOP SCXW134957106\">\u00a0<\/span><\/p>\n<pre class=\"brush: xml; title: ; notranslate\">\r\n\r\nxmlns:rescap=&amp;quot;http:\/\/schemas.microsoft.com\/appx\/manifest\/foundation\/windows10\/restrictedcapabilities&amp;quot;  \r\n  IgnorableNamespaces=&amp;quot;uap mp uap5 desktop4 iot2 rescap&amp;quot;&amp;gt; \r\n\u2026 \r\n  &amp;lt;Capabilities&amp;gt; \r\n    &amp;lt;Capability Name=&amp;quot;internetClient&amp;quot; \/&amp;gt; \r\n    &amp;lt;rescap:Capability Name=&amp;quot;broadFileSystemAccess&amp;quot; \/&amp;gt; \r\n  &amp;lt;\/Capabilities&amp;gt; \r\n\r\n<\/pre>\n<p>Because the app will\u00a0be doing some simple file handling and pattern matching, in the C++ version,\u00a0I\u00a0had to #include the\u00a0Windows.Storage.h\u00a0and regex, and declare the corresponding namespaces. In C#,\u00a0you\u00a0need the\u00a0equivalent\u00a0Windows.Storage\u00a0and\u00a0System.Text.RegularExpressions\u00a0namespaces.<\/p>\n<p>For the\u00a0findstr\u00a0functionality, recall that I\u2019m expecting a command-line such as \u201cCsFindstr\u00a0foo C:Bar\u201d, where \u201cfoo\u201d is the pattern to search for, and \u201cC:Bar\u201d is the folder location from which to start the recursive search. I can strip out all the generated code in Main, and replace it with firstly a simple test for the\u00a0expected number of\u00a0command-line arguments, and secondly a call to a\u00a0RecurseFolders\u00a0method (which I\u2019ll write in a minute).\u00a0In the C++ version, I tested __argc\u00a0&lt; 3, but in the managed version I need to test the incoming\u00a0args.Length\u00a0for &lt; 2 (the executable module name itself is not included in the C#\u00a0args).<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\">\r\n\r\nstatic void Main(string[] args) \r\n{ \r\n    if (args.Length &amp;lt; 2) \r\n    { \r\n        Console.WriteLine(&amp;quot;Insufficient arguments.&amp;quot;); \r\n        Console.WriteLine(&amp;quot;Usage:&amp;quot;); \r\n        Console.WriteLine(&amp;quot;   mFindstr &amp;lt;search-pattern&amp;gt; &amp;lt;fully-qualified-folder-path&amp;gt;.&amp;quot;); \r\n        Console.WriteLine(&amp;quot;Example:&amp;quot;); \r\n        Console.WriteLine(&amp;quot;   mFindstr on D:Temp.&amp;quot;); \r\n    } \r\n    else \r\n    { \r\n        string searchPattern = args[0]; \r\n        string folderPath = args[1]; \r\n        RecurseFolders(folderPath, searchPattern).Wait(); \r\n    } \r\n \r\n    Console.WriteLine(&amp;quot;Press a key to continue: &amp;quot;); \r\n    Console.ReadLine(); \r\n} \r\n\r\n<\/pre>\n<p>Now for the custom\u00a0RecurseFolders\u00a0method. Inside this method, I need to use a number of\u00a0async\u00a0methods for the file handling, so the method needs to be declared\u00a0async\u00a0\u2013 and this is also why I called Wait() on the Task return from the method back up in Main.\u00a0I can\u2019t make Main\u00a0async, so I must make sure to contain all\u00a0meaningful\u00a0async\u00a0return values\u00a0within the lower-level methods.<\/p>\n<p>In this method, I\u2019ll get the\u00a0StorageFolder\u00a0for the root folder supplied by the user on the command-line, get the files in this folder, and\u00a0then continue down the folder tree for all\u00a0sub-folders\u00a0and their files:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\">\r\n\r\nprivate static async Task&amp;lt;bool&amp;gt; RecurseFolders(string folderPath, string searchPattern) \r\n{ \r\n    bool success = true; \r\n    try \r\n    { \r\n        StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folderPath); \r\n \r\n        if (folder != null) \r\n        { \r\n            Console.WriteLine( \r\n                $&amp;quot;Searching folder '{folder}' and below for pattern '{searchPattern}'&amp;quot;); \r\n            try \r\n            { \r\n                \/\/ Get the files in this folder. \r\n                IReadOnlyList&amp;lt;StorageFile&amp;gt; files = await folder.GetFilesAsync(); \r\n                foreach (StorageFile file in files) \r\n                { \r\n                    SearchFile(file, searchPattern); \r\n                } \r\n \r\n                \/\/ Recurse sub-directories. \r\n                IReadOnlyList&amp;lt;StorageFolder&amp;gt; subDirs = await folder.GetFoldersAsync(); \r\n                if (subDirs.Count != 0) \r\n                { \r\n                    GetDirectories(subDirs, searchPattern); \r\n                } \r\n            } \r\n            catch (Exception ex) \r\n            { \r\n                success = false; \r\n                Console.WriteLine(ex.Message); \r\n            } \r\n        } \r\n    } \r\n    catch (Exception ex) \r\n    { \r\n        success = false; \r\n        Console.WriteLine(ex.Message); \r\n    } \r\n    return success; \r\n} \r\n\r\n<\/pre>\n<p><span class=\"TextRun SCXW131192216\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW131192216\">The\u00a0<\/span><span class=\"SpellingError SCXW131192216\">GetDirectories<\/span><span class=\"NormalTextRun SCXW131192216\">\u00a0method is the\u00a0<\/span><\/span><span class=\"TextRun SCXW131192216\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW131192216\">actual\u00a0<\/span><\/span><span class=\"TextRun SCXW131192216\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW131192216\">recursive method that performs the same operation (get the files in the current folder, then\u00a0<\/span><span class=\"SpellingError SCXW131192216\">recurse<\/span><span class=\"NormalTextRun SCXW131192216\">\u00a0sub-folders):<\/span><\/span><span class=\"EOP SCXW131192216\">\u00a0<\/span><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\">\r\n\r\nprivate static async void GetDirectories(IReadOnlyList&amp;lt;StorageFolder&amp;gt; folders, string searchPattern) \r\n{ \r\n    try \r\n    { \r\n        foreach (StorageFolder folder in folders) \r\n        { \r\n            \/\/ Get the files in this folder. \r\n            IReadOnlyList&amp;lt;StorageFile&amp;gt; files = await folder.GetFilesAsync(); \r\n            foreach (StorageFile file in files) \r\n            { \r\n                SearchFile(file, searchPattern); \r\n            } \r\n \r\n            \/\/ Recurse this folder to get sub-folder info. \r\n            IReadOnlyList&amp;lt;StorageFolder&amp;gt; subDirs = await folder.GetFoldersAsync(); \r\n            if (subDirs.Count != 0) \r\n            { \r\n                GetDirectories(subDirs, searchPattern); \r\n            } \r\n        } \r\n    } \r\n    catch (Exception ex) \r\n    { \r\n        Console.WriteLine(ex.Message); \r\n    } \r\n} \r\n\r\n<\/pre>\n<p><span class=\"TextRun SCXW64567837\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW64567837\">Finally, the\u00a0<\/span><span class=\"SpellingError SCXW64567837\">SearchFile<\/span><span class=\"NormalTextRun SCXW64567837\">\u00a0method, which is where I\u2019m doing the pattern-matching, using Regex<\/span><\/span><span class=\"TextRun SCXW64567837\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW64567837\">. As before, I\u2019m enhancing the raw search pattern to search for any whitespace-delimited \u201cword\u201d that contains the user-supplied pattern.<\/span><\/span><span class=\"TextRun SCXW64567837\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW64567837\">\u00a0Then I walk the returned\u00a0<\/span><span class=\"SpellingError SCXW64567837\">MatchCollection<\/span><span class=\"NormalTextRun SCXW64567837\">, and print out all the found \u201cwords\u201d and their position in the file.<\/span><\/span><span class=\"EOP SCXW64567837\">\u00a0<\/span><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\">\r\n\r\nprivate static async void SearchFile(StorageFile file, string searchPattern) \r\n{ \r\n    if (file != null) \r\n    { \r\n        try \r\n        { \r\n            Console.WriteLine($&amp;quot;Scanning file '{file.Path}'&amp;quot;); \r\n            string text = await FileIO.ReadTextAsync(file); \r\n            string compositePattern =  \r\n                &amp;quot;(S+s+){0}S*&amp;quot; + searchPattern + &amp;quot;S*(s+S+){0}&amp;quot;; \r\n            Regex regex = new Regex(compositePattern); \r\n            MatchCollection matches = regex.Matches(text); \r\n            foreach (Match match in matches) \r\n            { \r\n                Console.WriteLine($&amp;quot;{match.Index,8} {match.Value}&amp;quot;); \r\n            } \r\n        } \r\n        catch (Exception ex) \r\n        { \r\n            Console.WriteLine(ex.Message); \r\n        } \r\n    } \r\n} \r\n\r\n<\/pre>\n<p><span class=\"TextRun SCXW266616861\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW266616861\">With this, I can now p<\/span><\/span><span class=\"TextRun SCXW266616861\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW266616861\">ress F5 to build and deploy the app. For console apps it often makes sense to set the Debug properties to \u201cDo not launch, but debug my code when it starts\u201d \u2013 because the most useful testing will be done with varying command-line arguments, and therefore by launching the app from a command prompt<\/span><\/span><span class=\"TextRun SCXW266616861\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW266616861\">\u00a0rather from Visual Studio.<\/span><\/span><span class=\"EOP SCXW266616861\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/6ee7bdbd0dbdab5bfe36a968779af296.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-52740\" src=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/6ee7bdbd0dbdab5bfe36a968779af296.png\" alt=\"For console apps it often makes sense to set the Debug properties to \u201cDo not launch, but debug my code when it starts.\u201d\" width=\"822\" height=\"382\" \/><\/a><\/p>\n<p><span class=\"TextRun SCXW38875142\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW38875142\">I can t<\/span><\/span><span class=\"TextRun SCXW38875142\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW38875142\">est the app using a command window or\u00a0<\/span><span class=\"SpellingError SCXW38875142\">powershell<\/span><span class=\"NormalTextRun SCXW38875142\">\u00a0window:<\/span><\/span><span class=\"EOP SCXW38875142\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/0e521223d3f95d1e8ebf3aab383cbe2c.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-52743\" src=\"https:\/\/blogs.windows.com\/uploads\/mswbprod\/sites\/3\/2018\/06\/0e521223d3f95d1e8ebf3aab383cbe2c.png\" alt=\"Test the app using a command window or powershell window\" width=\"1162\" height=\"702\" \/><\/a><\/p>\n<p><span class=\"TextRun SCXW59157175\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW59157175\">That\u2019s it! You can now write Console UWP apps in C#.<\/span><\/span><span class=\"TextRun SCXW59157175\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW59157175\">\u00a0Full source code for this sample app is on\u00a0<\/span><span class=\"SpellingError SCXW59157175\">Github<\/span><span class=\"NormalTextRun SCXW59157175\">\u00a0<\/span><\/span><strong><a class=\"Hyperlink SCXW59157175\" href=\"https:\/\/github.com\/Microsoft\/AppModelSamples\/tree\/master\/Samples\/CsFindstr\" target=\"_blank\" rel=\"noopener noreferrer\"><span class=\"TextRun Underlined SCXW59157175\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW59157175\">here<\/span><\/span><\/a><span class=\"TextRun SCXW59157175\" lang=\"EN-US\" xml:lang=\"EN-US\"><span class=\"NormalTextRun SCXW59157175\">.<\/span><\/span><\/strong><span class=\"EOP SCXW59157175\">\u00a0<\/span><\/p>\n<p>Source: <a href=\"http:\/\/blogs.windows.com\/buildingapps\/2018\/06\/06\/c-console-uwp-applications\/\" target=\"_blank\">C# Console UWP Applications<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>C# Console UWP Applications We\u2019ve just published an update to the Console UWP App project templates on the Visual Studio marketplace\u00a0here. The latest version (v1.5) adds support for C#. The C# template code only works with Visual Studio 2017 version 15.7 or later.\u00a0In\u00a0a previous post,\u00a0I\u00a0described how to build a simple\u00a0findstr\u00a0UWP app using the C++ Console templates. In this post, we\u2019ll look at how to achieve the same with C#, and call out a few additional wrinkles you should be aware of. Having installed the updated VSIX, you can now choose a C# Console\u00a0UWP\u00a0App from the New Project dialog: Note that C# console apps are only supported from version 10.0.17134.0 of the platform. You should therefore specify a version &gt;= 10.0.17134 for the\u00a0minimum platform version\u00a0when you create your project.\u00a0If you forget this step, you can\u00a0fix it\u00a0at any time later by manually <a class=\"mh-excerpt-more\" href=\"https:\/\/jirak.net\/wp\/c-console-uwp-applications\/\" title=\"C# Console UWP Applications\">[ more&#8230; ]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":24816,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[169],"tags":[201],"class_list":["post-24815","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","tag-windows"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/24815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/comments?post=24815"}],"version-history":[{"count":1,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/24815\/revisions"}],"predecessor-version":[{"id":24817,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/24815\/revisions\/24817"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media\/24816"}],"wp:attachment":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media?parent=24815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/categories?post=24815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/tags?post=24815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}