{"id":233,"date":"2020-04-26T21:33:09","date_gmt":"2020-04-26T20:33:09","guid":{"rendered":"http:\/\/192.168.8.14\/?p=233"},"modified":"2020-04-26T21:44:37","modified_gmt":"2020-04-26T20:44:37","slug":"menu-function","status":"publish","type":"post","link":"https:\/\/www.jasonstreet.com\/?p=233","title":{"rendered":"Menu Function"},"content":{"rendered":"\n<p>One (very boring) locked in Bank Holiday weekend, with my right hand in plaster I decided to write a function\/s I had been meaning to write for a long time. <\/p>\n\n\n\n<p>A &#8220;simple&#8221; on screen menu. You give the function an array and it will display it and let you pick a row\/element and return that row. <\/p>\n\n\n\n<p>Because  the basic idea spiralled in complexity, I added multiple pages, display specific columns and search options.<\/p>\n\n\n\n<p>All written with my left hand.<\/p>\n\n\n\n<p>Controlling the menu is easy using the following keys:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Up &#8211; move the selected line up<\/li><li>Down &#8211; move the selected line down<\/li><li>Left &#8211; move to the previous page<\/li><li>Right &#8211; move to the next page<\/li><li>Enter &#8211; return the selected item\/row\/array element<\/li><li> a-z, ., -, 0-9 &#8211; display only the  items\/rows\/array elements that contain that string<\/li><li>Back Space &#8211; remove the last character from the search string.<\/li><li>Esc &#8211; exit and return $null.<\/li><\/ul>\n\n\n\n<p>I loaded in some test data (I will attach that) to demonstrate its functionality. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"839\" height=\"218\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/Do-Menu01.png\" alt=\"\" class=\"wp-image-234\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu01.png 839w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu01-300x78.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu01-768x200.png 768w\" sizes=\"auto, (max-width: 839px) 100vw, 839px\" \/><figcaption>A simple menu displaying the first of three pages<\/figcaption><\/figure>\n\n\n\n<p>The first screen shot shows the menu is its simplest form. I have called the function and only specified the object array. The function will default to display every attribute\/column and 10 lines per page.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"839\" height=\"213\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/Do-Menu02.png\" alt=\"\" class=\"wp-image-235\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu02.png 839w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu02-300x76.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu02-768x195.png 768w\" sizes=\"auto, (max-width: 839px) 100vw, 839px\" \/><figcaption>Displaying page 2 of 3<\/figcaption><\/figure>\n\n\n\n<p>The above screen shot shows rows from page 2. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"840\" height=\"217\" src=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/Do-Menu03.png\" alt=\"\" class=\"wp-image-237\" srcset=\"https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu03.png 840w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu03-300x78.png 300w, https:\/\/www.jasonstreet.com\/wp-content\/uploads\/2020\/04\/Do-Menu03-768x198.png 768w\" sizes=\"auto, (max-width: 840px) 100vw, 840px\" \/><figcaption>Searching for &#8220;dc&#8221;<\/figcaption><\/figure>\n\n\n\n<p>The screen shot above shows the menu after entering the string &#8220;dc&#8221;. Any row with the string &#8220;dc&#8221; in any of the displayed attributes is shown.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Code<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n&lt;#\n  .SYNOPSIS\n  Will take an array, display it on screen and allow the user to select one row.\n\n  .DESCRIPTION\n  Generate a screen menu from an array, allows the user to scroll up, down  as well as page left\/right and dynamic search.\n\n  .PARAMETER ObjList\n  Array to be displayed for the user to select a row\n\n  .PARAMETER DisplayCols\n  array of column names from ObjList to be displayed on screen\n\n  .PARAMETER HeaderText\n  Text to be shown at the top of the page\n\n  .PARAMETER MaxLinesPerPage\n  Number of lines per page. \n\n  .INPUTS\n  None. You cannot pipe objects to Do-Menu.\n\n  .OUTPUTS\n  selected row from input array\n\n  .EXAMPLE\n  $SelectedObj = Do-Menu $TestObs -DisplayCols Col1,Col2,Col4\n\n  .EXAMPLE\n  $SelectedObj = Do-Menu $TestObs -DisplayCols location,client,cluster -MaxLinesPerPage 20\n\n  .EXAMPLE\n  $SelectedObj = Do-Menu $MyObjectArray -DisplayCols Name,ID -MaxLinesPerPage 20\n#&gt;\nfunction Do-Menu{\n    param(\n        &#x5B;Parameter(Mandatory = $true)] $ObjList,\n        $DisplayCols = $null,\n        $MaxLinesPerPage = 10,\n        $HeaderText = &quot;  &quot;\n    )\n    \n    if ($DisplayCols -eq $null)\n    {\n        $DisplayCols = (($ObjList | get-member) | where{$_.MemberType -eq &quot;NoteProperty&quot;}).name\n    }\n\n    $OffSetLine = 0\n    $CurrentLine = 0\n    # Check and exit if this function is running in the ISE     \n    if($host.name -match &quot;ISE&quot;)\n    {\n        Write-Host &quot;This function will not work in the ISE (cant read keys)&quot;\n        return $null   \n    }\n\n    $StartCursPos = $host.UI.RawUI.CursorPosition\n    &#x5B;string]$SearchString = &#039;&#039;\n\n    # create new object array with an extra attribute num that increments (like a line number)\n    $NumObjList = @()\n    $num = 0\n    foreach($Obj in $ObjList)\n    {\n        $Obj | add-member -NotePropertyName num -NotePropertyValue $num -Force\n        $NumObjList += $Obj\n        $num ++\n    }\n    # sort the array by the unique line number\n    $DisplayObj = $NumObjList | sort num\n\n    # loop through each display column and get the max length of each, this is for formatting.\n    # we will end up with an array called $ColLengths that is the number of charictos that the $DisplayCol array should be.\n    $ColLengths = @()\n    foreach ($DisplayCol in $DisplayCols)\n    {\n        $MaxCLength = 0\n        foreach ($Row in $DisplayObj.$DisplayCol)\n        {\n            if ($Row.length -gt $MaxCLength){$MaxCLength = $Row.length}\n        }\n        # also test the column header length\n        if ($DisplayCol.length  -gt $MaxCLength){$MaxCLength = $DisplayCol.length}\n        $ColLengths += $MaxCLength\n    }\n\n    # initial display of the array \n    Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -TitleString $HeaderText\n\n    \n    \n\n    # now act on key presses, keep looping until enter or Esc is pressed \n    do{\n\n        $key = $Host.UI.RawUI.ReadKey()\n\n\n        if ($key.VirtualKeyCode -eq &#039;13&#039;) {\n            # Pressed return\n            return $ObjList&#x5B;$DisplayObj&#x5B;$CurrentLine].num]\n        } \n        if (($key.VirtualKeyCode -ge &#039;65&#039; -and $key.VirtualKeyCode -le &#039;90&#039;) -or ($key.VirtualKeyCode -ge &#039;48&#039; -and $key.VirtualKeyCode -le &#039;57&#039;) -or $key.VirtualKeyCode -eq &#039;189&#039; -or $key.VirtualKeyCode -eq &#039;190&#039;) {\n            # Pressed a - z or 0 - 9 or - or .\n\n            # add new character to SearchString\n            &#x5B;string]$SearchString = &#x5B;string]$SearchString + $key.Character.tostring()\n\n            # Search each display column for SearchString \n            $TempDisplayObj = @()\n            foreach($Col in $DisplayCols)\n            {\n              $TempDisplayObj += $NumObjList | where{$_.$Col -match $SearchString}\n\n            } \n            # join the multiple searches using the rownum added earlier. remove duplicates. \n            $DisplayObj = $TempDisplayObj | sort num -Unique\n\n            # if a search shortens the display list and CurrentLine is &quot;high&quot; it can leave the user on page 3 of 2. so if CurrentLine if greater then $DisplayObj.count set CurrentLinr and Offset to 0\n            if ($CurrentLine -ge @($DisplayObj).count)\n            {\n                $OffSetLine = 0\n                $CurrentLine = 0\n            }\n\n            # display the updated list\n            Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n\n        }  \n        if ($key.VirtualKeyCode -eq &#039;40&#039;) {\n            # Pressed down\n            # inc CurrentLine if not at the end of the array.\n            if ($CurrentLine -lt ($DisplayObj.count -1)){$CurrentLine ++}\n\n            # work out if we hace just crossed a page. if so inc offsetLine by 1 page ($MaxLinesPerPage)\n            if ($CurrentLine % $MaxLinesPerPage -eq 0){$OffSetLine = ($CurrentLine \/ $MaxLinesPerPage) * $MaxLinesPerPage}\n            Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n        } \n        if ($key.VirtualKeyCode -eq &#039;38&#039;) {\n            # Pressed up\n            # dec CurrentLine if not at the start of the array.\n            if ($CurrentLine -gt 0){$CurrentLine --}\n\n            # work out if we have just crossed a page. if so dec offsetLine by 1 page ($MaxLinesPerPage)\n            if ($CurrentLine % $MaxLinesPerPage -eq ($MaxLinesPerPage -1)){$OffSetLine = (($CurrentLine \/ $MaxLinesPerPage) * $MaxLinesPerPage) - ($MaxLinesPerPage -1)}\n            Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n        } \n        if ($key.VirtualKeyCode -eq &#039;37&#039;) {\n            # Pressed left\n            # dec $OffSetLine and $CurrentLine by one page ($MaxLinesPerPage) if we are not on page 1\n            if (($OffSetLine - $MaxLinesPerPage) -ge 0)\n            {\n                $OffSetLine = $OffSetLine - $MaxLinesPerPage\n                $CurrentLine = $CurrentLine - $MaxLinesPerPage\n            }\n            Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n\n\n        } \n        if ($key.VirtualKeyCode -eq &#039;39&#039;) {\n            # Pressed right\n            # inc $OffSetLine and $CurrentLine by one page ($MaxLinesPerPage) if we are not on the last page\n            if (($OffSetLine + $MaxLinesPerPage) -lt $DisplayObj.count){$OffSetLine = $OffSetLine + $MaxLinesPerPage}\n            if (($CurrentLine + $MaxLinesPerPage ) -lt $DisplayObj.count)\n            {\n                $CurrentLine = $CurrentLine + $MaxLinesPerPage\n            }else{\n                $CurrentLine = $OffSetLine\n            }\n            Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n \n        } \n        if ($key.VirtualKeyCode -eq &#039;27&#039;) {\n            # Pressed Esc\n            return $null\n        } \n        if ($key.VirtualKeyCode -eq &#039;8&#039;) {\n            # Pressed backspace\n            if ($SearchString.length -ge 1)\n            {\n                # remove last character from search string\n                $SearchString = $SearchString.Substring(0,$SearchString.Length-1)\n                $TempDisplayObj = @()\n                foreach($Col in $DisplayCols)\n                {\n                    # loop through each column and search for searchstring\n                    $TempDisplayObj += $NumObjList | where{$_.$Col -match $SearchString}\n                } \n                $DisplayObj = $TempDisplayObj | sort num -Unique\n                Do-CLIMenuDisplay -DispArr $DisplayObj -DisplayCols $DisplayCols -ColLengths $ColLengths -MaxLines $MaxLinesPerPage -OffSetLine $OffSetLine -CurrentLine $CurrentLine -CursPos $StartCursPos -SearchString $SearchString -TitleString $HeaderText\n\n            }\n        } \n    }until($ExitLoop -eq $true)\n\n\n}\n\nfunction Do-CLIMenuDisplay \n{\n    Param(\n        $DispArr,\n        $DisplayCols,\n        $ColLengths,\n        $MaxLinesPerPage,\n        $OffSetLine,\n        $CurrentLine,\n        $CursPos,\n        $SearchString,\n        $TitleString\n    )\n\n    # put the cursor at the start position, instead of clearing the screen I just overwrite. \n    $host.UI.RawUI.CursorPosition = $StartCursPos\n\n\n    write-host $TitleString\n    &#x5B;string]$LineOutString = &#039;&#039;\n\n    # build the column headers\n    # loop through each $DisplayCol, also $ColLengths to &quot;draw&quot; the headers with consistent spacing. \n    $LoopNum = 0\n    foreach ($DisplayCol in $DisplayCols)\n    {\n        $LineOutString += ( Do-FuncPadSpace -DisplayText $DisplayCol -MaxSpace $ColLengths&#x5B;$loopNum] ) + &quot;  &quot;\n        $LoopNum ++\n    }\n    write-host $LineOutString \n\n    # loop through the number of lines to display ($MaxLinesPerPage) \n    for($x = 0 ; $x -lt ($MaxLinesPerPage) ; $x++)\n    {\n        # check if $DispArr exists (a search could have returned nothing)\n        if ($DispArr)\n        {\n\n\n            #  start at the current $OffSetLine (first line of the current page) and draw this line if it exists in the DisplayArray\n            if(($OffSetLine + $x) -le @($DispArr).count)\n                                                                                                                    {\n            # now loop through each $DisplayCol data end build the line.\n            &#x5B;string]$LineOutString = &#039;&#039;\n            $loopNum = 0\n            foreach($Col in $DisplayCols)\n            {\n                # check if there is anything to display. don&#039;t pass an empty string to Do-FuncPadSpace.\n                if ( ($DispArr&#x5B;$OffSetLine + $x].$Col).length -ge 1)\n                {\n                    # pass $Col data to Do-FuncPadSpace to add the required spaces so data lines up in columns.\n                    $LineOutString += ( Do-FuncPadSpace -DisplayText ($DispArr&#x5B;$OffSetLine + $x].$Col) -MaxSpace $ColLengths&#x5B;$loopNum]) + &quot;  &quot;\n                    $LoopNum ++\n                }else{\n                    # blank line\n                    $LineOutString = &quot;                                             &quot;\n                }\n            }\n            # add some spaces at the end of the line so we remove old text on the line.\n            $LineOutString += &quot;                                          &quot;\n\n            # set correct colour of the selected line.\n            if ($OffSetLine + $x -eq $CurrentLine)\n            {\n                write-host $LineOutString -ForegroundColor Green\n            }else{\n                write-host $LineOutString -ForegroundColor DarkGreen\n            }\n        }else{\n                # blank line\n                write-host &quot;                                                                                              &quot;\n            }\n\n        }else{\n            write-host &quot;                                                                                              &quot;\n        }\n\n    }\n\n    # work out current page number \n    $Remander = $CurrentLine % $MaxLinesPerPage\n    $Div = ($CurrentLine - $Remander) \/ $MaxLinesPerPage\n    $MaxPage = &#x5B;int](@($DispArr).count \/ $MaxLinesPerPage)\n    $ThisPage = &#x5B;int]($Div) + 1\n    $MaxLine = @($DispArr).count - 1\n\n    # write the footer.\n    write-host &quot;                                                      &quot;\n    write-host &quot; Page $ThisPage of $MaxPage  (current item $CurrentLine of $MaxLine)         &quot;\n    write-host &quot; Search string = $SearchString                        &quot;\n    write-host &quot;                                                      &quot;\n    write-host &quot;                                                      &quot;\n}\n\n\n\n\n&lt;#\n   The function will take a text string and pad the end with spaces to make it $MaxSpace in length\n   $testStringofLength20 = Do-FuncPadSpace $testStringOfLength10 20\n#&gt;\nfunction Do-FuncPadSpace\n{\n    Param(\n        &#x5B;Parameter(Mandatory = $true)] $DisplayText,\n        &#x5B;Parameter(Mandatory = $true)] $MaxSpace\n    )\n\n    if ($DisplayText.length -le $MaxSpace)\n    {\n        # add spaces to text to make it the correct length\n        # I should do it with a loop but its not very readable (and it didn&#039;t work)\n        $spacesToAdd = $MaxSpace - $DisplayText.length\n        if ($spacesToAdd -eq 0){}\n        if ($spacesToAdd -eq 1){$Spaces = &quot; &quot;}\n        if ($spacesToAdd -eq 2){$Spaces = &quot;  &quot;}\n        if ($spacesToAdd -eq 3){$Spaces = &quot;   &quot;}\n        if ($spacesToAdd -eq 4){$Spaces = &quot;    &quot;}\n        if ($spacesToAdd -eq 5){$Spaces = &quot;     &quot;}\n        if ($spacesToAdd -eq 6){$Spaces = &quot;      &quot;}\n        if ($spacesToAdd -eq 7){$Spaces = &quot;       &quot;}\n        if ($spacesToAdd -eq 8){$Spaces = &quot;        &quot;}\n        if ($spacesToAdd -eq 9){$Spaces = &quot;         &quot;}\n        if ($spacesToAdd -eq 10){$Spaces = &quot;          &quot;}\n        if ($spacesToAdd -eq 11){$Spaces = &quot;           &quot;}\n        if ($spacesToAdd -eq 12){$Spaces = &quot;            &quot;}\n        if ($spacesToAdd -eq 13){$Spaces = &quot;             &quot;}\n        if ($spacesToAdd -eq 14){$Spaces = &quot;              &quot;}\n        if ($spacesToAdd -eq 15){$Spaces = &quot;               &quot;}\n        if ($spacesToAdd -eq 16){$Spaces = &quot;                &quot;}\n        if ($spacesToAdd -eq 17){$Spaces = &quot;                 &quot;}\n        if ($spacesToAdd -eq 18){$Spaces = &quot;                  &quot;}\n        if ($spacesToAdd -eq 19){$Spaces = &quot;                   &quot;}\n        if ($spacesToAdd -eq 20){$Spaces = &quot;                    &quot;}\n        if ($spacesToAdd -eq 21){$Spaces = &quot;                     &quot;}\n        $Result = $DisplayText + $Spaces\n        return $Result\n    }else{\n        # text to long, error\n    }\n}\n\n<\/pre><\/div>\n\n\n<div class=\"wp-block-file\"><a href=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/func_menu.txt\">func_menu<\/a><a href=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/func_menu.txt\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<div class=\"wp-block-file\"><a href=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/test.csv\">test<\/a><a href=\"http:\/\/192.168.8.14\/wp-content\/uploads\/2020\/04\/test.csv\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Installation<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li>Download the func_menu.txt file and rename it to func_menu.ps1 <\/li><li>Download the test.csv file to the same directory<\/li><li>open a powershell prompt (not the ISE)<\/li><li>CD to the script directory<\/li><li>dot source the function code<ul><li>. .\\func_menu.ps1<\/li><\/ul><\/li><li>import the test data<ul><li>$TestData = import-csv &#8220;test.csv&#8221;<\/li><\/ul><\/li><li>run the function<ul><li>Do-Menu -ObjList $TestData<\/li><\/ul><\/li><li>or <ul><li>$SelectedObj = Do-Menu -ObjList $TestData  -MaxLinesPerPage 20<\/li><li> Do-Menu -ObjList $TestData -DisplayCols name,role<\/li><\/ul><\/li><\/ul>\n\n\n\n<p>That&#8217;s it, have fun.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One (very boring) locked in Bank Holiday weekend, with my right hand in plaster I decided to write a function\/s I had been meaning to write for a long time. A &#8220;simple&#8221; on screen menu. You give the function an array and it will display it and let you pick a row\/element and return that&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[4],"tags":[17,34,35],"class_list":["post-233","post","type-post","status-publish","format-standard","hentry","category-powershell","tag-function","tag-menu","tag-searchable"],"_links":{"self":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/233","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=233"}],"version-history":[{"count":9,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/233\/revisions"}],"predecessor-version":[{"id":263,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/233\/revisions\/263"}],"wp:attachment":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}