diff m-toolbox/classes/@ltpda_uoh/report.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ltpda_uoh/report.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,800 @@
+% REPORT generates an HTML report about the input objects.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: REPORT generates an HTML report about the input objects.
+%
+% CALL:        report(objs);
+%              report(objs, options);
+%
+% INPUTS:      objs    - LTPDA objects
+%              options - a plist of options
+%
+% PARAMETERS:
+%              'dir'     - report dir [default: <temp dir>/ltpda_report/<date><time>]
+%              'extras'  - true [default] or false: plot data and diagrams
+%                          for objects, output mfile, and type() output.
+%              'desc'    - give a description to appear on the main report
+%                          page.
+%              'save'    - include saved versions of the objects in the
+%                          report directory. Objects are saved as XML.
+%                          Specify with true or false [default]
+%              'zip'     - compress the report directory to a ZIP file
+%              'plots'   - specify a cell-array of objects to build
+%                          plots on the main page. Each cell gets its
+%                          own plot. Example: {[a1, a3], {a5}}.
+%              'overwrite' - overwrite the report directory if it exists.
+%                            Specify true or false [default].
+%
+% <a href="matlab:utils.helper.displayMethodInfo('ltpda_uoh', 'report')">Parameters Description</a>
+%
+% VERSION:     $Id: report.m,v 1.20 2011/04/08 08:56:30 hewitson Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = report(varargin)
+
+  % starting initial checks
+  utils.helper.msg(utils.const.msg.MNAME, ['running ', mfilename]);
+
+  % Check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+
+  % Collect input variable names
+  in_names = cell(size(varargin));
+  for ii = 1:nargin,in_names{ii} = inputname(ii);end
+
+  % Collect all objs and plists
+  objs = {};
+  objnames = {};
+  classes = utils.helper.ltpda_userclasses;
+  for jj=1:numel(classes)
+    try
+      % can I create this type of class?
+      feval(classes{jj});
+      [oos, obj_invars] = utils.helper.collect_objects(varargin(:), classes{jj}, in_names);
+      if ~isempty(oos) && ~isa(oos, 'plist')
+        objs = [objs {oos}];
+        objnames = [objnames obj_invars];
+      end
+    end
+  end
+  % get plist
+  pl = utils.helper.collect_objects(varargin(:), 'plist');
+  pl = combine(pl, getDefaultPlist('Default'));
+
+  % Get options
+  outdir = find(pl, 'dir');
+  plotOn = find(pl, 'extras');
+  saveXML = find(pl, 'save');
+  compress = find(pl, 'zip');
+  groupPlot = find(pl, 'plots');
+
+  % Create output dir
+  if isempty(outdir)
+    outdir = fullfile(tempdir, 'ltpda_report', datestr(now, 30));
+  elseif (outdir == '.')
+    outdir = fullfile('ltpda_report', datestr(now, 30));
+  end
+  
+  % Does the directory exist?
+  if find(pl, 'overwrite')
+    if exist(outdir, 'dir') ~= 0
+      [success, msg, msgid] = rmdir(outdir, 's');
+      if ~success, disp(msg), return, end
+    end
+  else % check with the user
+    if exist(outdir, 'dir') == 7
+      disp('The requested report directory already exists.')
+      r = input('Do you want to overwrite it? [y/n]  ', 's');
+      if strcmpi(r, 'y')
+        [success, msg, msgid] = rmdir(outdir, 's');
+        if ~success, disp(msg), return, end
+      else
+        return
+      end
+    end
+  end
+  mkdir(outdir);
+  mkdir(fullfile(outdir, 'images'));
+
+  % Write .html file
+  indexFile = fullfile(outdir, 'index.html');
+  fd = fopen(indexFile, 'w+');
+
+  header = getHeader();
+  footer = getFooter();
+
+  % write header
+  fprintf(fd, header);
+
+  % write description
+  desc = find(pl, 'desc');
+  if ~iscell(desc), desc = {desc}; end
+  for kk=1:numel(desc)
+    fprintf(fd, '<p>%s</p>\n', desc{kk});
+  end
+
+  % write index entry
+  fprintf(fd, '<br><h2><a name="toc">Table of Contents</a></h2>\n');
+  [s, htmlfiles] = writeTableOfContents(objs, objnames);
+  fprintf(fd, s);
+
+  % Group plot?
+  if ~isempty(groupPlot)
+    % go through each cell - one plot per cell
+    for kk=1:numel(groupPlot)
+      % get objects
+      group = groupPlot{kk};
+      fprintf(fd, '<hr>\n');
+      fprintf(fd, '<h2>Plot %d</h2>', kk);
+      if isa(group, 'ao')
+        imname = 'images/groupplot_001.png';
+        n = 1;
+        while exist(fullfile(outdir, imname),'file')
+          n = n + 1;
+          imname = sprintf('images/groupplot_%03d.png', n);
+        end
+        % make a plot
+        hfig = iplot(group);
+        % make image
+        saveas(hfig, fullfile(outdir, imname));
+        % make link
+        fprintf(fd, '<img src="%s" alt="Plot" width="800px" border="3">\n', imname);
+        close(hfig);
+      else
+
+      end
+    end
+  end
+
+  % write individual html files
+  writeObjFiles(fd, objs, htmlfiles, header, footer, outdir, plotOn, saveXML);
+
+  % reportee info
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<br><h2>report created by:</h2>\n');
+  s = obj2table(provenance, outdir);
+  fprintf(fd, s);
+
+  fprintf(fd, '\n');
+  fprintf(fd, '\n');
+  % write footer
+  fprintf(fd, footer);
+  % Close
+  fclose(fd);
+
+  % copy stylesheet
+  dp = which('docstyle.css');
+  copyfile(dp, outdir);
+  copyfile(dp, fullfile(outdir, 'html'));
+
+  % zip ?
+  if compress
+    zip([outdir '.zip'], outdir);
+  end
+
+  % open report
+  if isempty(pl.find('dir'))
+    web(fullfile('file:///', outdir, 'index.html'))
+  else
+    web(fullfile('file:///', pwd, outdir, 'index.html'))
+  end
+
+  utils.helper.msg(utils.const.msg.PROC1, 'report written to %s', outdir);
+  if nargout == 1
+    varargout{1} = outdir;
+  end
+
+end
+
+%--------------------------------------------------------------------------
+% Write provenance info
+%
+function s = obj2table(obj, reportDir)
+
+  % prepare table
+  s =    sprintf('<p>\n\t');
+  s = [s sprintf('  <table border="1" cellspacing="0" cellpadding="0" width="1%%%%">\n')];
+  s = [s sprintf('    <tr valign="top">\n')];
+  s = [s sprintf('      <td align="center" valign="top">\n')];
+  s = [s sprintf('        <table border="0" cellspacing="0" cellpadding="3" width="100%%%%">\n')];
+  s = [s sprintf('          <colgroup>\n')];
+  s = [s sprintf('            <col width="1%%%%">\n')];
+  s = [s sprintf('            <col width="1%%%%">\n')];
+  s = [s sprintf('          </colgroup>\n')];
+  s = [s sprintf('          <thead>\n')];
+  s = [s sprintf('            <tr valign="top" bgcolor="#000000">\n')];
+  s = [s sprintf('              <td align="center" colspan="2"><font color="#FFFFFF">%s</font></td></tr>\n', upper(class(obj)))];
+  s = [s sprintf('            <tr bgcolor="#B2B2B2"valign="top">\n')];
+  s = [s sprintf('              <th>Property</th>\n')];
+  s = [s sprintf('              <th>Value</th>\n')];
+  s = [s sprintf('            </tr>\n')];
+  s = [s sprintf('          </thead>\n')];
+  s = [s sprintf('          <tbody>\n')];
+  props = properties(obj);
+  cols = {'#E9E9E9', '#FFFFFF'};
+  for jj=1:numel(props)
+    prop = props{jj};
+    val  = obj.(prop);
+    s = [s sprintf('            <tr valign="top" bgcolor="%s">\n', cols{mod(jj,2)+1})];
+    s = [s sprintf('              <td><h4><font color="#890022"><i>%s</i></font></h4></td>\n', props{jj})];
+    %---- EXCEPTIONS -------%
+    if isempty(val)
+      valstr = '<font color="#0003B6"><i>empty</i></font>';
+    else
+      if strcmp(prop, 'mfile')
+        valstr = '<i>see above</i>';
+      elseif strcmp(prop, 'mdlfile')
+        valstr = '<i>SIMULINK model file</i>';
+      else
+        valstr = val2html(val, reportDir);
+      end
+    end
+    s = [s sprintf('              <td>%s</td>\n', valstr)];
+    s = [s sprintf('            </tr>\n')];
+  end
+  s = [s sprintf('          </tbody>\n')];
+  s = [s sprintf('        </table>\n')];
+  s = [s sprintf('      </td>\n')];
+  s = [s sprintf('    </tr>\n')];
+  s = [s sprintf('  </table>\n')];
+  s = [s sprintf('</p>\n')];
+end
+
+
+%--------------------------------------------------------------------------
+% Convert a MATLAB type to an html string
+%
+function s = val2html(val, reportDir)
+  MAX_STR_LENGTH = 50;
+  MAX_NUM_LENGTH = 10;
+  if ischar(val) % String
+    s = ['<font color="#49B64B">' strtrunc(val, MAX_STR_LENGTH) '</font>'];
+  elseif iscell(val) % Symbol
+    cs = size(val);
+    if numel(val) == 1
+      s = val2html(val{1});
+    else
+      s = '<table border="1" cellpadding="2" cellspacing="0">\n';
+      s = [s sprintf('  <thead>\n')];
+      s = [s sprintf('    <tr  valign="top">\n')];
+      s = [s sprintf('<th bgcolor="#8BCEC3"></th>')];
+      for jj=1:cs(2) % loop over columns
+        s = [s sprintf('<th bgcolor="#8BCEC3">%d</th>', jj)];
+      end
+      s = [s sprintf('    </tr>\n')];
+      s = [s sprintf('  </thead>\n')];
+      for jj=1:cs(1)
+        s = [s '<tr>\n'];
+        s = [s sprintf('<th bgcolor="#8BCEC3">%d</th>', jj)];
+        for kk=1:cs(2)
+          s = [s '<td align="center" valign="middle" >\n'];
+          s = [s val2html(val{jj,kk})];
+          s = [s '</td>\n'];
+        end
+        s = [s '</tr>\n'];
+      end
+      s = [s '</table>\n'];
+    end
+  %%%%%%%% SYMBOLS
+  elseif isa(val, 'sym')
+
+    if numel(val) == 1
+      s = strtrunc(char(sym), 50);
+    else
+      cs = size(val);
+      s = '<table border="1" width="600px" cellpadding="3" cellspacing="0">\n';
+      s = [s sprintf('  <thead>\n')];
+      s = [s sprintf('    <tr  valign="top">\n')];
+      s = [s sprintf('<th bgcolor="#B2B2B2"></th>')];
+      for jj=1:cs(2) % loop over columns
+        s = [s sprintf('<th bgcolor="#B2B2B2">%d</th>', jj)];
+      end
+      s = [s sprintf('    </tr>\n')];
+      s = [s sprintf('  </thead>\n')];
+
+      for jj=1:cs(1) % loop over rows
+        s = [s '<tr>\n'];
+        s = [s sprintf('<th bgcolor="#B2B2B2">%d</th>', jj)];
+        for kk=1:cs(2) % loop over columns
+          s = [s '<td align="center" valign="middle" >\n'];
+          s = [s '<font color="#6969B6">' strtrunc(char(val(jj,kk)),50) '</font>'];
+          s = [s '</td>\n'];
+        end
+        s = [s '</tr>\n'];
+      end
+      s = [s '</table>\n'];
+    end
+  elseif isa(val, 'ltpda_obj') % LTPDA object
+    if isa(val, 'history')
+      % make image
+      imname = 'images/hist_img_001.png';
+      n = 1;
+      while exist(fullfile(reportDir, imname),'file')
+        n = n + 1;
+        imname = sprintf('images/hist_img_%03d.png', n);
+      end
+      % make image
+      dotview(val, plist('filename', fullfile(reportDir, imname), 'view', false, 'format', 'png'));
+      % make link
+      s = sprintf('<img src="%s" alt="History Plot" border="3">\n', imname);
+    elseif isa(val, 'unit') || isa(val, 'time') || isa(val, 'plist')
+      s = mask_special_char(char(val));
+    else
+      s = obj2table(val, reportDir);
+    end
+  elseif islogical(val)
+    if val
+      s = '<i>true</i>';
+    else
+      s = '<i>false</i>';
+    end
+  elseif isnumeric(val) % Numbers
+    if isempty(val)
+      s = '<font color="#0003B6"><i>empty</i></font>';
+    else
+      if numel(val) > 1
+        s = [sprintf('<font color="#0003B6"><tt><font color="#000000">[%dx%d]</font>', size(val,1), size(val,2)) mat2str(val(1:min(numel(val), MAX_NUM_LENGTH)), 4)];
+      else
+        s = ['<font color="#0003B6"><tt>' mat2str(val(1:min(numel(val), MAX_NUM_LENGTH)), 4)];
+      end
+      if numel(val) > MAX_NUM_LENGTH
+        s = [s '...'];
+      end
+      s = [s '</tt></font>'];
+    end
+  else
+    s = strtrunc(char(val), MAX_STR_LENGTH);
+  end
+
+end
+
+
+function txt = Cell2String(c)
+  % recursive code to print the content of cell arrays
+  if iscell(c) % for a cell
+    txt = '';%;
+    for i=1:size(c,1)
+      if i==1
+        txti = '{';
+      else
+        txti = ' ';
+      end
+      for j=1:size(c,2)
+        txti = [txti ' ' Cell2String(c{i,j})];
+      end
+      if i==size(c,1)
+        txti = [txti, ' }'];
+      end
+      txt = strvcat(txt, txti);
+    end
+  elseif isa(c, 'sym')
+    txt = char(c);
+  elseif islogical(c) % for a logical
+    txt = mat2str(c);
+  elseif isnumeric(c)||isa(c,'sym') % for a numerical array, only size is displayed
+    if size(c,1)+size(c,2)==0 % for 0x0 array
+      txt = '  []   ';
+    elseif isa(c,'double') && (norm(c)==0) % for zero array (test dos not carsh for sym)
+      txt = '  []   ';
+    else % for non empty array
+      if size(c,1)>9
+        txt1 = ['[',num2str(size(c,1))];
+      else
+        txt1 = [' [',num2str(size(c,1))];
+      end
+      if size(c,2)>9
+        txt2 = [num2str(size(c,2)),']'];
+      else
+        txt2 = [num2str(size(c,2)),'] '];
+      end
+      txt = [txt1,'x',txt2 ];
+    end
+    % txt = mat2str(c); % old display
+  elseif ischar(c)
+    txt = ['''' c ''''];
+  else
+    txt = char(c);
+  end
+end
+
+%--------------------------------------------------------------------------
+% Truncate a string
+%
+function s = strtrunc(s, n)
+  sl = length(s);
+  s  = s(1:min(sl, n));
+  if sl > n
+    s = [s '...'];
+  end
+  s = mask_special_char(s);
+end
+
+%--------------------------------------------------------------------------
+% Mask the special characters '<', '>' and &
+%
+% '<' with '&lt;'
+% '>' with '&gt;'
+% '&' with '&amp;'
+%
+function s = mask_special_char(s)
+  s = strrep(s, '&' ,'&amp;');
+  s = strrep(s, '<', '&lt;');
+  s = strrep(s, '>' ,'&gt;');
+end
+
+%--------------------------------------------------------------------------
+% Write a table of contents for the input objects
+%
+function [s, filenames] = writeTableOfContents(objs, objnames)
+
+  filenames = {};
+
+  % start table
+  s =    sprintf('<p>\n\t');
+  s = [s sprintf('  <table border="1" cellspacing="0" cellpadding="0" width="20%%%%">\n')];
+  s = [s sprintf('    <tr valign="top">\n')];
+  s = [s sprintf('      <td valign="top">\n')];
+  s = [s sprintf('        <table border="0" cellspacing="0" cellpadding="1" width="100%%%%">\n')];
+  s = [s sprintf('          <colgroup>\n')];
+  s = [s sprintf('            <col width="1%%%%">\n')];
+  s = [s sprintf('            <col width="1%%%%">\n')];
+  s = [s sprintf('          </colgroup>\n')];
+  s = [s sprintf('          <thead>\n')];
+  s = [s sprintf('            <tr valign="top">\n')];
+  s = [s sprintf('              <th bgcolor="#B2B2B2">obj #</th>\n')];
+  s = [s sprintf('              <th bgcolor="#B2B2B2">link</th>\n')];
+  s = [s sprintf('            </tr>\n')];
+  s = [s sprintf('          </thead>\n')];
+  s = [s sprintf('          <tbody>\n')];
+
+  cols = {'#E9E9E9', '#FFFFFF'};
+  nn = 1;
+  for jj=1:numel(objs)
+    for kk=1:numel(objs{jj})
+      obj = objs{jj}(kk);
+      % make filename
+      filenames{nn} = sprintf('obj_%03d', nn);
+      % write table entry
+      s = [s sprintf('            <tr valign="top" bgcolor="%s">\n', cols{mod(nn,2)+1})];
+      s = [s sprintf('              <td><font color="#890022">%03d</font></td>\n', nn)];
+      s = [s sprintf('              <td><a href="index.html#%s">%s [%s]</a></td>\n', filenames{nn}, strtrunc(objnames{nn}, 30), class(obj))];
+      s = [s sprintf('            </tr>\n')];
+      nn = nn + 1;
+    end
+  end
+  s = [s sprintf('            </tr>\n')];
+  s = [s sprintf('          </tbody>\n')];
+  s = [s sprintf('        </table>\n')];
+  s = [s sprintf('      </td>\n')];
+  s = [s sprintf('    </tr>\n')];
+  s = [s sprintf('  </table>\n')];
+  s = [s sprintf('</p>\n')];
+end
+
+
+function s = getFooter()
+  s = '</body>\n</html>\n';
+end
+
+function s = getHeader()
+  s = '';
+
+  % write HTML header
+  s = [s sprintf('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"\n')];
+  s = [s sprintf('"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">\n')];
+  s = [s sprintf('<html lang="en">\n')];
+  s = [s sprintf('<head>\n')];
+  s = [s sprintf('<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">\n')];
+  s = [s sprintf('\n')];
+  s = [s sprintf('\n')];
+
+  % Page Title
+  pageTitle = ['LTPDA Report from ' datestr(now)];
+  s = [s sprintf('<title>%s</title>\n', pageTitle)];
+  s = [s sprintf('<link rel="stylesheet" href="docstyle.css" type="text/css">\n')];
+  s = [s sprintf('<meta name="generator" content="DocBook XSL Stylesheets V1.52.2">\n')];
+  s = [s sprintf('<meta name="description" content="Presents details of an LTPDA object.">\n')];
+  s = [s sprintf('</head>\n')];
+  s = [s sprintf('\n')];
+  s = [s sprintf('\n')];
+  s = [s sprintf('<body>\n')];
+  s = [s sprintf('<a name="top"><table cellpadding="5" cellspacing="0" width="100%%%%" bgcolor="#F9E767"><tr><td>\n')];
+  s = [s sprintf('  <h1 class="title">%s</h1></td></tr></table>\n\n', pageTitle)];
+  s = [s sprintf('<hr><br></a>\n\n')];
+
+end
+
+%--------------------------------------------------------------------------
+% Write html file for each object
+%
+function writeObjFiles(fd, objs, filenames, header, footer, outdir, plotOn, saveXML)
+
+  % Loop over objects
+  nn = 1;
+  for jj=1:numel(objs)
+    for kk=1:numel(objs{jj})
+      % get object
+      obj = objs{jj}(kk);
+
+      % Object name
+      fprintf(fd, '<table width="100%%%%" bgcolor="#F9F19B" cellpadding="5" cellspacing="0"><tr><td>\n');
+      fprintf(fd, '<h1><a name="%s">Name: %s</a></h1>\n', filenames{nn}, mask_special_char(obj.name));
+      fprintf(fd, '</td></tr></table>\n');
+      fprintf(fd, '<p><h3><a href="index.html#top">Back to Top</a></h3></p>\n');
+      fprintf(fd, '<hr>\n');
+      fprintf(fd, '<h2>Class: %s</h2>\n', class(obj));
+
+      % Description
+      if isprop(obj, 'description')
+        fprintf(fd, '<hr>\n');
+        fprintf(fd, '<h2>Description</h2>\n');
+        if isempty(obj.description)
+          fprintf(fd, '<i>none</i>\n');
+        else
+          fprintf(fd, '<p>%s</p>\n', mask_special_char(obj.description));
+        end
+      end
+
+      % Additional stuff
+      if plotOn
+        if isa(obj, 'ao')
+          writeAOextras(obj, fd, outdir);
+        elseif isa(obj, 'miir')
+          writeMIIRextras(obj, fd, outdir);
+        elseif isa(obj, 'mfir')
+          writeMFIRextras(obj, fd, outdir);
+        elseif isa(obj, 'pzmodel')
+          writePZMODELextras(obj, fd, outdir);
+        elseif isa(obj, 'ssm')
+          writeSSMextras(obj, fd, outdir)
+        else
+          % no extras for this type
+        end
+      end
+
+      % write object table
+      fprintf(fd, '<hr>\n');
+      fprintf(fd, '<h2>Object Table View</h2>\n');
+      s = obj2table(obj, outdir);
+      fprintf(fd, s);
+
+      fprintf(fd, '<p><h3><a href="index.html#top">Back to Top</a></h3></p>\n');
+
+      % save XML ?
+      if saveXML
+        [path, name, ext] = fileparts(filenames{nn});
+        xmldir = fullfile(outdir, 'xml');
+        mkdir(xmldir);
+        xmlfile = fullfile(xmldir, [name '.xml']);
+        save(obj, xmlfile);
+      end
+      nn = nn + 1;
+    end % End loop over objects
+  end % Loop over object types
+end
+
+%--------------------------------------------------------------------------
+% Write extra bits for SSM
+%
+function writeSSMextras(obj, fd, outdir)
+
+  %-----------------------------------------------
+  % make dot view
+  % make image
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>Block Diagram</h2>\n');
+  imname = 'images/ssm_img_001.png';
+  n = 1;
+  while exist(fullfile(outdir, imname),'file')
+    n = n + 1;
+    imname = sprintf('images/ssm_img_%03d.png', n);
+  end
+  % make image
+  dotview(obj, plist('filename', fullfile(outdir, imname), 'view', false, 'format', 'png'));
+  % make link
+  fprintf(fd, '<p><img src="%s" alt="SSM Diagram" border="3"></p>\n', imname);
+
+end
+%--------------------------------------------------------------------------
+% Write extra bits for MIIR
+%
+function writeMIIRextras(obj, fd, outdir)
+
+  %-----------------------------------------------
+  % plot response
+  % make image
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>Response</h2>\n');
+  imname = 'images/resp_img_001.png';
+  n = 1;
+  while exist(fullfile(outdir, imname),'file')
+    n = n + 1;
+    imname = sprintf('images/resp_img_%03d.png', n);
+  end
+  % make a plot
+  r = resp(obj);
+  hfig = iplot(r);
+  % make image
+  if ~isempty(hfig)
+    saveas(hfig, fullfile(outdir, imname));
+    % make link
+    fprintf(fd, '<p><img src="%s" alt="MIIR Response" width="800px" border="3"></p>\n', imname);
+    close(hfig);
+  else
+    fprintf(fd, '<p><font color="#0003B6"><i>empty</i></font></p>\n');
+  end
+
+end
+%--------------------------------------------------------------------------
+% Write extra bits for MFIR
+%
+function writeMFIRextras(obj, fd, outdir)
+
+  %-----------------------------------------------
+  % plot response
+  % make image
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>Response</h2>\n');
+  imname = 'images/resp_img_001.png';
+  n = 1;
+  while exist(fullfile(outdir, imname),'file')
+    n = n + 1;
+    imname = sprintf('images/resp_img_%03d.png', n);
+  end
+  % make a plot
+  hfig = iplot(resp(obj));
+  % make image
+  if ~isempty(hfig)
+    saveas(hfig, fullfile(outdir, imname));
+    % make link
+    fprintf(fd, '<p><img src="%s" alt="MFIR Response" width="800px" border="3"></p>\n', imname);
+    close(hfig);
+  else
+    fprintf(fd, '<p><font color="#0003B6"><i>empty</i></font></p>\n');
+  end
+
+end
+%--------------------------------------------------------------------------
+% Write extra bits for pzmodels
+%
+function writePZMODELextras(obj, fd, outdir)
+
+  %-----------------------------------------------
+  % plot response
+  % make image
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>Response</h2>\n');
+  imname = 'images/resp_img_001.png';
+  n = 1;
+  while exist(fullfile(outdir, imname),'file')
+    n = n + 1;
+    imname = sprintf('images/resp_img_%03d.png', n);
+  end
+  % make a plot
+  hfig = iplot(resp(obj));
+  % make image
+  if ~isempty(hfig)
+    saveas(hfig, fullfile(outdir, imname));
+    % make link
+    fprintf(fd, '<p><img src="%s" alt="PZMODEL Response" width="800px" border="3"></p>\n', imname);
+    close(hfig);
+  else
+    fprintf(fd, '<p><font color="#0003B6"><i>empty</i></font></p>\n');
+  end
+end
+%--------------------------------------------------------------------------
+% Write extra bits for AOs
+%
+function writeAOextras(obj, fd, outdir)
+
+  %-------------------------------------------
+  % PLOT
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>Plot</h2>\n');
+  imname = 'images/ao_img_001.png';
+  n = 1;
+  while exist(fullfile(outdir, imname),'file')
+    n = n + 1;
+    imname = sprintf('images/ao_img_%03d.png', n);
+  end
+  % make a plot
+  hfig = iplot(obj);
+  % make image
+  if ~isempty(hfig)
+    saveas(hfig, fullfile(outdir, imname));
+    % make link
+    fprintf(fd, '<p><img src="%s" alt="AO Plot" width="800px" border="3"></p>\n', imname);
+    close(hfig);
+  else
+    fprintf(fd, '<p><font color="#0003B6"><i>empty</i></font></p>\n');
+  end
+
+  %-------------------------
+  % Output of type
+  if ~isempty(obj.hist)
+    cmds = hist2m(obj.hist, plist('stop_option', 'full'));
+    txt = mfile2html(cmds(end:-1:1));
+  else
+    txt = '<p><font color="#0003B6"><i>empty</i></font></p>';
+  end
+  fprintf(fd, '<hr>\n');
+  fprintf(fd, '<h2>History dump</h2>\n');
+  fprintf(fd, '<br><p>This is the output of <tt>type(<i>object</i>)</tt></p>\n');
+  fprintf(fd, '<p><div class="fragment"><pre>\n');
+  fprintf(fd, '\n%s', txt);
+  fprintf(fd, '</pre></div></p>\n');
+
+end
+
+%--------------------------------------------------------------------------
+% Reformat an mfile contained in a cell array to be output as html
+function txt = mfile2html(mfile)
+    % add format tags
+    for kk=1:numel(mfile)
+      % make strings
+
+      % Mask '&' in the strings
+      mfile{kk} = regexprep(mfile{kk}, '(''[^'']*'')', '${strrep($1, ''&'', ''&amp;'')}');
+      % Mask '>' in the strings
+      mfile{kk} = regexprep(mfile{kk}, '(''[^'']*'')', '${strrep($1, ''>'', ''&gt;'')}');
+      % Mask '<' in the strings
+      mfile{kk} = regexprep(mfile{kk}, '(''[^'']*'')', '${strrep($1, ''<'', ''&lt;'')}');
+      mfile{kk} = regexprep(mfile{kk}, '''([^''\\]*(\\.[^''\\]*)*)''', '<span class="string">''$1''</span>');
+      % make comments
+      idx = strfind(mfile{kk}, '%');
+      if ~isempty(idx)
+        mfile{kk} = [mfile{kk}(1:idx(1)-1) '<span class="comment">' mfile{kk}(idx(1):end) '</span>'];
+      end
+    end
+    % reformat into a big string
+    txt = sprintf([repmat('%s\t',1,size(mfile,1)),'\n'],mfile{:});
+    txt = strrep(txt, '`', '''');
+end
+
+%--------------------------------------------------------------------------
+% Get Info
+%
+function ii = getInfo(varargin)
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pls   = [];
+  elseif nargin == 1 && ~isempty(varargin{1}) && ischar(varargin{1})
+    sets{1} = varargin{1};
+    pls = getDefaultPlist(sets{1});
+  else
+    sets = {'Default'};
+    pls = [];
+    for kk=1:numel(sets)
+      pls = [pls getDefaultPlist(sets{kk})];
+    end
+  end
+  % Build info object
+  ii = minfo(mfilename, 'ltpda_uoh', 'ltpda', utils.const.categories.output, '$Id: ', sets, pls);
+  ii.setModifier(false);
+  ii.setOutmin(0);
+end
+
+function plout = getDefaultPlist(set)
+  persistent pl;
+  persistent lastset;
+  if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set)
+    pl = buildplist(set);
+    lastset = set;
+  end
+  plout = pl;
+end
+
+function plo = buildplist(set)
+  switch lower(set)
+    case 'default'
+      plo = plist('dir', '', 'extras', true, 'desc', '', ...
+                  'save', false, 'zip', false, 'plots', {}, ...
+                  'overwrite', false);
+    otherwise
+      error('### Unknown parameter set [%s].', set);
+  end
+end
+