{"id":102,"date":"2007-08-09T15:59:35","date_gmt":"2007-08-09T20:59:35","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/2007\/08\/08\/a-way-to-create-reusable-tools\/"},"modified":"2016-07-31T20:45:42","modified_gmt":"2016-08-01T01:45:42","slug":"a-way-to-create-reusable-tools","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2007\/08\/09\/a-way-to-create-reusable-tools\/","title":{"rendered":"A Way to Create Reusable Tools"},"content":{"rendered":"<div class=\"content\">\n<p>There are a lot of ways to create reusable tools and widgets in lots of programming languages, including MATLAB. Today I<br \/>\nwant to illustrate creating a reusable visualization tool that can then be incorporated into a more complex visualization<br \/>\ntool. Several of us (Scott, Mike, and I) at The MathWorks developed this example for the MATLAB World Tour that took place earlier this year. I even posted some pictures from some of <a href=\"https:\/\/blogs.mathworks.com\/loren\/category\/travel\/\">the events<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3>Contents<\/h3>\n<div>\n<ul>\n<li><a href=\"#1\">Here's a GUI Using the Tool<\/a><\/li>\n<li><a href=\"#2\">Code Architecture<\/a><\/li>\n<li><a href=\"#3\">Initialization<\/a><\/li>\n<li><a href=\"#10\">The Engine Code<\/a><\/li>\n<li><a href=\"#11\">Help<\/a><\/li>\n<li><a href=\"#12\">Variable Initialization<\/a><\/li>\n<li><a href=\"#14\">The Main Work<\/a><\/li>\n<li><a href=\"#17\">The GUI<\/a><\/li>\n<li><a href=\"#18\">Modular Programming Architecture<\/a><\/li>\n<li><a href=\"#20\">The Files<\/a><\/li>\n<\/ul>\n<\/div>\n<h3>Here's a GUI Using the Tool<a name=\"1\"><\/a><\/h3>\n<p>Here I show the tool embedded in a GUI (graphical user interface). There's a slider that allows the user to choose a viewing<br \/>\nplane through the x-axis of the 3-D volume.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">[x,y,z,v] = flow();\r\nvolvisGUI(x,y,z,v)<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_01.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<h3>Code Architecture<a name=\"2\"><\/a><\/h3>\n<p>The code is split into two files, the actual GUI, in <tt>volvisGUI.m<\/tt> and the viewer that shows planes slicing through the volume, in <tt>volumeVisualization.m<\/tt>. Let's first look at a skeleton of the code for <tt>volumeVisualization<\/tt>.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">dbtype <span style=\"color: #a020f0;\">volumeVisualizationPseudo<\/span><\/pre>\n<pre style=\"font-style: oblique;\">1     function s = volumeVisualizationPseudo(x,y,z,v)\r\n2     %volumeVisualizationPseudo   Pseudo-code for volumeVisualization.\r\n3     \r\n4     %   Copyright 2007 The MathWorks, Inc.\r\n5     \r\n6     %% Initialize\r\n7     initDisplay(x,y,z,v)\r\n8     \r\n9     %% Nested Functions\r\n10        %% Add slice plane\r\n11        function addSlicePlane(xLoc)\r\n12        end\r\n13        %% Delete Slice plane\r\n14        function deleteLastSlicePlane()\r\n15        end\r\n16        %% Initialize DIsplay\r\n17        function initDisplay(x,y,z,v)\r\n18        end\r\n19    \r\n20    % Export structure\r\n21    s.addSlicePlane = @addSlicePlane;\r\n22    s.deleteLastSlicePlane = @deleteLastSlicePlane;\r\n23    s.xMin = min(x(:));\r\n24    s.xMax = max(x(:));\r\n25    end\r\n\r\n<\/pre>\n<h3>Initialization<a name=\"3\"><\/a><\/h3>\n<p>In this code, you can see that the figure is initialized, and a structure is returned. This structure contains the minimum<br \/>\nand maximum values possible for a plane along the x-axis as well as function handles to two functions, one to add a slice<br \/>\nplane, and one to delete the last slice plane. The two function handles are the functionality I may then use if I want to<br \/>\nbuild on top of this visualization.<\/p>\n<p>Let me try out the engine now. First I create the visualization.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">close <span style=\"color: #a020f0;\">all<\/span>\r\ns = volumeVisualization(x,y,z,v)<\/pre>\n<pre style=\"font-style: oblique;\">s = \r\n           addSlicePlane: @volumeVisualization\/addSlicePlane\r\n    deleteLastSlicePlane: @volumeVisualization\/deleteLastSlicePlane\r\n                    xMin: 0.1000\r\n                    xMax: 9.9000\r\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_02.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>Next, let me add and remove some slices.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.addSlicePlane(5)<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_03.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.addSlicePlane(3.2)<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_04.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>Now delete the last plane added.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.deleteLastSlicePlane()<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_05.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>And again.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.deleteLastSlicePlane()<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/102\/vviztour07_06.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>And again. Or can I? I only added two slices and I am now up to deleting the third!<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.deleteLastSlicePlane()<\/pre>\n<h3>The Engine Code<a name=\"10\"><\/a><\/h3>\n<p>Whew! No seg-fault or other crash. Let's look at the actual code to see what's going on. I'll discuss it in segments.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">dbtype <span style=\"color: #a020f0;\">volumeVisualization<\/span><\/pre>\n<pre style=\"font-style: oblique;\">1     function s = volumeVisualization(x,y,z,v)\r\n2     %volumeVisualization Engine for choosing y-z planes to view.\r\n3     %   s = volumeVisualization(X,Y,Z,V) returns a structure \r\n4     %   containing information about the visualization of volume\r\n5     %   data described by X,Y,Z,V.  The fields are:\r\n6     %          addSlicePlane -- function handle to add a slice\r\n7     %                           plane at location x\r\n8     %   deleteLastSlicePLane -- function handle to delete the\r\n9     %                           last slice plane added\r\n10    %                   xMin -- minimum x location for a plane\r\n11    %                   xMax -- maximum x location for a plane\r\n12    %\r\n13    %      Example:\r\n14    %      [x,y,z,v] = flow;\r\n15    %      s = volumeVisualization(x,y,z,v);\r\n16    %      s.addSlicePlane(3.7)\r\n17    %      s.addSlicePlane(7.5)\r\n18    %      pause\r\n19    %      s.deleteLastSlicePlane()\r\n20    %      pause\r\n21    %      s.deleteLastSlicePlane()\r\n22    \r\n23    %   Copyright 2007 The MathWorks, Inc.\r\n24    \r\n25    %% Store handles to the various planes\r\n26    %initialize handle to axis\r\n27    %initialize handle to slice plane\r\n28    hAxis = [];         \r\n29    hSlicePlanes = [];  \r\n30    \r\n31    %% Create data for generic slice through yz-plane\r\n32    [yd,zd] = meshgrid(linspace(min(y(:)),max(y(:)),100), ...\r\n33        linspace(min(z(:)),max(z(:)),100));\r\n34    \r\n35    %% Plot the volume initially\r\n36    initDisplay()\r\n37    \r\n38    %% Nested Functions\r\n39        function addSlicePlane(xLoc)\r\n40        %addSlicePlane   Add a slice plane xLoc.\r\n41            xd            = xLoc*ones(size(yd));\r\n42            newSlicePlane = slice(hAxis, x, y, z, v, xd, yd, zd);\r\n43            hSlicePlanes   = [ hSlicePlanes, newSlicePlane ];\r\n44            set(newSlicePlane,'FaceColor'      ,'interp',...\r\n45                              'EdgeColor'      ,'none'  ,...\r\n46                              'DiffuseStrength',.8       );\r\n47        end\r\n48    \r\n49        function deleteLastSlicePlane()\r\n50        %deleteLastSlicePlane Delete the last slice plane added.\r\n51            if ~isempty(hSlicePlanes)\r\n52                delete(hSlicePlanes(end));\r\n53                hSlicePlanes = hSlicePlanes(1:end-1);\r\n54            end\r\n55        end\r\n56    \r\n57        function initDisplay()\r\n58        %initDisplay  Initialize Display.\r\n59    \r\n60            % Draw back and bottom walls\r\n61            if isempty(hAxis) || ~ishandle(hAxis)\r\n62                hAxis = gca;\r\n63                hold on;\r\n64            end\r\n65            hx = slice(hAxis, x, y, z, v, ...\r\n66                max(x(:)),       [],       []) ;\r\n67            hy = slice(hAxis, x, y, z, v, ...\r\n68                [],       max(y(:)),       []) ;\r\n69            hz = slice(hAxis, x, y, z, v, ...\r\n70                [],              [],min(z(:))) ;\r\n71    \r\n72            % Make everything look nice\r\n73            set([hx hy hz],'FaceColor','interp',...\r\n74                'EdgeColor','none')\r\n75            set(hAxis,'FontSize',18,'FontWeight','Bold');\r\n76            xlabel('X');ylabel('Y');zlabel('Z')\r\n77            daspect([1,1,1])\r\n78            axis tight\r\n79            box on\r\n80            view(-38.5,16)\r\n81            colormap (jet(128))\r\n82        end\r\n83    \r\n84    s.addSlicePlane = @addSlicePlane;\r\n85    s.deleteLastSlicePlane = @deleteLastSlicePlane;\r\n86    s.xMin = min(x(:));\r\n87    s.xMax = max(x(:));\r\n88    \r\n89    end\r\n\r\n<\/pre>\n<h3>Help<a name=\"11\"><\/a><\/h3>\n<p>We start off with the function declaration, followed by lines 2-21 for the help including an example.<\/p>\n<h3>Variable Initialization<a name=\"12\"><\/a><\/h3>\n<p>We next initialize variables to hold the handle to the axes in which the data are plotted and another array for the handles<br \/>\nto the slice planes. They start off empty. We also make an array of values for the y and z data for a generic slice. And<br \/>\nthen we initialize the plot, by calling the nested function <tt>initDisplay<\/tt>. You can see that we plot several slices along different directions and alter aspects of the plot such as colormap, aspects<br \/>\nof the axes, etc.<\/p>\n<p>Finally, we set up a structure to return the minimum and maximum values for the slices along the x-axis and function handles<br \/>\nto two functions, for adding and deleting slices. These function handles refer to nested functions in the file <tt>volumeVisualization.m<\/tt> and I will discuss these functions in the next section.<\/p>\n<h3>The Main Work<a name=\"14\"><\/a><\/h3>\n<p>The main work for this application is done after the initialization and is embodied in the two nested functions <tt>addSlicePlane<\/tt> and <tt>deleteLastSlicePlane<\/tt>.<\/p>\n<p>When I call <tt>addSlicePlane<\/tt>, I insert a plane at a particular x-location. The function creates data for the slice plane, instantiates a slice, makes<br \/>\nit pretty by altering some color and shading properties, and adds the handle to the latest slice to the list of slice handles.<br \/>\nAs simple as that.<\/p>\n<p>Calling <tt>deleteLastSlicePlane<\/tt> again manages the list of slice planes by deleting the last element on the list from the plot, and removing it from the list<br \/>\nof slice planes. If that list is empty, the function essentially does nothing, which is why it had the good graces to not<br \/>\nerror out on me earlier.<\/p>\n<h3>The GUI<a name=\"17\"><\/a><\/h3>\n<p>I am now poised to use this M-file to create the initial GUI I showed. That GUI has a slider that maps to positions for planes<br \/>\nalong the x-axis. When a user selects a value, the slider callback simply deletes the last slice plane and adds a new one<br \/>\nat the chosen location. Here's the code.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">dbtype <span style=\"color: #a020f0;\">volvisGUI<\/span><\/pre>\n<pre style=\"font-style: oblique;\">1     function volvisGUI(x,y,z,v)\r\n2     % volvisGUI Interactive volume visualization.\r\n3     %\r\n4     %   Example:\r\n5     %   [x,y,z,v] = flow;\r\n6     %   volvisGUI(x,y,z,v)\r\n7     \r\n8     %   Copyright 2007 The MathWorks, Inc.\r\n9     \r\n10    %% Initalize visualization\r\n11    figure;\r\n12    s = volumeVisualization(x,y,z,v);\r\n13    s.addSlicePlane(s.xMin);\r\n14    \r\n15    %% Add uicontrol\r\n16    hSlider = uicontrol(...\r\n17        'Units','normalized', ...\r\n18        'Position',[.75 .05 .2 .05], ...\r\n19        'Style','slider', ...\r\n20        'Min',s.xMin, ...\r\n21        'Max',s.xMax, ...\r\n22        'Value',s.xMin, ...\r\n23        'Callback',@updateSliderPosition);\r\n24    \r\n25    %%\r\n26        function updateSliderPosition(varargin)\r\n27            s.deleteLastSlicePlane();\r\n28            x = get(hSlider,'Value');\r\n29            s.addSlicePlane(x);\r\n30        end\r\n31    \r\n32    end\r\n33    \r\n\r\n<\/pre>\n<h3>Modular Programming Architecture<a name=\"18\"><\/a><\/h3>\n<p>I've demonstrated here a programming architecture, using nested functions, where you can create individual tools, and incorporate<br \/>\nthem into larger applications.<\/p>\n<p>I have the visualization engine and I showed how to use it both in a stand-alone way as well as how to incorporate it into<br \/>\na GUI. It now can operate as a tool ready to incorporate in other applications. For example, I could have chosen it to power<br \/>\nan animation. Or I could add other degrees of freedom in a GUI by supplying a way to choose other colormaps perhaps.<\/p>\n<h3>The Files<a name=\"20\"><\/a><\/h3>\n<p>You can find the running files for this example on the File Exchange at MATLAB Central.<\/p>\n<p>How might you use such ideas for creating tools you can reuse and share easily? Post your thoughts <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=102\">here<\/a>.<\/p>\n<p><script>\/\/ <![CDATA[\nfunction grabCode_2756c556f6204a0f82c364bc3f7b34a5() {\n        \/\/ Remember the title so we can use it in the new page\n        title = document.title;\n\n        \/\/ Break up these strings so that their presence\n        \/\/ in the Javascript doesn't mess up the search for\n        \/\/ the MATLAB code.\n        t1='2756c556f6204a0f82c364bc3f7b34a5 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 2756c556f6204a0f82c364bc3f7b34a5';\n    \n        b=document.getElementsByTagName('body')[0];\n        i1=b.innerHTML.indexOf(t1)+t1.length;\n        i2=b.innerHTML.indexOf(t2);\n \n        code_string = b.innerHTML.substring(i1, i2);\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\n\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \n        \/\/ in the XML parser.\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\n        \/\/ doesn't go ahead and substitute the less-than character. \n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\n\n        author = 'Loren Shure';\n        copyright = 'Copyright 2007 The MathWorks, Inc.';\n\n        w = window.open();\n        d = w.document;\n        d.write('\n\n\n\n\n\n<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\n\n\n\n\n\n\n\\n');\n      \n      d.title = title + ' (MATLAB code)';\n      d.close();\n      }\n\/\/ ]]><\/script><\/p>\n<p style=\"text-align: right; font-size: xx-small; font-weight: lighter; font-style: italic; color: gray;\"><a><span style=\"font-size: x-small; font-style: italic;\">Get<br \/>\nthe MATLAB code<br \/>\n<noscript>(requires JavaScript)<\/noscript><\/span><\/a><\/p>\n<p>Published with MATLAB\u00ae 7.4<\/p>\n<\/div>\n<p><!--\n2756c556f6204a0f82c364bc3f7b34a5 ##### SOURCE BEGIN #####\n%% A Way to Create Reusable Tools\n% There are a lot of ways to create reusable tools and widgets in lots of\n% programming languages, including MATLAB.  Today I want to illustrate\n% creating a reusable visualization tool that can then be incorporated\n% into a more complex visualization tool.  Several of us (Scott, Mike,\n% and I) at The MathWorks developed this example for the\n% <https:\/\/www.mathworks.com\/company\/events\/worldtour\/matlab07\/?s_cid=HP_E_C_MLTOUR MATLAB World Tour>\n% that took place earlier this year.  I even posted some pictures from some\n% of\n% <https:\/\/blogs.mathworks.com\/loren\/category\/travel\/ the events>.\n%% Here's a GUI Using the Tool\n% Here I show the tool embedded in a GUI (graphical user interface).\n% There's a slider that allows the user to choose a viewing plane through\n% the x-axis of the 3-D volume.\n[x,y,z,v] = flow();\nvolvisGUI(x,y,z,v)\n%% Code Architecture\n% The code is split into two files, the actual GUI, in |volvisGUI.m| and\n% the viewer that shows planes slicing through the volume, in\n% |volumeVisualization.m|.  Let's first look at a skeleton of the code for\n% |volumeVisualization|.\ndbtype volumeVisualizationPseudo\n%% Initialization\n% In this code, you can see that the figure is initialized, and a structure\n% is returned.  This structure contains the minimum and maximum values\n% possible for a plane along the x-axis as well as function handles to two\n% functions, one to add a slice plane, and one to delete the last slice\n% plane.  The two function handles are the functionality I may then use if\n% I want to build on top of this visualization.\n%%\n% Let me try out the engine now.  First I create the visualization.\nclose all\ns = volumeVisualization(x,y,z,v)\n%%\n% Next, let me add and remove some slices.\ns.addSlicePlane(5)\n%%\ns.addSlicePlane(3.2)\n%%\n% Now delete the last plane added.\ns.deleteLastSlicePlane()\n%%\n% And again.\ns.deleteLastSlicePlane()\n%%\n% And again.  Or can I?  I only added two slices and I am now up to\n% deleting the third!\ns.deleteLastSlicePlane()\n%% The Engine Code\n% Whew!  No seg-fault or other crash.  Let's look at the actual code to see\n% what's going on.  I'll discuss it in segments.\ndbtype volumeVisualization\n%% Help\n% We start off with the function declaration, followed by lines 2-21 for the\n% help including an example.\n%% Variable Initialization\n% We next initialize variables to hold the handle to the axes in which the\n% data are plotted and another array for the handles to the slice planes.\n% They start off empty.  We also make an array of values for the y and z\n% data for a generic slice.  And then we initialize the plot, by calling\n% the nested function |initDisplay|.  You can see that we plot several\n% slices along different directions and alter aspects of the plot such as\n% colormap, aspects of the axes, etc.\n%%\n% Finally, we set up a structure to return the\n% minimum and maximum values for the slices along the x-axis and function\n% handles to two functions, for adding and deleting slices.  These function\n% handles refer to nested functions in the file |volumeVisualization.m| and\n% I will discuss these functions in the next section.\n%% The Main Work\n% The main work for this application is done after the initialization and\n% is embodied in the two nested functions |addSlicePlane| and\n% |deleteLastSlicePlane|.\n%%\n% When I call |addSlicePlane|, I insert a plane at a particular x-location.\n% The function creates data for the slice plane, instantiates a slice,\n% makes it pretty by altering some color and shading properties, and adds\n% the handle to the latest slice to the list of slice handles.  As simple\n% as that.\n%%\n% Calling |deleteLastSlicePlane| again manages the list of slice planes by\n% deleting the last element on the list from the plot, and removing it from\n% the list of slice planes.  If that list is empty, the function\n% essentially does nothing, which is why it had the good graces to not\n% error out on me earlier.\n%% The GUI\n% I am now poised to use this M-file to create the initial GUI I showed.\n% That GUI has a slider that maps to positions for planes along the x-axis.\n% When a user selects a value, the slider callback simply deletes the last\n% slice plane and adds a new one at the chosen location.  Here's the code.\ndbtype volvisGUI\n%% Modular Programming Architecture\n% I've demonstrated here a programming architecture, using nested\n% functions, where you can create individual tools, and incorporate them\n% into larger applications.\n%%\n% I have the visualization engine and I showed how to use it both in a\n% stand-alone way as well as how to incorporate it into a GUI.  It now can\n% operate as a tool ready to incorporate in other applications.  For\n% example, I could have chosen it to power an animation.  Or I could add other\n% degrees of freedom in a GUI by supplying a way to choose other colormaps\n% perhaps.\n%% The Files\n% You can find the running files for this example\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=15867&objectType=file here>\n% on the File Exchange at MATLAB Cental.\n%%\n% How might you use such ideas for creating tools you can reuse and share\n% easily?  Post your thoughts\n% <https:\/\/blogs.mathworks.com\/loren\/?p=102 here>.\n##### SOURCE END ##### 2756c556f6204a0f82c364bc3f7b34a5\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\nThere are a lot of ways to create reusable tools and widgets in lots of programming languages, including MATLAB. Today I<br \/>\nwant to illustrate creating a reusable visualization tool that can then be... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2007\/08\/09\/a-way-to-create-reusable-tools\/\">read more >><\/a><\/p>\n","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3,11,13],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/102"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/102\/revisions"}],"predecessor-version":[{"id":1857,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/102\/revisions\/1857"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}