{"id":148,"date":"2008-07-29T07:07:43","date_gmt":"2008-07-29T12:07:43","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/2008\/07\/29\/understanding-object-cleanup\/"},"modified":"2016-07-31T13:42:13","modified_gmt":"2016-07-31T18:42:13","slug":"understanding-object-cleanup","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2008\/07\/29\/understanding-object-cleanup\/","title":{"rendered":"Understanding Object Cleanup"},"content":{"rendered":"<div class=\"content\">\n<p>Today I would like to introduce a guest blogger, <a href=\"mailto:nick.haddad@mathworks.com\">Nick Haddad<\/a>, a developer here at The Mathworks who works on Audio &amp; Video related features in MATLAB. Today he talks about cleaning<br \/>\nup different types of objects in MATLAB.<\/p>\n<p>&nbsp;<\/p>\n<h3>Contents<\/h3>\n<div>\n<ul>\n<li><a href=\"#3\">Introduction<\/a><\/li>\n<li><a href=\"#4\">Recording Audio With a Callback<\/a><\/li>\n<li><a href=\"#7\">Scoped Objects vs. User-Managed Objects<\/a><\/li>\n<li><a href=\"#12\">Why do User-Managed Objects Exist?<\/a><\/li>\n<li><a href=\"#13\">Scoped or User-Managed?<\/a><\/li>\n<li><a href=\"#14\">Has this ever happened to you?<\/a><\/li>\n<\/ul>\n<\/div>\n<h3>Introduction<a name=\"3\"><\/a><\/h3>\n<p>The other day I was reading a <a href=\"http:\/\/iheartmatlab.blogspot.com\/2008\/07\/sound-card-spectral-analysis.html\">post<\/a> about sound card spectral analysis from the excellent new <a href=\"http:\/\/iheartmatlab.blogspot.com\">iheartmatlab blog<\/a>. Beyond being a great post on recording from sound cards, the author ran into an issue involving object lifetime that has<br \/>\ntripped me up in the past too.<\/p>\n<p>So, today I would like to talk about two types of objects in MATLAB, scoped objects and user-managed objects. Knowing which<br \/>\nkind of object you are working with can avoid all sorts of confusion. Let's start with a small example.<\/p>\n<h3>Recording Audio With a Callback<a name=\"4\"><\/a><\/h3>\n<p>Suppose you want to use the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/audiorecorder.html\"><tt>audiorecorder<\/tt><\/a> object to record some audio from your sound card. The audiorecorder has a property called <tt>TimerFcn<\/tt>, which allows you to specify a callback function. This callback function calls a function you specify while you are recording audio. Here's an example function.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #0000ff;\">function<\/span> makeRecorder( timerCallback, timerPeriod )\r\n\r\n<span style=\"color: #228b22;\">% Create an audio recorder object<\/span>\r\nrecObject = audiorecorder();\r\n\r\n<span style=\"color: #228b22;\">% Install a callback is called every 'timerPeriod' seconds<\/span>\r\nset( recObject, <span style=\"color: #0000ff;\">...<\/span>\r\n    <span style=\"color: #a020f0;\">'TimerFcn'<\/span>, timerCallback, <span style=\"color: #0000ff;\">...<\/span>\r\n    <span style=\"color: #a020f0;\">'TimerPeriod'<\/span>, timerPeriod );\r\n\r\n<span style=\"color: #228b22;\">% start recording<\/span>\r\nrecord( recObject );\r\n\r\n<span style=\"color: #0000ff;\">end<\/span><\/pre>\n<p>Once recording has started, the function <tt>timerCallback<\/tt> is called every <tt>timerPeriod<\/tt> seconds. This can be handy for inspecting audio data as it is streaming in.<\/p>\n<p>On the face of things the <tt>makeRecorder<\/tt> function looks like it is ready to run. But, there is one subtlety that causes this function not to work as expected. When<br \/>\nthe <tt>makeRecorder<\/tt> function ends, the <tt>recObject<\/tt> variable goes out of scope, is removed from the workspace, and cleans itself up. For an <tt>audiorecorder<\/tt> object, cleaning up means:<\/p>\n<div>\n<ul>\n<li>Stop recording<\/li>\n<li>Remove the installed timer callback<\/li>\n<li>Remove all audiorecorder data from memory<\/li>\n<\/ul>\n<\/div>\n<p>In this case the <tt>timerCallback<\/tt> is never called because when <tt>makeRecorder<\/tt> ends, recording immediately stops and the audiorecorder's timer is shut down.<\/p>\n<p>The reason the object is cleaned up is because the lifetime of an <tt>audiorecorder<\/tt> object is bound by its scope. To keep the object alive you would need to copy the object's local variable out of the <tt>makeRecorder<\/tt> function.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #0000ff;\">function<\/span> recObject = makeRecorderBetter( timerCallback, timerPeriod )\r\n\r\n<span style=\"color: #228b22;\">% Create an audio recorder object<\/span>\r\nrecObject = audiorecorder();\r\n\r\n<span style=\"color: #228b22;\">% Install a callback is called every 'timerPeriod' seconds<\/span>\r\nset( recObject, <span style=\"color: #0000ff;\">...<\/span>\r\n    <span style=\"color: #a020f0;\">'TimerFcn'<\/span>, timerCallback, <span style=\"color: #0000ff;\">...<\/span>\r\n    <span style=\"color: #a020f0;\">'TimerPeriod'<\/span>, timerPeriod );\r\n\r\n<span style=\"color: #228b22;\">% start recording<\/span>\r\nrecord( recObject );\r\n\r\n<span style=\"color: #0000ff;\">end<\/span><\/pre>\n<p>Now <tt>recObject<\/tt> will be in the workspace of the code that calls <tt>makeRecorder<\/tt>, which allows the <tt>audiorecorder<\/tt> to stay alive.<\/p>\n<h3>Scoped Objects vs. User-Managed Objects<a name=\"7\"><\/a><\/h3>\n<p>The <tt>audiorecorder<\/tt> object is what I like to call a scoped object because it cleans up after itself when it goes out of scope. Scoped objects<br \/>\nare the most common type of object in MATLAB. They behave just like regular scalar and matrix variables.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #228b22;\">% Create and clear a scalar<\/span>\r\nz = sin(pi);\r\nclear <span style=\"color: #a020f0;\">z<\/span>;\r\n\r\n<span style=\"color: #228b22;\">% Create and clear a 3 x 3 matrix<\/span>\r\nM = magic(3);\r\nclear <span style=\"color: #a020f0;\">M<\/span>;\r\n\r\n<span style=\"color: #228b22;\">% Create and clear a timeseries object<\/span>\r\nt = timeseries();\r\nclear <span style=\"color: #a020f0;\">t<\/span>;<\/pre>\n<p>Clearing the <tt>timeseries<\/tt> object above removes the <tt>timeseries<\/tt> from memory completely, just like clearing a scalar or matrix variable.<\/p>\n<p>The reason the <tt>makeRecorder<\/tt> example above can be confusing is that some objects in MATLAB clean themselves up when they go out of scope, and some don't.<br \/>\nIf you try the same type of thing with a timer object, the results are very different.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #0000ff;\">function<\/span> makeTimer( timerCallback )\r\n\r\ntimerObject = timer(<span style=\"color: #a020f0;\">'TimerFcn'<\/span>,timerCallback, <span style=\"color: #0000ff;\">...<\/span>\r\n                    <span style=\"color: #a020f0;\">'Period'<\/span>, 0.25, <span style=\"color: #0000ff;\">...<\/span>\r\n                    <span style=\"color: #a020f0;\">'ExecutionMode'<\/span>, <span style=\"color: #a020f0;\">'fixedSpacing'<\/span> );\r\nstart( timerObject );\r\n\r\n<span style=\"color: #0000ff;\">end<\/span><\/pre>\n<p>In this example, the variable <tt>timerObject<\/tt> goes out of scope at the end of <tt>makeTimer<\/tt>, but the timer <b>does not<\/b> get cleaned up. So, the timer fires every 0.25 seconds and the callback function <tt>timerCallback<\/tt> is called appropriately. Let's test it out.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #228b22;\">% Create a timer<\/span>\r\nmakeTimer( @(obj, event) display([obj.Name <span style=\"color: #a020f0;\">' fired'<\/span>]) );\r\n\r\n<span style=\"color: #228b22;\">% pause for a second to let the timer fire<\/span>\r\npause(1);<\/pre>\n<pre style=\"font-style: oblique;\">timer-1 fired\r\ntimer-1 fired\r\ntimer-1 fired\r\ntimer-1 fired\r\n<\/pre>\n<p>You can see here that the timer fired 4 times in one second, even though I can no longer get to the timer object I created.<\/p>\n<p>Timer objects are what I like to call user-managed objects, in that they don't clean up after themselves. You are responsible<br \/>\nfor cleaning up a timer by calling the <tt>delete<\/tt> method after you are done with the timer.<\/p>\n<p>But, after <tt>makeTimer<\/tt> ends, the <tt>timerObject<\/tt> variable is no longer in the workspace, so you will need to find it using the <tt>timerfind<\/tt> function.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\"><span style=\"color: #228b22;\">% find all outstanding timers<\/span>\r\ntimers = timerfind();\r\n\r\n<span style=\"color: #228b22;\">% stop the timers you find<\/span>\r\nstop(timers);\r\n\r\n<span style=\"color: #228b22;\">% delete and clear the timers<\/span>\r\ndelete(timers);\r\nclear <span style=\"color: #a020f0;\">timers<\/span>;<\/pre>\n<h3>Why do User-Managed Objects Exist?<a name=\"12\"><\/a><\/h3>\n<p>Using a user-managed object seems like extra work, but you get flexibility over the object's lifetime expressely because it<br \/>\ncan remain around regardless of a variable's scope. This can be very helpful in several situations, like when you are building<br \/>\nGUIs. For example, you could create a timer object in the <tt>CreateFcn<\/tt> of a figure window which refreshes the figure every second, and then clean up the timer in the figure's <tt>DeleteFcn<\/tt>.<\/p>\n<p>Also, if you are working with a user-managed object and would like to treat it as a scoped object, you can use <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/oncleanup.html\"><tt>onCleanup<\/tt><\/a>, which was introduced in R2008a. See Loren's previous post that covers <tt>onCleanup<\/tt>, <a href=\"https:\/\/blogs.mathworks.com\/loren\/2008\/03\/10\/keeping-things-tidy\">Keeping Things Tidy<\/a>.<\/p>\n<h3>Scoped or User-Managed?<a name=\"13\"><\/a><\/h3>\n<p>MATLAB has a lot of different user-managed objects including <tt>timer<\/tt>, <tt>analoginput<\/tt>, and <a href=\"https:\/\/www.mathworks.com\/help\/imaq\/videoinput.html\"><tt>videoinput<\/tt><\/a> to name a few. Each of these has a corresponding <tt>find<\/tt> function to help you find objects that have been removed from the workspace but are still hanging around in memory.<\/p>\n<p>If you are struggling to figure out if an object is scoped or user-managed, follow these guidelines:<\/p>\n<div>\n<ul>\n<li>Assume the object you are using is a scoped object and will tidy up after itself.<\/li>\n<li>If an object's documentation mentions a <tt>delete<\/tt> function, it might be a user managed object.<\/li>\n<li>If an object's documentation has a <tt>xxxfind<\/tt> method (<tt>timerfind<\/tt>, <tt>daqfind<\/tt>, etc.), it is most likely a user-managed object.<\/li>\n<\/ul>\n<\/div>\n<p>Regardless of the guidelines above, it is good just to know that scoped objects and user-managed objects exist in MATLAB and<br \/>\nthat there are differences between the behavior of each.<\/p>\n<h3>Has this ever happened to you?<a name=\"14\"><\/a><\/h3>\n<p>Have you ever run into issues with user-managed objects? Has an object in MATLAB ever been cleaned up when you weren't expecting<br \/>\nit too? Share you experiences <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p148#respond\">here<\/a>.<\/p>\n<p><script>\/\/ <![CDATA[\nfunction grabCode_e65c7cf5cb944d9dad032c4efccce190() {\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='e65c7cf5cb944d9dad032c4efccce190 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\n        t2='##### ' + 'SOURCE END' + ' #####' + ' e65c7cf5cb944d9dad032c4efccce190';\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 2008 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.6<\/p>\n<\/div>\n<p><!--\ne65c7cf5cb944d9dad032c4efccce190 ##### SOURCE BEGIN #####\n%% Understanding Object Cleanup\n%\n% Today I would like to introduce a guest blogger, <mailto:nick.haddad@mathworks.com Nick Haddad>, a developer\n% here at The Mathworks who works on Audio & Video related features\n% in MATLAB.  Today he talks about cleaning up different types of objects\n% in MATLAB.\n%\n\n%% DELETE THIS SECTION\nfunction cleanMessyBlogPost\n\n%% Introduction\n% The other day I was reading a <http:\/\/iheartmatlab.blogspot.com\/2008\/07\/sound-card-spectral-analysis.html post>\n% about sound card spectral analysis from the excellent new\n% <http:\/\/iheartmatlab.blogspot.com iheartmatlab blog>.  Beyond being a great\n% post on recording from sound cards, the author ran into an\n% issue involving object lifetime that has tripped me up in the past too.\n%\n% So, today I would like to talk about two types of objects in MATLAB,\n% scoped objects and user-managed objects.  Knowing which kind of object you\n% are working with can avoid all sorts of confusion.  Let's start with a\n% small example.\n\n%% Recording Audio With a Callback\n% Suppose you want to use the\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/audiorecorder.html % |audiorecorder|> object to record some audio from your sound card.\n% The audiorecorder has a property called |TimerFcn|, which allows you to\n% specify a\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/matlab_prog\/f9-39541.html callback function>.\n% This callback function calls a function you specify while you\n% are recording audio.  Here's an example function.\n\nfunction makeRecorder( timerCallback, timerPeriod )\n\n% Create an audio recorder object\nrecObject = audiorecorder();\n\n% Install a callback is called every 'timerPeriod' seconds\nset( recObject, ...\n'TimerFcn', timerCallback, ...\n'TimerPeriod', timerPeriod );\n\n% start recording\nrecord( recObject );\n\nend\n\n%%\n% Once recording has started, the function |timerCallback| is called every\n% |timerPeriod| seconds.  This can be handy for inspecting audio data as it\n% is streaming in.\n%\n% On the face of things the |makeRecorder| function looks like it is ready to run.\n% But, there is one subtlety that causes this function not to work as expected.\n% When the |makeRecorder| function ends, the |recObject| variable goes out of\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/matlab_prog\/f0-38052.html#f0-38068 scope>,\n% is removed from the workspace, and cleans itself up. For an\n% |audiorecorder| object, cleaning up means:\n%\n% * Stop recording\n% * Remove the installed timer callback\n% * Remove all audiorecorder data from memory\n%\n% In this case the |timerCallback| is never called because when |makeRecorder| ends, recording\n% immediately stops and the audiorecorder's timer is shut down.\n%\n% The reason the object is cleaned up is because the lifetime of an\n% |audiorecorder| object is bound by its scope. To keep the object alive you would need\n% to copy the object's local variable out of the |makeRecorder| function.\n\nfunction recObject = makeRecorderBetter( timerCallback, timerPeriod )\n\n% Create an audio recorder object\nrecObject = audiorecorder();\n\n% Install a callback is called every 'timerPeriod' seconds\nset( recObject, ...\n'TimerFcn', timerCallback, ...\n'TimerPeriod', timerPeriod );\n\n% start recording\nrecord( recObject );\n\nend\n\n%%\n% Now |recObject| will be in the workspace of the code that calls\n% |makeRecorder|, which allows the |audiorecorder| to stay alive.\n\n%% Scoped Objects vs. User-Managed Objects\n% The |audiorecorder| object is what I like to call a scoped object because it\n% cleans up after itself when it goes out of scope. Scoped objects are the most common\n% type of object in MATLAB. They behave just like regular scalar and\n% matrix variables.\n\n% Create and clear a scalar\nz = sin(pi);\nclear z;\n\n% Create and clear a 3 x 3 matrix\nM = magic(3);\nclear M;\n\n% Create and clear a timeseries object\nt = timeseries();\nclear t;\n\n%%\n% Clearing the <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/timeseries.html |timeseries|> object\n% above removes the |timeseries| from memory completely, just like clearing\n% a scalar or matrix variable.\n%\n% The reason the |makeRecorder| example above can be confusing is that some objects in MATLAB clean\n% themselves up when they go out of scope, and some don't.  If you try the same type of\n% thing with a timer object, the results are very different.\n\nfunction makeTimer( timerCallback )\n\ntimerObject = timer('TimerFcn',timerCallback, ...\n'Period', 0.25, ...\n'ExecutionMode', 'fixedSpacing' );\nstart( timerObject );\n\nend\n\n%%\n% In this example, the variable |timerObject| goes out of scope at the end of\n% |makeTimer|, but the timer *does not* get cleaned up.  So, the timer fires every 0.25 seconds and the callback\n% function |timerCallback| is called appropriately. Let's test it out.\n\n% Create a timer\nmakeTimer( @(obj, event) display([obj.Name ' fired']) );\n\n% pause for a second to let the timer fire\npause(1);\n\n%%\n% You can see here that the timer fired 4 times in one second, even though\n% I can no longer get to the timer object I created.\n\n%%\n% Timer objects are what I like to call user-managed objects, in that they don't\n% clean up after themselves.  You are responsible for cleaning up a timer\n% by calling the <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/deletetimer.html |delete|>\n% method after you are done with the timer.\n%\n% But, after |makeTimer| ends, the |timerObject| variable is no longer in the workspace,\n% so you will need to find it using the <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/timerfind.html |timerfind|>\n% function.\n\n% find all outstanding timers\ntimers = timerfind();\n\n% stop the timers you find\nstop(timers);\n\n% delete and clear the timers\ndelete(timers);\nclear timers;\n\n%% Why do User-Managed Objects Exist?\n% Using a user-managed object seems like extra work, but you get flexibility over the object's\n% lifetime expressely because it can remain around regardless of a variable's scope.\n% This can be very helpful in several situations, like when you are building GUIs.\n% For example, you could create a timer object in the |CreateFcn| of a\n% figure window which refreshes the figure every second, and then clean up\n% the timer in the figure's |DeleteFcn|.\n%\n% Also, if you are working with a user-managed object and would like to\n% treat it as a scoped object, you can use <https:\/\/www.mathworks.com\/help\/matlab\/ref\/oncleanup.html |onCleanup|>,\n% which was introduced in R2008a.  See Loren's previous post that covers |onCleanup|,\n% <https:\/\/blogs.mathworks.com\/loren\/2008\/03\/10\/keeping-things-tidy Keeping Things Tidy>.\n%\n%\n\n%% Scoped or User-Managed?\n% MATLAB has a lot of different user-managed objects including\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/timer.html |timer|>,\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/toolbox\/daq\/analoginput.html |analoginput|>,\n% and <https:\/\/www.mathworks.com\/help\/imaq\/videoinput.html |videoinput|>\n% to name a few.  Each of these has a corresponding |find| function to help you find\n% objects that have been removed from the workspace but are still hanging around in\n% memory.\n%\n% If you are struggling to figure out if an object is scoped or user-managed,\n% follow these guidelines:\n%\n% * Assume the object you are using is a scoped object and will tidy up\n% after itself.\n% * If an object's documentation mentions a |delete| function, it might\n% be a user managed object.\n% * If an object's documentation has a |xxxfind| method (|timerfind|, |daqfind|, etc.), it is most likely a user-managed object.\n%\n% Regardless of the guidelines above, it is good just to know that scoped objects and\n% user-managed objects exist in MATLAB and that there are differences between the behavior\n% of each.\n%\n%\n\n%% Has this ever happened to you?\n% Have you ever run into issues with user-managed objects?  Has an object\n% in MATLAB ever been cleaned up when you weren't expecting it too?  Share\n% you experiences <https:\/\/blogs.mathworks.com\/loren\/?p148#respond here>.\n\n%% DELETE THIS SECTION\n%\nend\n##### SOURCE END ##### e65c7cf5cb944d9dad032c4efccce190\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\nToday I would like to introduce a guest blogger, Nick Haddad, a developer here at The Mathworks who works on Audio &amp; Video related features in MATLAB. Today he talks about cleaning<br \/>\nup different... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2008\/07\/29\/understanding-object-cleanup\/\">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":[14,44],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/148"}],"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=148"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/148\/revisions"}],"predecessor-version":[{"id":1832,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/148\/revisions\/1832"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=148"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}