function [xmlStruct, map] = transformXML2Map(fileName)
% Create a MATLAB structure from a given XML file.
% The XML file is first parsed through the "xml2struct" function and
% then transformed into a structure. The content of this structure can be
% found in the [description document](https://github.com/opencobra/cobratoolbox/blob/master/docs/source/notes/simpleMATLABStructure.md)
%
% USAGE:
%
%   [xmlStruct, map] = transformXML2Map(fileName)
%
% INPUT:
%   fileName:       Path to the XML file.
%
% OUTPUTS:
%   xmlStruct:      Structure obtained from the "xml2struct" function.
%                   To be kept for the conversion back to an XML file
%                   of the structure.
%   map:            Matlab structure of the map containing all the
%                   relevant fields usable for checking and correction.
%
%                * sID -  Stoichiometric matrix with `rows = MetabolitesID` and
%                  `columns = ReactionsID` in the same order as in the map
%                  structure. Contains `-1` if the metabolite is a
%                  reactant/substract, `+1` if the metabolite is a product
%                  and `0` if it does not participate in the reaction.
%                * sAlias - Stoichiometric matrix with `rows = MetabolitesAlias` and
%                  `columns = ReactionsID` in the same order as in the map
%                  structure. Contains `-1` if the metabolite is a
%                  reactant/substract, `+1` if the metabolite is a product
%                  and `0` if it does not participate in the reaction.
%                * idAlias - Logical matrix with `rows = MetabolitesID` and
%                  `columns = MetabolitesAlias`. Contains `+1` if the
%                  `MetaboliteID` match with the `MetaboliteAlias` and `0`
%                  if it doesn't.
%
% .. Author: - N.Sompairac - Institut Curie, Paris, 24/07/2017

tic

% Works nicely but has a huge tree structured

if strcmp('~',fileName(1))
    savedPath=pwd;
    cd('~')
    homePath=pwd;
    fileName = strrep(fileName,'~',homePath);
    cd(savedPath)
end

xmlStruct = xml2struct(fileName);

% Loop over molecules to get the needed information and store it in a
% structure. Molecules refer to each individual node.
for mol = 1:length(xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias)
    map.molAlias{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.id;
    map.molID{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.species;
    % Check if the info on compartment exists
    if any(strcmp('compartmentAlias', fieldnames(xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes)))
        map.molCompartAlias{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.compartmentAlias;
    else
        map.molCompartAlias{mol, 1} = '';
    end
    map.molXPos{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.x;
    map.molYPos{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.y;
    map.molWidth{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.w;
    map.molHeight{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.h;
    map.molColor{mol, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_usualView.celldesigner_colon_paint.Attributes.color;
end
clearvars mol

% Loop over species to get the needed information and store it in a
% structure. Species refer to each individual name.
for spec = 1:length(xmlStruct.sbml.model.listOfSpecies.species)
    map.specID{spec, 1} = xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.id;
    map.specMetaID{spec, 1} = xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.metaid;
    map.specName{spec, 1} = xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.name;
    map.specType{spec, 1} = xmlStruct.sbml.model.listOfSpecies.species{spec}.annotation.celldesigner_colon_extension.celldesigner_colon_speciesIdentity.celldesigner_colon_class.Text;
    % Check if the info on notes exists for the specie
    if any(strcmp('notes', fieldnames(xmlStruct.sbml.model.listOfSpecies.species{spec})))
        map.specNotes{spec, 1} = xmlStruct.sbml.model.listOfSpecies.species{spec}.notes.html.body.Text;
    else
        map.specNotes{spec, 1} = '';
    end
end
clearvars spec

% Loop over reactions to get the need information and store it in a
% structure. Reactions refer to each individual reaction name.
for react = 1:length(xmlStruct.sbml.model.listOfReactions.reaction)
    % Test if the reaction has an ID
    if any(strcmp('id', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes)))
        map.rxnID{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.id;
    else
        map.rxnID{react, 1} = '';
    end
    map.rxnMetaID{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.metaid;
    % Test if the reaction has a Name
    if any(strcmp('name', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes)))
        map.rxnName{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.name;
    else
        map.rxnName{react, 1} = '';
    end
    map.rxnType{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_reactionType.Text;
    % Check if info on reversibility exists
    if any(strcmp('reversible', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes)))
        map.rxnReversibility{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.reversible;
    else
        map.rxnReversibility{react, 1} = 'true';
    end
    map.rxnBaseReactantAlias{react, 1} = {};
    map.rxnBaseReactantID{react, 1} = {};
    % Test if there is only 1 base reactant
    if length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant) == 1
        map.rxnBaseReactantAlias{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant.Attributes.alias;
        map.rxnBaseReactantID{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant.Attributes.species;
    else
        % Looping over the multiple base reactants
        for base = 1:length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant)
            map.rxnBaseReactantAlias{react, 1}{base, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant{base}.Attributes.alias;
            map.rxnBaseReactantID{react, 1}{base, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant{base}.Attributes.species;
        end
        clearvars base
    end
    map.rxnBaseProductAlias{react, 1} = {};
    map.rxnBaseProductID{react, 1} = {};
    % Test if there is only 1 base product
    if length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct) == 1
        map.rxnBaseProductAlias{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct.Attributes.alias;
        map.rxnBaseProductID{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct.Attributes.species;
    else
        % Looping over the multiple base products
        for base = 1:length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct)
            map.rxnBaseProductAlias{react, 1}{base, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct{base}.Attributes.alias;
            map.rxnBaseProductID{react, 1}{base, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct{base}.Attributes.species;
        end
        clearvars base
    end
    % Test if there are some reactants in the reaction
    if any(strcmp('celldesigner_colon_listOfReactantLinks', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension)))
        map.rxnReactantAlias{react, 1} = {};
        map.rxnReactantID{react, 1} = {};
        % Test if there is only 1 reactant
        if length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink) == 1
            map.rxnReactantAlias{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink(1).Attributes.alias;
            map.rxnReactantID{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink(1).Attributes.reactant;
        else
            for x = 1:length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink)
                map.rxnReactantAlias{react, 1}{x, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.Attributes.alias;
                map.rxnReactantID{react, 1}{x, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.Attributes.reactant;
            end
            clearvars x
        end
    else
        map.rxnReactantAlias{react, 1} = '';
        map.rxnReactantID{react, 1} = '';
    end
    % Test if there are some products in the reaction
    if any(strcmp('celldesigner_colon_listOfProductLinks', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension)))
        map.rxnProductAlias{react, 1} = {};
        map.rxnProductID{react, 1} = {};
        % Test if there is only 1 product
        if length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink) == 1
            map.rxnProductAlias{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink(1).Attributes.alias;
            map.rxnProductID{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink(1).Attributes.product;
        else
            for x = 1:length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink)
                map.rxnProductAlias{react, 1}{x, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.Attributes.alias;
                map.rxnProductID{react, 1}{x, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.Attributes.product;
            end
            clearvars x
        end
    else
        map.rxnProductAlias{react, 1} = '';
        map.rxnProductID{react, 1} = '';
    end
    % Check if there are modifications for the reaction
    if any(strcmp('listOfModifiers', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react})))
        % Test if there is only one modification
        if length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification) == 1
            map.rxnModAlias{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.aliases;
            map.rxnModID{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.modifiers;
            map.rxnModType{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.type;
            map.rxnModColor{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).celldesigner_colon_line.Attributes.color;
            map.rxnModWidth{react, 1}{1, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).celldesigner_colon_line.Attributes.width;
        else
            % Loop over the possible modifications
            for mod = 1:length(xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification)
                map.rxnModAlias{react, 1}{mod, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{mod}.Attributes.aliases;
                map.rxnModID{react, 1}{mod, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{mod}.Attributes.modifiers;
                map.rxnModType{react, 1}{mod, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{mod}.Attributes.type;
                map.rxnModColor{react, 1}{mod, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{mod}.celldesigner_colon_line.Attributes.color;
                map.rxnModWidth{react, 1}{mod, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{mod}.celldesigner_colon_line.Attributes.width;
            end
            clearvars mod
        end
    else
        map.rxnModAlias{react, 1} = '';
        map.rxnModID{react, 1} = '';
        map.rxnModType{react, 1} = '';
        map.rxnModColor{react, 1} = '';
        map.rxnModWidth{react, 1} = '';
    end
    map.rxnColor{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_line.Attributes.color;
    map.rxnWidth{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_line.Attributes.width;

    % Check if the info on notes exists for the reaction
    if any(strcmp('notes', fieldnames(xmlStruct.sbml.model.listOfReactions.reaction{react})))
        map.rxnNotes{react, 1} = xmlStruct.sbml.model.listOfReactions.reaction{react}.notes.html.body.Text;
    else
        map.rxnNotes{react, 1} = '';
    end
end
clearvars react

% Check if there is any information on Compartments
if any(strcmp('celldesigner_colon_compartmentAlias', fieldnames(xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases)))
    % Test is there is only 1 compartment
    if length(xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias) == 1
        map.compartAlias{1, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias(1).Attributes.id;
        map.compartName{1, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias(1).Attributes.compartment;
    else
        % Loop over compartments to get the need information and store it in a
        % structure. Compartments refer to each individual compartment name.
        for compart = 1:length(xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias)
            map.compartAlias{compart, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias{compart}.Attributes.id;
            map.compartName{compart, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias{compart}.Attributes.compartment;
        end
        clearvars compart
    end
else
    map.compartAlias = '';
    map.compartName = '';
end
map = getMapMatrices(map);
toc


function TableDemo(Action);

persistent Handles T;

% function TableDemo(Action);
%
% Demonstrates the table class.
% The Action argument selects the button callback code
% and should not be supplied from the command line.
%
% Copyright (c) SINUS Messtechnik GmbH 2002
% www.sinusmess.de - Sound & Vibration Instrumentation
%                  - PCB Services
%                  - Electronic Design & Production

if nargin == 0
   % No Action parameter supplied:  create figure, table and other controls

   % Create figure and initialise data
   Handles.TableDemoFig = figure;
   set(Handles.TableDemoFig, 'Position', [50 50 800 420], ...
                             'Name', 'Table Test', ...
                             'ResizeFcn', 'TableDemo(''Resize'')');
   RowMax = 10;
   ColMax = 15;
   load PSE.mat;

   % Create table object with visible frame, create table controls and assign data
   T = table(Handles.TableDemoFig, 'Units', 'pixels', ...
                                   'Position', [10 40 780 370], ...
                                   'Visible', 'on');
   T = controls(T, RowMax, ColMax, 'ForegroundColor', 'red');
   T{:,:} = PSE;  % Assign data to table (can also be indexed specifically)

   % Create pushbuttons on figure
   Handles.SaveData    = uicontrol(Handles.TableDemoFig, ...
                                   'Style', 'pushbutton', ...
                                   'Position', [10 10 90 20], ...
                                   'String', 'Save Data', ...
                                   'Callback', 'TableDemo(''SaveData'')');
   Handles.RemoveTable = uicontrol(Handles.TableDemoFig, ...
                                   'Style', 'pushbutton', ...
                                   'Position', [100 10 90 20], ...
                                   'String', 'Remove Table', ...
                                   'Callback', 'TableDemo(''RemoveTable'')');
   Handles.Scroll      = uicontrol(Handles.TableDemoFig, ...
                                   'Style', 'pushbutton', ...
                                   'Position', [190 10 90 20], ...
                                   'String', 'Scroll to 3,4', ...
                                   'Callback', 'TableDemo(''Scroll'')');
   Handles.ScrollBack  = uicontrol(Handles.TableDemoFig, ...
                                   'Style', 'pushbutton', ...
                                   'Position', [280 10 90 20], ...
                                   'String', 'Scroll to 1,1', ...
                                   'Callback', 'TableDemo(''ScrollBack'')');
   Handles.SetMagic    = uicontrol(Handles.TableDemoFig, ...
                                   'Style', 'pushbutton', ...
                                   'Position', [370 10 90 20], ...
                                   'String', 'Set Magic Square', ...
                                   'Callback', 'TableDemo(''SetMagic'')');

else
   % Action argument supplied (selects callback function for figure or control).
   % Other callbacks are handled automatically in the table class directory.

   switch Action
   case 'Resize'       % ResizeFcn of Handles.TableDemoFig
      FigurePos = get(Handles.TableDemoFig, 'Position');
      TablePos = get(T, 'Position');
      TablePos(3) = FigurePos(3) - 20;
      TablePos(4) = FigurePos(4) - 50;
      T = set(T, 'Position', TablePos);
   case 'SaveData'     % Assign data from table (can also be indexed specifically)
      a = T{:,:};
      save save.mat a;
   case 'RemoveTable'  % Delete table
      T = delete(T);
      set(Handles.SaveData,    'Enable','off');
      set(Handles.RemoveTable, 'Enable','off');
      set(Handles.Scroll,      'Enable','off');
      set(Handles.ScrollBack,  'Enable','off');
      set(Handles.SetMagic,    'Enable','off');
   case 'Scroll'       % Set coordinates of upper left corner displayed within table
      T = scroll(T, 3, 4);
   case 'ScrollBack'   % Set coordinates of upper left corner displayed within table
      T = scroll(T, 1, 1);
   case 'SetMagic'     % Assign data to table (indexed specifically)
      T(1:5,3:7) = num2cell(magic(5));
   otherwise           % This should never happen...
      msgbox(['Unknown Action: ' Action], 'TableDemo', 'error');
   end
end


function sev = read_tdt_sev(filename, dtype, begsample, endsample)

% READ_TDT_SEV
%
% Use as
%   sev = read_tdt_sev(filename, dtype, begsample, endsample)
%
% Note: sev files contain raw broadband data that is streamed to the RS4

fid = fopen(filename, 'rb', 'ieee-le');

if nargin<3
  begsample = 1;
end

if nargin<4
  endsample = inf;
end

switch dtype
  case 0
    fmt   = 'float32';
    wsize = 4;
  case 1
    fmt   = 'int32';
    wsize = 4;
  case 2
    fmt   = 'int16';
    wsize = 2;
  case 3
    fmt   = 'int8';
    wsize = 1;
  case 4
    fmt   = 'double';
    wsize = 8;
  case 5
    error('don''t know what a DFORM_QWORD is');
  otherwise
    error('unknown dtype');
end

fseek(fid, begsample*wsize, 'cof');
sev = fread(fid, endsample-begsample, fmt);
fclose(fid);


function B = LDRtoLDR(A, expA, expB)

Radiance = LDRtoHDR(A, expA);
B = HDRtoLDR(Radiance, expB);


function t = uminus(t)
%UMINUS Unary minus (-) for tenmat.
%
%   See also TENMAT.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

t.data = -t.data;


function [p1,p2]=rubberbandbox(varargin)
% Function to draw a rubberband box and return the start and end points
% Usage: [p1,p2]=rubberbox;     uses current axes
%        [p1,p2]=rubberbox(h);  uses axes refered to by handle, h
% Based on an idea of Sandra Martinka's Rubberline
% Written/Edited by Bob Hamans (B.C.Hamans@student.tue.nl)
% 02-04-2003

%Check for optional argument
switch nargin
case 0
  h=gca;
case 1
  h=varargin{1};
  axes(h);
otherwise
  disp('Too many input arguments.');
end

% Get current user data
cudata=get(gcf,'UserData');
hold on;
% Wait for left mouse button to be pressed
k=waitforbuttonpress;
p1=get(h,'CurrentPoint');       %get starting point
p1=p1(1,1:2);                   %extract x and y
lh=plot(p1(1),p1(2),'-r');      %plot starting point
% Save current point (p1) data in a structure to be passed
udata.p1=p1;
udata.h=h;
udata.lh=lh;
% Set gcf object properties 'UserData' and call function 'wbmf' on mouse motion.
set(gcf,'UserData',udata,'WindowButtonMotionFcn','wbmf','DoubleBuffer','on');
k=waitforbuttonpress;

% Get data for the end point
p2=get(h,'Currentpoint');       %get end point
p2=p2(1,1:2);                   %extract x and y
set(gcf,'UserData',cudata,'WindowButtonMotionFcn','','DoubleBuffer','off'); %reset UserData, etc..
delete(lh);

function wbmf %window motion callback function
utemp=get(gcf,'UserData');
ptemp=get(utemp.h,'CurrentPoint');
ptemp=ptemp(1,1:2);
% Use 5 point to draw a rectangular rubberband box
set(utemp.lh,'XData',[ptemp(1),ptemp(1),utemp.p1(1),utemp.p1(1),ptemp(1)],'YData',[ptemp(2),utemp.p1(2),utemp.p1(2),ptemp(2),ptemp(2)]);


function tests = test_ehsan_yale_faces
  tests = functiontests(localfunctions);
end

function setupOnce(testCase)
    close all;
end

function teardownOnce(testCase)
    close all;
end

function test_basic(testCase)
    yf = spx.data.image.EhsanYaleFaces();
    verifyEqual(testCase, yf.image_height, 48);
    verifyEqual(testCase, yf.image_width, 42);
    verifyEqual(testCase, yf.num_subjects, 38);
    verifyEqual(testCase, yf.num_faces_per_subject, 64);
    verifyEqual(testCase, yf.num_total_faces, 64*38);
end

function test1(testCase)
    yf = spx.data.image.EhsanYaleFaces();
    mf = spx.graphics.Figures();
    mf.new_figure('Example faces');
    canvas = yf.create_random_canvas(5, 5);
    imshow(canvas);
    colormap(gray);
    axis image;
    axis off;
    pause(.2);
end


function test_bug1162

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_postamble ft_postamble_history ft_freqgrandaverage

timelock1 = [];
timelock1.label = {'1' '2'};
timelock1.time  = 1:5;
timelock1.dimord = 'rpt_chan_time';
timelock1.avg = randn(1,2,5);
timelock1.cfg = 'this is number 1';

timelock2 = [];
timelock2.label = {'1' '2'};
timelock2.time  = 1:5;
timelock2.dimord = 'rpt_chan_time';
timelock2.avg = randn(1,2,5);
timelock2.cfg = 'this is number 2';

cfg = [];
grandavg = ft_timelockgrandaverage(cfg, timelock1, timelock2);

% grandavg.cfg.previous{1} should be 'this is number 1'
% grandavg.cfg.previous{2} should be 'this is number 1'
disp(grandavg.cfg.previous);

assert(iscell(grandavg.cfg.previous));
assert(~isempty(grandavg.cfg.previous));
assert(~isempty(grandavg.cfg.previous{1}));
assert(~isempty(grandavg.cfg.previous{2}));


function model=setParam(model, paramType, rxnList, params, var)
% setParam
%   Sets parameters for reactions
%
%   model       a model structure
%   paramType   the type of parameter to set:
%               'lb'    Lower bound
%               'ub'    Upper bound
%               'eq'    Both upper and lower bound (equality
%                       constraint)
%               'obj'   Objective coefficient
%               'rev'   Reversibility
%               'var'   Variance around measured bound
%   rxnList     a cell array of reaction IDs or a vector with their
%               corresponding indexes
%   params      a vector of the corresponding values
%   var         percentage of variance around measured value, if 'var' is
%               set as paramType. Defining 'var' as 5 results in lb and ub
%               at 97.5% and 102.5% of the provide params value (if params
%               value is negative, then lb and ub are 102.5% and 97.5%).
%
%   model       an updated model structure
%
%   Usage: model=setParam(model, paramType, rxnList, params)

paramType=convertCharArray(paramType);
if ~any(strcmpi(paramType,{'lb','ub','eq','obj','rev','var'}))
    EM=['Incorrect parameter type: "' paramType '"'];
    dispEM(EM);
end
if isnumeric(rxnList) || islogical(rxnList)
    rxnList=model.rxns(rxnList);
else
    rxnList=convertCharArray(rxnList);
end

%Allow to set several parameters to the same value
if numel(rxnList)~=numel(params) && numel(params)~=1
    EM='The number of parameter values and the number of reactions must be the same';
    dispEM(EM);
end

if length(rxnList)>1
    if length(paramType)==1
        paramType(1:length(rxnList))=paramType;
    end
    if length(params)==1
        params(1:length(rxnList))=params;
    end
end

%Find the indexes for the reactions in rxnList. Do not use getIndexes
%as we do not want to throw errors if matches fail
indexes=zeros(numel(rxnList),1);

for i=1:numel(rxnList)
    index=find(strcmp(rxnList{i},model.rxns),1);
    if ~isempty(index)
        indexes(i)=index;
    else
        indexes(i)=-1;
        EM=['Reaction ' rxnList{i} ' is not present in the reaction list'];
        dispEM(EM,false);
    end
end

%Remove the reactions that were not found
params(indexes==-1)=[];
indexes(indexes==-1)=[];
paramType(indexes==-1)=[];
%Change the parameters

if ~isempty(indexes)
    if contains(paramType,'obj')
        model.c=zeros(numel(model.c),1); % parameter is changed, not added
    end
    for j=1:length(paramType)
        if strcmpi(paramType{j},'eq')
            model.lb(indexes(j))=params(j);
            model.ub(indexes(j))=params(j);
        end
        if strcmpi(paramType{j},'lb')
            model.lb(indexes(j))=params(j);
        end
        if strcmpi(paramType{j},'ub')
            model.ub(indexes(j))=params(j);
        end
        if strcmpi(paramType{j},'obj')
            model.c(indexes(j))=params(j);
        end
        if strcmpi(paramType{j},'rev')
            %Non-zero values are interpreted as reversible
            model.rev(indexes(j))=params(j)~=0;
        end
        if strcmpi(paramType{j},'var')
            if params(j) < 0
                model.lb(indexes(j)) = params(j) * (1+var/200);
                model.ub(indexes(j)) = params(j) * (1-var/200);
            else
                model.lb(indexes(j)) = params(j) * (1-var/200);
                model.ub(indexes(j)) = params(j) * (1+var/200);
            end
        end
    end
end
end


% khobe ama ba hplot mishkel dare c_type kar nemikone Ti Td , Kc ro ehtemalan baid global bedam
function pid
    global C_controller
    hfigure = findall(0,'tag','pid');
    if hfigure
        figure(hfigure)
    else
        h_pid = figure('unit','pixel','pos',[172  412  450  102],'ToolBar','none',...
            'menubar','none','resize','off','CloseRequestFcn','','tag','pid','name','controler',...
            'NumberTitle','off');
        h_panel = uipanel('parent',h_pid,'unit','pixel','pos',[9    14   432    76]);
        h_Ti = uicontrol('parent',h_panel,'unit','pixel','pos',[250.0000   53.0000   77.0000   16.0000],...
            'style','text','string','1/Ti','tag','text2');
        h_Td = uicontrol('parent',h_panel,'unit','pixel','pos',[350.0000   53.0000   77.0000   16.0000],...
            'style','text','string','Td','tag','text3');
        h_P = uicontrol('parent',h_panel,'unit','pixel','pos',[150.0000   53.0000   77.0000   16.0000],...
            'style','text','string','P','tag','text1');
        h_Ti_edit = uicontrol('parent',h_panel,'unit','pixel','pos',[250.0000   32.0000   76.0000   21.0000],...
            'style','edit','string','1','tag','edit2');
        h_Td_edit = uicontrol('parent',h_panel,'unit','pixel','pos',[350.0000   32.0000   76.0000   21.0000],...
            'style','edit','string','1','tag','edit3');
        h_P_edit = uicontrol('parent',h_panel,'unit','pixel','pos',[150.0000   32.0000   76.0000   21.0000],...
            'style','edit','string','1','tag','edit1');
        h_popupmenu = uicontrol('parent',h_panel,'unit','pixel','pos',[13    30    88    21],...
            'style','popupmenu','string', {'P' 'P.I' 'P.I.D'},'BackgroundColor',[1 1 1],...
            'callback',@value_callback,'tag','popup');
        txths = findall(0,'style','text','-not','tag','text1');
        set(txths,'vis','off')
        txthe = findall(0,'style','edit','-not','tag','edit1');
        set(txthe,'vis','off')
        C_controller=1;
    end
    function value_callback(hObject, eventdata, handles)
        global C_controller
        h_popupmenu = findall(0,'tag','popup');
        hpid= get(h_popupmenu,'value');
        switch hpid
            case 1
                txths = findall(0,'style','text','-not','tag','text1');
                set(txths,'vis','off')
                txthe = findall(0,'style','edit','-not','tag','edit1');
                set(txthe,'vis','off')
                C_controller=1;
            case 2
                txths = findall(0,'style','text');
                set(txths,'vis','on')
                txthe = findall(0,'style','edit');
                set(txthe,'vis','on')
                txths = findall(0,'tag','text3');
                set(txths,'vis','off')
                txthe = findall(0,'tag','edit3');
                set(txthe,'vis','off')
                C_controller=2;
            case 3
                txths = findall(0,'style','text');
                set(txths,'vis','on')
                txthe = findall(0,'style','edit');
                set(txthe,'vis','on')
                C_controller=3;
        end


 function s = sum(ob)
%function s = sum(ob)
%	"sum" method for Gblock object

s = sum(ob.base);


function vl_compilenn_calvin()
% vl_compilenn_calvin()
%
% Compile the C code provided in Matconvnet-calvin.
% Matconvnet code needs to be compiled separately.
%
% Copyright by Holger Caesar, 2016

root = calvin_root();
codeDir = fullfile(root, 'matconvnet-calvin', 'matlab');
mexDir = fullfile(codeDir, 'mex');
mexOpts = {'-largeArrayDims', '-outdir', sprintf('"%s"', mexDir)};

% E2S2-related
mex(mexOpts{:}, fullfile(codeDir, 'labelpresence', 'labelPresence_backward.cpp'));
mex(mexOpts{:}, fullfile(codeDir, 'regiontopixel', 'regionToPixel_backward.cpp'));
mex(mexOpts{:}, fullfile(codeDir, 'regiontopixel', 'regionToPixelSoft_backward.cpp'));
mex(mexOpts{:}, fullfile(codeDir, 'roipool', 'roiPooling_forward.cpp'));
mex(mexOpts{:}, fullfile(codeDir, 'roipool', 'roiPooling_backward.cpp'));

% Misc
mex(mexOpts{:}, fullfile(codeDir, 'misc', 'computeBlobOverlapAnyPair.cpp'));
mex(mexOpts{:}, fullfile(codeDir, 'misc', 'scoreBlobIoUs.cpp'));


function p3 = diff(p1)
%PREAL/DIFF Overloaded DIFF function for class preal.

global useUnitsFlag

if ~(useUnitsFlag) % If physunits is disabled...
    p3=diff(double(p1)); % ... treat as double.
    return
end

if isscalar(p1)
    p3=preal([]);
    return
end
if isvector(p1)
    p3=preal(ones(size(p1)));
    p3(end)=[];
    for k=1:numel(p3)
        p3(k)=p1(k+1)-p1(k);
    end
else
    error('preal/diff is only defined for vectors')
end


function pageFinish(api)

gui = localCreatePage();

api.setWizardTitle('Import Data');
api.setWizardDescription('Select Method');

api.setLeavePageCallback(@leavePage);
api.setGotoPageCallback(@gotoPage);

set(gui.hVarname     ,'Callback',          @localExportBehavior);
set(gui.hFinishGroup ,'SelectionChangeFcn',@localExportBehavior);

  function nextPage = leavePage

    nextPage = [];

  end

  function gotoPage

    api.Progress.enableNext(false);
    api.Progress.enableFinish(true);

    localUpdateGUI();

  end

  function localExportBehavior(varargin)

    varName = regexprep(get(gui.hVarname,'String'),'\s','');
    api.Export.setWorkspaceName(varName);

    doScript = get(gui.hRadio(1),'Value');
    api.Export.setGenerateScriptFile(doScript);

    localUpdateGUI();

  end

  function localUpdateGUI()

    doScript = api.Export.getGenerateScriptFile();
    varname  = api.Export.getWorkspaceName();

    val_alias = {'off','on'};
    set(gui.hVarname,'Visible',val_alias{~doScript+1})
    set(gui.hVarname,'String',varname);

    set(gui.hRadio(1),'Value',doScript)
    set(gui.hRadio(2),'Value',~doScript)

    data = api.getDataTransformed();

    set(gui.hTitle,'String',[ 'Summary of ' class(data) ' data to be imported:']);
    set(gui.hPreview,'String',cellstr(char(data)));

  end

  function gui = localCreatePage()
    % final import wizard page
    page = api.hPanel;

    h = api.Spacings.PageHeight;
    w = api.Spacings.PageWidth;
    m = api.Spacings.Margin;
    fs = api.Spacings.FontSize;

    summarytitle = uicontrol(...
      'Parent',page,...
      'String','Data summary:',...
      'Position',[1 h-20-m w 20],...
      'Style','text',...
      'FontSize',fs,...
      'HorizontalAlignment','left');

    preview = uicontrol(...
      'Parent',page,...
      'BackgroundColor',[1 1 1],...
      'FontName','monospaced',...
      'FontSize',fs,...
      'HorizontalAlignment','left',...
      'Max',2,...
      'Position',[1 h-210 w-2 175],...
      'String',blanks(0),...
      'Style','edit');

    finish_exp = uibuttongroup('title','Import to',...
      'Parent',page,...
      'FontSize',fs,...
      'units','pixels','position',[1 h-270 w-2 50]);

    radio_exp(2) = uicontrol(...
      'Parent',finish_exp,...
      'HorizontalAlignment','left',...
      'Position',[160 10 150 20 ],...
      'String',' workspace variable',...
      'FontSize',fs,...
      'Value',0,...
      'Style','radio');

    radio_exp(1) = uicontrol(...
      'Parent',finish_exp,...
      'HorizontalAlignment','left',...
      'Position',[10 10 150 20 ],...
      'String',' script (m-file)',...
      'FontSize',fs,...
      'Value',1,...
      'Style','radio');

    workspace(1) = uicontrol(...
      'Parent',page,...
      'BackgroundColor',[1 1 1],...
      'FontName','monospaced',...
      'HorizontalAlignment','left',...
      'FontSize',fs,...
      'Position',[320 15  150 22 ],...
      'String',blanks(0),...
      'Style','edit');

    gui.hFinishGroup = finish_exp;
    gui.hRadio       = radio_exp;
    gui.hVarname     = workspace;
    gui.hTitle       = summarytitle;
    gui.hPreview     = preview;

  end

end


addpath('./lib')
run('./SE-Sync/manopt/importmanopt.m')
addpath('./SE-Sync/lib')


function f_star = processOutputQP_oneFoot(analyticalSolution,primalSolution,QPStatus,feetContactStatus,Config)

    % PROCESSOUTPUTQP_ONEFOOT evaluates the output of the WBToolbox QP block.
    %                         In case the QP block exited with an error, a
    %                        "default", user defined solution to the QP problem
    %                         is provided instead of the one coming from the QP block.
    %
    % FORMAT: f_star = processOutputQP_oneFoot(analyticalSolution,primalSolution,QPStatus,feetContactStatus,Config)
    %
    % INPUT:  - analyticalSolution = the alternative user defined solution to the QP
    %                                problem to be used when the QP block fails;
    %         - primalSolution = the solution to the QP problem provided by the
    %                            WBToolbox QP block;
    %         - QPStatus = the status check returned by the QP block.
    %
    %         - feetContactStatus = [2 x 1] a vector describing the feet contact
    %                               status. Format: [leftFoot; rightFoot];
    %         - Config = a structure containing the robot-related configuration
    %                    parameters;
    %
    % OUTPUT: - f_star = the final solution to the QP problem that will be used in
    %                    the controller.
    %
    % Authors: Daniele Pucci, Marie Charbonneau, Gabriele Nava
    %
    %          all authors are with the Italian Istitute of Technology (IIT)
    %          email: name.surname@iit.it
    %
    % Genoa, Dec 2017
    %

    %% --- Initialization ---

    CONTACT_THRESHOLD   = 0.1;
    QP_STATUS_THRESHOLD = 0.01;

    % if the robot is balancing on one foot, extend the QP solution to
    % have the correct dimension of f_star for matrix multiplication
    if feetContactStatus(1) > (1 - CONTACT_THRESHOLD)

        % left foot balancing
        updated_primalSolution     = [primalSolution; zeros(6,1)];
        updated_analyticalSolution = [analyticalSolution; zeros(6,1)];

    else
        % right foot balancing
        updated_primalSolution     = [zeros(6,1); primalSolution];
        updated_analyticalSolution = [zeros(6,1); analyticalSolution];
    end

    if Config.USE_QP_SOLVER && abs(QPStatus)< QP_STATUS_THRESHOLD

        f_star = updated_primalSolution;
    else
        f_star = updated_analyticalSolution;
    end
end


function hypograph( varargin )

%HYPOGRAPH Declares a hypograph variable.
%   HYPOGRAPH VARIABLE x
%   where x is a valid MATLAB variable name, declares a scalar
%   variable for the current cvx problem, and specifies it as
%   the objective of a maximization. There is no need to declare
%   a separate MAXIMIZE command.
%
%   This keyword should be used only when attempting to
%   create a new function for the CVX library. Suppose you have a
%   function F(X) whose hypograph {(X,Y)}{F(X)>=Y} can be
%   described as a CVX feasibiliy problem. Then declaring Y
%   as an EPIGRAPH turns the model into one that computes the
%   value of the function itself, maximizing over Y.
%
%   Other uses of this keyword are NOT supported and can lead
%   to numerical errors.
%
%   HYPOGRAPH VARIABLE x(n1,n2,...,nk)
%   declares a vector, matrix, or array hypograph variable with
%   dimensions n1, n2, ..., nk, each of which must be positive
%   integers.
%
%   Structure modifiers such as "symmetric", "toeplitz", etc.
%   are permitted with hypograph variables.
%
%   Examples:
%      hypograph variable x
%      hypograph variable x(100)
%
%   See also VARIABLE, EPIGRAPH.

if nargin < 2,
    error( 'Incorrect syntax for HYPOGRAPH VARIABLE. Type HELP HYPOGRAPH for details.' );
elseif ~iscellstr( varargin ),
    error( 'All arguments must be strings.' );
elseif ~strcmp( varargin{1}, 'variable' ),
    error( 'Incorrect syntax for HYPOGRAPH VARIABLE. Type HELP HYPOGRAPH for details.' );
end
evalin( 'caller', sprintf( '%s ', 'variable', varargin{2:end}, ' hypograph_' ) );

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [varargout] = subsref(obj,s)

n = numel(s);
if n == 0,
  varargout{1} = obj;
  return;
end

% which flies are referenced?
i = 1;
switch s(i).type,
  case '()',

    switch numel(s(i).subs),

      % one argument means fly index
      case 1,
        if ischar(s(i).subs{1}) && strcmp(s(i).subs{1},':'),
          idx = 1:obj.nflies;
        elseif isnumeric(s(i).subs{1}),
          idx = s(i).subs{1};
          if any(idx < 1 | idx > obj.nflies | idx ~= round(idx)),
            error('Indices must be whole numbers between 1 and %d',obj.nflies);
          end
        else
          error('Bad indexing argument');
        end

      % two arguments means experiment + fly
      case 2,

        % experiment indices
        j = 1;
        if ischar(s(i).subs{j}) && strcmp(s(i).subs{j},':'),
          exps = 1:obj.nexpdirs;
        elseif ischar(s(i).subs{j}) && ismember(s(i).subs{j},obj.expdirs),
          exps = find(strcmp(s(i).subs{j},obj.expdirs),1);
        elseif iscell(s(i).subs{j}),
          [didfind,exps] = ismember(s(i).subs{j},obj.expdirs);
          if any(~didfind),
            error(['Bad experiment indexing arguments: ',sprintf('%s ',s(i).subs{j}{~didfind})]);
          end
        elseif isnumeric(s(i).subs{j}),
          exps = s(i).subs{j};
          if any(exps < 1 | exps > obj.nexpdirs | exps ~= round(exps)),
            error('Experiment indices must be whole numbers between 1 and nexpdirs = %d',obj.nexpdirs);
          end
        else
          error('Bad experiment indexing argument');
        end

        % fly indices
        j = 2;
        if ischar(s(i).subs{j}) && strcmp(s(i).subs{j},':'),
          idx = [obj.exp2flies{exps}];
        elseif isnumeric(s(i).subs{j}),
          idx = cell2mat(cellfun(@(x)x(s(i).subs{j}),obj.exp2flies(exps),'UniformOutput',false));
        else
          error('Bad fly indexing argument');
        end

      otherwise
        error('Number of indexing arguments must be <= 2');
    end

    % go on to next argument
    i = 2;

  case '.',

    if ismember(s(i).subs,methods(obj)) || ismember(s(i).subs,properties(obj)),
      [varargout{1:nargout}] = builtin('subsref',obj,s);
      return;
    end

    idx = 1:obj.nflies;

    % use this argument
    i = 1;

  otherwise
    error('{} referencing not supported');
end

if n < i,
  % TODO: maybe implement this?
  error('Field name must be specified');
end

% get field
if ~strcmpi(s(i).type,'.'),
  error('Field name must be specified');
end
fn = s(i).subs;
i = i + 1;

% get indices
elidx = [];
if n < i,
  t = ':';
else
  if ~strcmp(s(i).type,'()'),
    error('Frame indices must be indexed by ()');
  end
  if numel(s(i).subs) > 2,
    error('Can only index as (i,t) or (t)');
  elseif numel(s(i).subs) == 2,
    elidx = s(i).subs{1};
    t = s(i).subs{2};
  else
    t = s(i).subs{1};
  end
end

if strcmp(fn,'nframes'),
  res = {obj.nframes(idx)};
elseif strcmp(fn,'firstframe'),
  res = {obj.firstframes(idx)};
elseif strcmp(fn,'endframe'),
  res = {obj.endframes(idx)};
elseif strcmp(fn,'off'),
  res = {1-obj.firstframes(idx)};
elseif strcmp(fn,'trkInfo')
  res = {obj.trkInfo{idx}};
elseif (numel(fn)>=4) && strcmp(fn(1:4),'kpts')
  res = {obj.(fn){idx}};
else
  res = cell(1,numel(idx));
  for j = 1:numel(idx),
    x = obj.GetPerFrameData(fn,idx(j));
    if ~isempty(elidx),
      if ~ischar(elidx),
        x = x(elidx,:);
      end
      if ischar(t),
        res{j} = x;
      else
        res{j} = x(:,t);
      end
    else
      if ischar(t),
        res{j} = x;
      else
        res{j} = x(t);
      end
    end
  end
end
if nargout>0 && nargout < numel(res),
  if numel(res) == 1,
    varargout{1:nargout} = res{1};
  else
    varargout{1:nargout} = res;
  end
else
  varargout = res;
end


function install_blendenpik
% install_blendenpik
%
% Compiles and install Blendenpik.
% Blenenpik is a library for fast solution of dense least squares problem.
%
% 6-December 2009, Version 1.3
% Copyright (C) 2009, Haim Avron and Sivan Toledo.

%% Get configuration
[s, hostname] = system('hostname');
hostname = hostname(1:end-1);
config_file = sprintf('config/config.%s', hostname);

% Generate config file?
if (exist(config_file) ~= 0)
    regen_config = input('Configuration file already exist. Regenerate? ', 's');
    if (strcmp(lower(regen_config), 'yes'))
        configure_blenenpik;
    end
else
    configure_blenenpik;
end

% Read config file
fid = fopen(config_file);
if (fid == -1)
    error(sprintf('Config file %s not found!', CONFIG_FILE));
end
while 1
    tline = fgetl(fid);
    if ~ischar(tline), break, end
    eval(tline);
end

WISDOM_FILE = sprintf('%s/dat/wisdom_file.%s.%d.dat', pwd, hostname, FFTW_PLANNING_LEVEL);
if (ispc)
    WISDOM_FILE(WISDOM_FILE == '\') = '/';
end

%% Write config.h
fid = fopen('config.h', 'w');
fprintf(fid, '#define FFTW_QUANT %d\n', FFTW_QUANT);
fprintf(fid, '#define FFTW_TIMES %d\n', FFTW_TIMES);
fprintf(fid, '#define FFTW_WISDOM_FILE "%s"\n', WISDOM_FILE);
if (FFTW_PLANNING_LEVEL > 0)
    wisdom_flag = 'FFTW_WISDOM_ONLY';
else
    wisdom_flag = 'FFTW_ESTIMATE';
end
fprintf(fid, '#define FFTW_WISDOM_FLAG %s\n', wisdom_flag);
if (BLAS_UNDERSCORE)
    fprintf(fid, '#define BLAS_UNDERSCORE\n');
end

if (USE_FFTW)
    fprintf(fid, '#define USE_FFTW\n');
end

if (USE_SWHT)
    fprintf(fid, '#define USE_SWHT\n');
end

fclose(fid);

%% Compile
MEX_DIR = pwd;

if (~exist(MEX_DIR, 'dir'))
    mkdir(MEX_DIR);
end

incs = sprintf('-I"%s"', pwd);
libs = '';

if (USE_FFTW)
    incs = sprintf('%s -I"%s"', incs, FFTW_DIR_INC);
    libs = sprintf('%s -L"%s" -l%s', libs, FFTW_DIR_LIB, FFTW_NAME);
end

if (USE_SWHT)
    incs = sprintf('%s -I"%s"', incs, SWHT_DIR_INC);
    libs = sprintf('%s -L"%s" -l%s', libs, SWHT_DIR_LIB, SWHT_NAME);
end

prefix0 = sprintf('mex -outdir ''%s'' %s -O %s', MEX_DIR, incs, libs);
prefix = sprintf('%s -L"%s" -l%s -L"%s" -l%s %s ', prefix0,  LAPACK_DIR, LAPACK_NAME, BLAS_DIR, BLAS_NAME, ADDITIONAL_FLAGS);

eval([prefix '-c ' 'fftw_r2r.c']);
FFTW_R2R_OBJ = sprintf('"%s/fftw_r2r%s"', MEX_DIR, OBJ_EXT);
eval([prefix 'mex_fftw_r2r.c ' FFTW_R2R_OBJ]);
eval([prefix 'fast_unitary_transform.c ' FFTW_R2R_OBJ]);
eval([prefix 'fast_unitary_transform_size.c']);
eval([prefix 'build_fftw_wisdom.c']);
eval([prefix 'wtime.c']);
eval([prefix 'mex_dtrcon.c']);
eval([prefix 'mex_dgeqrf.c']);
eval([prefix 'mex_dormqr.c']);
eval([prefix 'mex_dtrsm.c']);
eval([prefix 'mex_dlange.c']);
eval([prefix 'lapack_solve_ls.c']);
eval([prefix 'dense_overdetermined_lsqr.c']);
eval([prefix 'dense_full_overdetermined_lsqr.c']);
eval([prefix 'dense_underdetermined_lsqr.c']);
addpath(MEX_DIR);
addpath(pwd);
savepath;

if (~exist('dat', 'dir'))
    mkdir('dat');
end

if (USE_FFTW)
    if (exist(WISDOM_FILE, 'file'))
        build_wisdom_text = input('FFTW wisdom already exist. Rebuild? (yes/no) ', 's');
        build_wisdom = strcmp(lower(build_wisdom_text), 'yes');
    else
        build_wisdom = true;
    end
    if (build_wisdom)
        disp('Building FFTW''s wisdom...');
        build_fftw_wisdom(FFTW_PLANNING_LEVEL, WISDOM_FILE);
    end
end


function finetuned_model_path = train_LocNet_model(...
        image_db_train, image_db_val, model, conf)
% train_LocNet_model: trains the LocNet network
%
% INPUTS:
% 1) image_db_train: struct with the specifiers of the training dataset
% 2) image_db_val: struct with the specifiers of the testing dataset
% 3) model: struct with the localization model
% 4) conf: struct with the configuration options of the training process
%
% OUTPUT:
% 1) finetuned_model_path: string with the path to the trained caffe model
% produced from the training procedure.
%
% This file is part of the code that implements the following paper:
% Title      : "LocNet: Improving Localization Accuracy for Object Detection"
% Authors    : Spyros Gidaris, Nikos Komodakis
% Institution: Universite Paris Est, Ecole des Ponts ParisTech
% ArXiv link : http://arxiv.org/abs/1511.07763
% code       : https://github.com/gidariss/LocNet
%
%
% AUTORIGHTS
% --------------------------------------------------------
% Copyright (c) 2016 Spyros Gidaris
%
% Title     : "LocNet: Improving Localization Accuracy for Object Detection"
% ArXiv link: http://arxiv.org/abs/1511.07763
% Licensed under The MIT License [see LICENSE for details]
% ---------------------------------------------------------

mkdir_if_missing(conf.finetune_rst_dir);
timestamp = datestr(datevec(now()), 'yyyymmdd_HHMMSS');
log_file  = fullfile(conf.finetune_rst_dir, 'output', ['LocNet_' timestamp, '.txt']);
mkdir_if_missing(fileparts(log_file));
finetuned_model_path = '';
diary(log_file);

image_db_train_file = fullfile(conf.finetune_rst_dir,'train_file.mat');
image_db_val_file   = fullfile(conf.finetune_rst_dir,'val_file.mat');

% load training dataset
try
    load(image_db_train_file,'image_db_train');
catch
    image_db_train = load_image_dataset(...
        'dataset',          image_db_train.dataset, ...
        'image_set',        image_db_train.image_set, ...
        'voc_year',         image_db_train.voc_year, ...
        'proposals_method', image_db_train.proposals_method,...
        'use_flips',        image_db_train.use_flips);
    image_db_train.cache_regions_dir = ...
        fullfile(pwd,'cached_regions', ...
        ['LocNet_model_', image_db_train.image_set_name, '_', image_db_train.proposals_suffix,filesep]);
    mkdir_if_missing(image_db_train.cache_regions_dir);

    fprintf('Prepare training data:\n')
    image_db_train = setup_image_db(image_db_train, conf);
    fprintf('Done\n')
    save(image_db_train_file,'image_db_train','-v7.3');
end

% load testing dataset
try
    load(image_db_val_file,'image_db_val');
catch
    image_db_val = load_image_dataset(...
        'dataset',          image_db_val.dataset, ...
        'image_set',        image_db_val.image_set, ...
        'voc_year',         image_db_val.voc_year, ...
        'proposals_method', image_db_val.proposals_method,...
        'use_flips',        image_db_val.use_flips);

    image_db_val.cache_regions_dir = ...
        fullfile(pwd,'cached_regions', ...
        ['LocNet_model_', image_db_val.image_set_name, '_', image_db_val.proposals_suffix,filesep]);
    mkdir_if_missing(image_db_val.cache_regions_dir);

    fprintf('Prepare validation data:\n')
    image_db_val = setup_image_db(image_db_val, conf);
    fprintf('Done\n')
    save(image_db_val_file,'image_db_val','-v7.3');
end

fprintf('conf:\n');
disp(conf);
fprintf('model:\n');
disp(model);
fprintf('pooler:\n');
disp(model.pooler_loc);
fprintf('model.loc_params:\n');
disp(model.loc_params);

current_dir = pwd;
cd(fileparts(conf.finetune_net_def_file))
% initialize caffe solver
[solver, iter_] = InitializeSolver(conf);

fprintf('Starting iteration %d\n', iter_);

prev_rng = seed_rand();
last_finetuned_model_prev_path = '';

rng(prev_rng);

iter_ = solver.iter();
mean_error_test = TestNet(conf, model, solver, image_db_val);
ShowState(iter_, NaN, mean_error_test);
if conf.test_only
    mean_error_test = TestNet(conf, model, solver, image_db_val);
    ShowState(iter_, NaN, mean_error_test);
    return;
end

% start training
shuffled_inds   = {};
while(iter_ < conf.max_iter)
    % train the localization model (for conf.test_interval number of iterations)
    [mean_error_train, shuffled_inds] = TrainNet(conf, model, solver, image_db_train, shuffled_inds);
    % test the localization model (for conf.test_iter number of iterations)
    mean_error_test = TestNet( conf, model, solver, image_db_val);

    iter_ = solver.iter();
    ShowState(iter_, mean_error_train, mean_error_test);
    diary; diary; % flush diary

    last_finetuned_model_path = fullfile(conf.finetune_rst_dir, ...
        sprintf('%s_iter_%d.caffemodel', conf.snapshot_prefix, iter_));
    assert(exist(last_finetuned_model_path,'file')>0);
    fprintf('last save as %s\n', last_finetuned_model_path);

    % delete the previously saved model
    deletePreviousModel(last_finetuned_model_prev_path);
    last_finetuned_model_prev_path = last_finetuned_model_path;
end
cd(current_dir);
finetuned_model_path = last_finetuned_model_path;
fprintf('Optimization is finished\n')
end

function [solver, iter_] = InitializeSolver(conf)
solver = caffe.Solver(conf.finetune_net_def_file);
iter_   = 1;

if isfield(conf,'solver_state_file') && ~isempty(conf.solver_state_file)
    solver.restore(conf.solver_state_file);
    [directory,filename] = fileparts(conf.solver_state_file);
    model_file = [directory,filesep, filename, '.caffemodel'];
    solver.net.copy_from(model_file);
    solver.test_nets(1).copy_from(model_file);
    iter_   = solver.iter();
    rng('shuffle')
else
    solver.net.copy_from(conf.net_file);
    solver.test_nets(1).copy_from(conf.net_file);
end
end

function deletePreviousModel(finetuned_model_prev_path)
if exist(finetuned_model_prev_path, 'file')
	delete(finetuned_model_prev_path);
end
[directory,filename] = fileparts(finetuned_model_prev_path);
finetuned_model_prev_path_solver_state = [directory,filesep, filename,'.solverstate'];
if exist(finetuned_model_prev_path_solver_state, 'file')
    delete(finetuned_model_prev_path_solver_state);
end
end

function ShowState(iter, train_error, test_error)
fprintf('\n------------------------- Iteration %d -------------------------\n', iter);
fprintf('Error - Training : %.4f - Testing : %.4f\n', train_error, test_error);
end

function [mean_loc_error] = TestNet(conf, model, solver, image_db_val)
fprintf('Testing: \n'); th = tic;

% sample testing images and testing regions
conf.save_data_test_file = fullfile(conf.finetune_rst_dir, ...
    sprintf('test_file_ims_per_batch%d_batch_size%d_test_iter%d.mat', ...
    conf.ims_per_batch, conf.batch_size, conf.test_iter));
try
    ld = load(conf.save_data_test_file);
    shuffled_inds_val    = ld.shuffled_inds_val;
    windows_bbox_loc_val = ld.windows_bbox_loc_val;
catch
    % sample test images
    shuffled_inds_val    = GenerateRandomMinibatch([], image_db_val, conf.ims_per_batch);
    shuffled_inds_val    = shuffled_inds_val(randperm(length(shuffled_inds_val), conf.test_iter));
    windows_bbox_loc_val = cell(length(shuffled_inds_val),1);
    % sample test regions from the test images
    for i = 1:length(shuffled_inds_val)
        windows_bbox_loc_val{i} = SampleImageRegionsForLoc(conf, image_db_val.images(shuffled_inds_val{i}));
    end
    save(conf.save_data_test_file, 'shuffled_inds_val', 'windows_bbox_loc_val');
end

mean_loc_error = 0;
mean_loc_loss  = 0;

bbox_inits_loc  = cell(length(shuffled_inds_val),1);
predictions_loc = cell([1,1,1,length(shuffled_inds_val)]);
bbox_target_loc = cell(length(shuffled_inds_val),1);
for i = 1:length(shuffled_inds_val)
    image_roidb_this_minibath = image_db_val.images(shuffled_inds_val{i}); % validation image
    windows_bbox_loc_this = windows_bbox_loc_val{i}; % sampled regions in the validation image

    % get image caffe blobs
    [im_blob, im_scales, image_sizes] = GetImageBlob(model, image_roidb_this_minibath);

    % get regions caffe blobs and target blobs
    [loc_blobs, bbox_target_loc{i}, bbox_inits_loc{i}] = ...
        GetLocNetMinibatchData(model.loc_params, model, image_roidb_this_minibath, ...
        windows_bbox_loc_this, im_scales, image_sizes);
    % set network input
    net_inputs = [{im_blob}, loc_blobs];

    caffe_reshape_net_as_input(solver.test_nets(1), net_inputs);
    caffe_set_input(solver.test_nets(1), net_inputs);
    solver.test_nets(1).forward_prefilled();

    % get output
    mean_loc_loss        = mean_loc_loss + solver.test_nets(1).blobs('loss_loc').get_data();
    predictions_loc{i}   = solver.test_nets(1).blobs('preds_loc').get_data();
    loc_accuracy         = get_loc_accuracy(model.loc_params, predictions_loc{i}, loc_blobs);
    mean_loc_error       = mean_loc_error + (1-loc_accuracy);
end

[mAR_before, mAR_after, mAR_unbound] = ...
    get_mean_Average_Recall_stats(bbox_inits_loc, bbox_target_loc, predictions_loc, model.loc_params);
mean_loc_error = mean_loc_error / length(shuffled_inds_val);
mean_loc_loss  = mean_loc_loss  / length(shuffled_inds_val);

fprintf('elapsed time %.2f sec | localization: loss %.4f error %.4f mAR %.2f --> mAR %.2f (upper bound %.2f)\n', ...
    toc(th), mean_loc_loss, mean_loc_error, ...
    mAR_before*100, mAR_after*100, mAR_unbound*100);
end

function [loc_accuracy] = get_loc_accuracy(conf, predictions_loc, loc_blobs)
% compute the accuracy of the predicted probability vectors w.r.t. the
% target probability vectors (only for the LocNet models).

switch conf.loc_type
    case {'inout','borders','combined'}
        target_vectors = loc_blobs{2};
        target_weights = loc_blobs{3};
        mask           = target_weights > 0;
        preds_vectors  = single(predictions_loc > 0.5);
        loc_accuracy   = sum(target_vectors(mask) == preds_vectors(mask)) / sum(mask(:));
    otherwise
        loc_accuracy = 0;
end

end

function [mAR_before, mAR_after, mAR_unbound] = ...
    get_mean_Average_Recall_stats(bbox_inits_loc, bbox_target_loc, predictions_loc, conf)

bbox_target_loc = cell2mat(bbox_target_loc);
bbox_inits_loc  = cell2mat(bbox_inits_loc);
class_indices   = bbox_inits_loc(:,5);
bbox_inits_loc  = bbox_inits_loc(:,1:4);

switch conf.loc_type
    case 'bboxreg'
        predictions_loc = squeeze(cell2mat(predictions_loc(:)'));

        % permute from [(4*num_classes) x NumBoxes] -> [NumBoxes x (4*num_classes)]
        predictions_loc = single(permute(predictions_loc, [2, 1]));
        % reshape from [NumBoxes x (4*num_classes)] -> [NumBoxes x 4 x num_classes]
        predictions_loc = reshape(predictions_loc, ...
            [size(predictions_loc,1), 4, conf.num_classes]);

        pred_bbox_loc = decode_reg_vals_to_bbox_targets(...
            bbox_inits_loc, predictions_loc, class_indices);

        if nargout >= 3
            % find the ideal predictions...
            target_reg_values = encode_bbox_targets_to_reg_vals(...
                bbox_inits_loc, bbox_target_loc, conf.num_classes);

            pred_bbox_loc_ideal = decode_reg_vals_to_bbox_targets(...
                bbox_inits_loc, target_reg_values, class_indices);

            % upper bound on the mAR with the CNN-based bounding box
            % regression model. Normaly mAR = 1.0.
            mAR_unbound = compute_mAR_of_bboxes(bbox_inits_loc, pred_bbox_loc_ideal(:,1:4), ...
                bbox_target_loc(:,1:4), class_indices, conf.num_classes);
        end
    case {'inout','borders','combined'}
        predictions_loc = squeeze(cell2mat(predictions_loc));

        pred_bbox_loc = decode_loc_probs_to_bbox_targets(...
            bbox_inits_loc, class_indices, predictions_loc, conf);

        if nargout >= 3
            % find the ideal predictions...
            target_loc_prob_vectors = encode_bbox_target_to_loc_probs(...
                bbox_inits_loc, bbox_target_loc, conf);

            pred_bbox_loc_ideal = decode_loc_probs_to_bbox_targets(...
                bbox_inits_loc, class_indices, target_loc_prob_vectors, conf);

            % upper bound on the mAR with LocNet model. Because of the
            % quantization of the search region in M horizontal stripes and
            % M vertical stripes the mAR < 1.0
            mAR_unbound = compute_mAR_of_bboxes(bbox_inits_loc, pred_bbox_loc_ideal(:,1:4), ...
                bbox_target_loc(:,1:4), class_indices, conf.num_classes);
        end
    otherwise
        error('Invalid localization type %s',conf.loc_type)
end

mAR_before = compute_mAR_of_bboxes(bbox_inits_loc, bbox_inits_loc, ...
            bbox_target_loc(:,1:4), class_indices, conf.num_classes);

mAR_after = compute_mAR_of_bboxes(bbox_inits_loc, pred_bbox_loc(:,1:4), ...
            bbox_target_loc(:,1:4), class_indices, conf.num_classes);
end

function [mean_loc_error, shuffled_inds] = TrainNet(conf, model, solver, image_db_train, shuffled_inds)
mean_loc_error = 0;
mean_loc_loss = 0;
fprintf('Training:\n'); th = tic;
for i = 1:conf.test_interval
    % sample training images
    [shuffled_inds, sub_db_inds] = GenerateRandomMinibatch(...
        shuffled_inds, image_db_train, conf.ims_per_batch);
    image_roidb_this_minibath = image_db_train.images(sub_db_inds);

    % get the training image blobs that will be fed to caffe
    [im_blob, im_scales, image_sizes] = GetImageBlob(model, image_roidb_this_minibath);

    % sample training regions for localization
    windows_bbox_loc = SampleImageRegionsForLoc(conf, image_roidb_this_minibath);

    % get training regions caffe blobs and the target blobs
    loc_blobs = GetLocNetMinibatchData(model.loc_params, model, ...
        image_roidb_this_minibath, windows_bbox_loc, im_scales, image_sizes);
    % set network input
    net_inputs = [{im_blob}, loc_blobs];

    caffe_reshape_net_as_input(solver.net, net_inputs);
    caffe_set_input(solver.net, net_inputs);
    solver.step(1);

    % get output
    mean_loc_loss   = mean_loc_loss + solver.net.blobs('loss_loc').get_data();
    predictions_loc = solver.net.blobs('preds_loc').get_data();
    loc_accuracy    = get_loc_accuracy(model.loc_params, predictions_loc, loc_blobs);
    mean_loc_error  = mean_loc_error + (1-loc_accuracy);

    if (mod(i, conf.display_step) == 0)
        fprintf('%2d/%d:\telapsed time %.2f sec --- error %.4f loss %.4f\n', ...
            i, conf.test_interval, toc(th), mean_loc_error/i, mean_loc_loss/i);
        th = tic;
        diary; diary; % flush diary
    end
end
mean_loc_error = mean_loc_error/i;
end

function [mAR, AR] = compute_mAR_of_bboxes(all_bbox_init, all_bbox_pred, all_bbox_targets, class_ids, num_classes)
% compute the mAR of the predicted bounding boxes w.r.t. the target
% bounding boxes.

AR = zeros(1,num_classes);
fprintf('AveRecall: ')
for c = 1:num_classes
    is_this_cls  = class_ids==c;
    bbox_pred    = all_bbox_pred(is_this_cls,:);
    bbox_targets = all_bbox_targets(is_this_cls,:);
    is_not_gt    = ~all(all_bbox_init(is_this_cls,:) == bbox_targets, 2);
    bbox_pred    = bbox_pred(is_not_gt,:);
    bbox_targets = bbox_targets(is_not_gt,:);
    AR(c)        = compute_ave_recall_of_bbox(bbox_pred, bbox_targets);
    fprintf('[%d]=%.2f(%d) ',c, AR(c),size(bbox_targets,1));
end

fprintf('\n')
mAR = mean(AR);
end

function [shuffled_inds, sub_inds] = GenerateRandomMinibatch(...
    shuffled_inds, image_db, ims_per_batch)
% This function comes from the Faster R-CNN code and the matlab
% re-implementation of Fast-RCNN (https://github.com/ShaoqingRen/faster_rcnn)

% shuffle training data per batch
if isempty(shuffled_inds)
    fprintf('!!!!!!!!!!!!!!!!!!!!!!!!New Epoch!!!!!!!!!!!!!!!!!!!!!!!!!!!\n');
    % make sure each minibatch, only has horizontal images or vertical
    % images, to save gpu memory
    hori_image_inds = image_db.image_sizes(:,2) >= image_db.image_sizes(:,1);
    vert_image_inds = ~hori_image_inds;
    hori_image_inds = single(find(hori_image_inds));
    vert_image_inds = single(find(vert_image_inds));

    % random perm
    lim = floor(length(hori_image_inds) / ims_per_batch) * ims_per_batch;
    hori_image_inds = hori_image_inds(randperm(length(hori_image_inds), lim));
    lim = floor(length(vert_image_inds) / ims_per_batch) * ims_per_batch;
    vert_image_inds = vert_image_inds(randperm(length(vert_image_inds), lim));

    % combine sample for each ims_per_batch
    hori_image_inds = reshape(hori_image_inds, ims_per_batch, []);
    vert_image_inds = reshape(vert_image_inds, ims_per_batch, []);

    shuffled_inds = [hori_image_inds, vert_image_inds];
    shuffled_inds = shuffled_inds(:, randperm(size(shuffled_inds, 2)));
    shuffled_inds = num2cell(shuffled_inds, 1);
end

if nargout > 1
    % generate minibatch training data
    sub_inds = shuffled_inds{1};
    assert(length(sub_inds) == ims_per_batch);
    shuffled_inds(1) = [];
end

end

function sampled_regions_loc = SampleImageRegionsForLoc(conf, image_roidb)

num_images = length(image_roidb);
assert(mod(conf.batch_size, num_images) == 0, ...
    sprintf('num_images %d must divide BATCH_SIZE %d', num_images, conf.batch_size));

rois_per_image  = conf.batch_size / num_images; % regions per image
num_images  = length(image_roidb);
sampled_regions_loc = cell(num_images, 1);
for i = 1:num_images
    num_regions = size(image_roidb(i).windows_bbox_loc,1);
    % sample rois_per_image number of regions from this image
    indices = randperm(num_regions, min(rois_per_image, num_regions));
    windows_bbox_loc_this = image_roidb(i).windows_bbox_loc(indices,:);
    region_inds_loc = windows_bbox_loc_this(:,1);
    % load the entire set of training regions of this image (cached in disk)
    regions = load_img_regions(image_roidb(i).regions);
    % keep only the regions of this minibatch
    bboxes = regions(region_inds_loc,1:4);
    sampled_regions_loc{i} = single([bboxes,windows_bbox_loc_this(:,2:3)]);
end
end

function [im_blob, im_scales, image_sizes, im_scaled_size] = GetImageBlob(model, image_roidb)
% This function comes from the Faster R-CNN code and the matlab
% re-implementation of Fast-RCNN (https://github.com/ShaoqingRen/faster_rcnn)

num_images     = length(image_roidb);
random_scale_inds = randi(length(model.scales), num_images, 1);
processed_imgs = cell(num_images, 1);
im_scales      = nan(num_images, 1);
image_sizes    = nan(num_images, 2);
im_scaled_size = nan(num_images, 2);
for i = 1:num_images
    img = get_image(image_roidb(i).image_path);
    image_sizes(i,1) = size(img,1);
    image_sizes(i,2) = size(img,2);
    target_size = model.scales(random_scale_inds(i));
    [processed_imgs{i}, im_scales(i), im_scaled_size(i,:)] = prepare_img_blob(img, ...
        target_size, model.mean_pix, model.max_size);
end

im_blob = img_list_to_blob(processed_imgs);
end

function image_db = setup_image_db(image_db, conf)
num_imgs = length(image_db.image_paths);
image_db.all_windows_bbox_loc = cell(num_imgs, 1);
num_regions_fg_loc = zeros(num_imgs, 1);

cache_regions_dir = image_db.cache_regions_dir;
all_region_files  = strcat(cache_regions_dir, getImageIdsFromImagePaths( image_db.image_paths ),'.mat');

for i = 1:num_imgs
    % find for each image its training bounding boxes and their
    % corresponding target bounding boxes
    [image_db.all_regions{i}, image_db.all_windows_bbox_loc{i}, num_regions_fg_loc(i)] = ...
        setup_img_data(image_db.all_bbox_gt{i}, image_db.all_regions{i}, conf);

    % cache the training bounding boxes in the hard disk (for large
    % datasets, such as MSCOCO, is in-efficient memory wise to keep the
    % training boxes in the memory)
    save_img_regions(image_db.all_regions{i}, all_region_files{i});
    image_db.all_regions{i} = [];
    tic_toc_print('setup img data %d / % d (%.2f)\n', i, num_imgs, 100*i/num_imgs);
end

image_db.all_regions = [];
image_db.all_regions = all_region_files;

is_valid = (num_regions_fg_loc > 0);

fprintf('valid: %d/%d (%.3f) \n', sum(is_valid),length(is_valid),sum(is_valid)/length(is_valid));

image_db.image_paths          = image_db.image_paths(is_valid);
image_db.all_regions          = image_db.all_regions(is_valid);
image_db.all_windows_bbox_loc = image_db.all_windows_bbox_loc(is_valid);
image_db.all_bbox_gt          = image_db.all_bbox_gt(is_valid);
num_regions_fg_loc            = num_regions_fg_loc(is_valid);

image_db.images = cell2struct(...
    [image_db.image_paths, image_db.all_regions, ...
     image_db.all_windows_bbox_loc, image_db.all_bbox_gt], ...
    {'image_path', 'regions', 'windows_bbox_loc', 'bbox_gt'}, 2);

image_db = rmfield(image_db, 'image_paths');
image_db = rmfield(image_db, 'all_regions');
image_db = rmfield(image_db, 'all_windows_bbox_loc');
image_db = rmfield(image_db, 'all_bbox_gt');

fprintf('Total number of fg regions for localization: %d\n', sum(num_regions_fg_loc))

num_classes = length(image_db.classes);
fg_per_class = zeros(num_classes,1);
gt_per_class = zeros(num_classes,1);
labels_per_img = -ones(num_imgs,num_classes,'single');
for i = 1:num_imgs
    class_ids         = image_db.images(i).windows_bbox_loc(:,end);
    fg_per_class_this = accumarray(class_ids, 1, [num_classes, 1]);
    fg_per_class      = fg_per_class+fg_per_class_this;
    gt_per_class_this = accumarray(image_db.images(i).bbox_gt(:,5),1,[num_classes, 1]);
    gt_per_class      = gt_per_class + gt_per_class_this;

    unique_class_ids = unique(class_ids);
    labels_per_img(i,unique_class_ids) = 1;
end

% print the number of training boxes and grount truth bounding boxes per
% category
fprintf('Regions / GTs per class:\n');
for i = 1:num_classes
    fprintf('Category %d: FG %d GT %d R %.2f\n',i, fg_per_class(i), gt_per_class(i), fg_per_class(i)/gt_per_class(i));
end

image_db.gt_per_class   = gt_per_class;
image_db.fg_per_class   = fg_per_class;
image_db.labels_per_img = labels_per_img;
end

function [bbox_proposals, windows_bbox_loc, num_regions_fg_loc] = ...
    setup_img_data(bbox_gt, bbox_proposals, conf)

num_classes           = conf.num_classes;
fg_threshold_bbox_loc = conf.fg_threshold_bbox_loc;

bbox_gt_label = bbox_gt(:,5);
bbox_all = [bbox_gt(:,1:4); bbox_proposals(:,1:4)];
overlaps = zeros(size(bbox_all,1), num_classes, 'single');

windows_bbox_loc = cell(num_classes, 1);
for class_idx = 1:num_classes
    this_class_ind = find(bbox_gt_label == class_idx);

    windows_bbox_loc{class_idx} = zeros(0,3,'single');
    if ~isempty(this_class_ind)
        overlap_class = single(boxoverlap(bbox_all(:,1:4), bbox_gt(this_class_ind,1:4)));
        [overlaps(:, class_idx), gt_index] = max(overlap_class, [], 2);

        this_class_pr_index = find(overlaps(:, class_idx) >= fg_threshold_bbox_loc);
        if ~isempty(this_class_pr_index)
            this_class_gt_index = this_class_ind(gt_index);
            this_class_gt_index = this_class_gt_index(this_class_pr_index);
            windows_bbox_loc{class_idx} = ...
                single([this_class_pr_index(:), this_class_gt_index(:), ...
                ones(length(this_class_pr_index),1)*class_idx]);
        end
    end
end
windows_bbox_loc = single(cell2mat(windows_bbox_loc)); % label, overlap, bbox_init, bbox_target
num_regions_fg_loc = size(windows_bbox_loc,1);

% remove unecesary bbox proposals...
pr_ind = windows_bbox_loc(:,1);
[pr_ind_u, ~, pr_ind_new] = unique(pr_ind);
bbox_proposals = bbox_all(pr_ind_u,1:4);
assert(all(all(bbox_proposals(pr_ind_new,1:4)==bbox_all(pr_ind,1:4))))
windows_bbox_loc(:,1) = pr_ind_new;
end

function save_img_regions(regions, regions_file)
if ~(exist(regions_file,'file')>0)
    save(regions_file, 'regions', '-v7.3');
end
end

function regions = load_img_regions(regions_file)
load(regions_file, 'regions');
end


% eegplot2event() - convert EEGPLOT rejections into events
%                   compatible with EEGLAB format for continuous
%                   datasets.
%
% Usage:
%   >> [events] = eegplot2event( eegplotrej, type, colorin, colorout );
%
% Inputs:
%   eegplotrej - EEGPLOT output (TMPREJ; see eegplot for more details)
%   type       - type of the event. Default -1.
%   colorin    - only extract rejection of specific colors (here a n x 3
%                array must be given). Default: extract all rejections.
%   colorout   - do not extract rejection of specified colors.
%
% Outputs:
%   events     - array of events in the EEGLAB format.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: eegplot(), eeg_multieegplot(), eegplot2trial(), eeglab()

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function events = eegplot2trial( TMPREJ, type, color, colorout );

if nargin < 1
   help eegplot2event;
   return;
end;

if nargin < 2
   type = -1;
end;

% only take into account specific colors
% --------------------------------------
if exist('color') == 1
	for index = 1:size(color,1)
   		tmpcol1 = TMPREJ(:,3) + 255*TMPREJ(:,4) + 255*255*TMPREJ(:,5);
   		tmpcol2 = color(index,1)+255*color(index,2)+255*255*color(index,3);
   		I = find( tmpcol1 == tmpcol2);
   		if isempty(I)
      		fprintf('Warning: color [%d %d %d] not found\n', ...
      			color(index,1), color(index,2), color(index,3));
   		end;
   		TMPREJ = TMPREJ(I,:);
   	end;
end;

% remove other specific colors
% ----------------------------
if exist('colorout') == 1
	for index = 1:size(colorout,1)
   		tmpcol1 = TMPREJ(:,3) + 255*TMPREJ(:,4) + 255*255*TMPREJ(:,5);
   		tmpcol2 = colorout(index,1)+255*colorout(index,2)+255*255*colorout(index,3);
   		I = find( tmpcol1 ~= tmpcol2);
   		TMPREJ = TMPREJ(I,:);
   	end;
end;

events = [];
if ~isempty(TMPREJ)
   events = TMPREJ(:,1:5);
   events = [ type*ones(size(events,1), 1) ones(size(events,1), 1) round(events(:,1:2)) events(:,3:5)];
end;

return;


  function y = fatrix2_maskit(mask, x)
%|function y = fatrix2_maskit(mask, x)
%|
%| Apply mask to x (replicating if needed via bsxfun).
%| If mask is empty, then y := x.
%|
%| Used as part of many "back" (adjoint) methods to comply with fatrix2
%| requirement that "back" method apply the mask.

if nargin < 2, ir_usage, end

if isempty(mask)
	y = x;
elseif isequal(size(mask), size(x))
	y = mask .* x;
else
	siz = size(x);
	size_mask = size(mask);
	if numel(size_mask) == 2 && size_mask(2) == 1
		size_mask = size_mask(1);
		ndim_mask = 1;
	else
		ndim_mask = ndims(mask);
	end
	if ~isequal(size_mask, siz(1:ndim_mask))
		pr size(mask)
		pr size(x)
		fail 'size mismatch'
	end
	y = bsxfun(@times, mask, x);
end


function data = loadjson(fname,varargin)
%
% data=loadjson(fname,opt)
%    or
% data=loadjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
%            date: 2011/09/09
%         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
%            date: 2009/11/02
%         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
%            date: 2009/03/22
%         Joel Feenstra:
%         http://www.mathworks.com/matlabcentral/fileexchange/20565
%            date: 2008/07/03
%
% $Id: loadjson.m 415 2013-10-07 16:38:31Z fangq $
%
% input:
%      fname: input file name, if fname contains "{}" or "[]", fname
%             will be interpreted as a JSON string
%      opt: a struct to store parsing options, opt can be replaced by
%           a list of ('param',value) pairs. The param string is equivallent
%           to a field in opt.
%
% output:
%      dat: a cell array, where {...} blocks are converted into cell arrays,
%           and [...] are converted to arrays
%
% license:
%     BSD license, see LICENSE_BSD.txt files for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%

global pos inStr len  esc index_esc len_esc isoct arraytoken

if(regexp(fname,'[\{\}\]\[]','once'))
   string=fname;
elseif(exist(fname,'file'))
   fid = fopen(fname,'rt');
   string = fscanf(fid,'%c');
   fclose(fid);
else
   error('input file does not exist');
end

pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\','  ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);

% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);

opt=varargin2struct(varargin{:});
jsoncount=1;
while pos <= len
    switch(next_char)
        case '{'
            data{jsoncount} = parse_object(opt);
        case '['
            data{jsoncount} = parse_array(opt);
        otherwise
            error_pos('Outer level structure must be an object or an array');
    end
    jsoncount=jsoncount+1;
end % while

jsoncount=length(data);
if(jsoncount==1 && iscell(data))
    data=data{1};
end

if(~isempty(data))
      if(isstruct(data)) % data can be a struct array
          data=jstruct2array(data);
      elseif(iscell(data))
          data=jcell2array(data);
      end
end

%%
function newdata=parse_collection(id,data,obj)

if(jsoncount>0 && exist('data','var'))
    if(~iscell(data))
       newdata=cell(1);
       newdata{1}=data;
       data=newdata;
    end
end

%%
function newdata=jcell2array(data)
len=length(data);
newdata=data;
for i=1:len
      if(isstruct(data{i}))
          newdata{i}=jstruct2array(data{i});
      elseif(iscell(data{i}))
          newdata{i}=jcell2array(data{i});
      end
end

%%-------------------------------------------------------------------------
function newdata=jstruct2array(data)
fn=fieldnames(data);
newdata=data;
len=length(data);
for i=1:length(fn) % depth-first
    for j=1:len
        if(isstruct(getfield(data(j),fn{i})))
            newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
        end
    end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
  newdata=cell(len,1);
  for j=1:len
    ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
    iscpx=0;
    if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
        if(data(j).x0x5F_ArrayIsComplex_)
           iscpx=1;
        end
    end
    if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
        if(data(j).x0x5F_ArrayIsSparse_)
            if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
                dim=data(j).x0x5F_ArraySize_;
                if(iscpx && size(ndata,2)==4-any(dim==1))
                    ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
                end
                if isempty(ndata)
                    % All-zeros sparse
                    ndata=sparse(dim(1),prod(dim(2:end)));
                elseif dim(1)==1
                    % Sparse row vector
                    ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
                elseif dim(2)==1
                    % Sparse column vector
                    ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
                else
                    % Generic sparse array.
                    ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
                end
            else
                if(iscpx && size(ndata,2)==4)
                    ndata(:,3)=complex(ndata(:,3),ndata(:,4));
                end
                ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
            end
        end
    elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
        if(iscpx && size(ndata,2)==2)
             ndata=complex(ndata(:,1),ndata(:,2));
        end
        ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
    end
    newdata{j}=ndata;
  end
  if(len==1)
      newdata=newdata{1};
  end
end

%%-------------------------------------------------------------------------
function object = parse_object(varargin)
    parse_char('{');
    object = [];
    if next_char ~= '}'
        while 1
            str = parseStr(varargin{:});
            if isempty(str)
                error_pos('Name of value at position %d cannot be empty');
            end
            parse_char(':');
            val = parse_value(varargin{:});
            eval( sprintf( 'object.%s  = val;', valid_field(str) ) );
            if next_char == '}'
                break;
            end
            parse_char(',');
        end
    end
    parse_char('}');

%%-------------------------------------------------------------------------

function object = parse_array(varargin) % JSON array is written in row-major order
global pos inStr isoct
    parse_char('[');
    object = cell(0, 1);
    dim2=[];
    if next_char ~= ']'
        [endpos e1l e1r maxlevel]=matching_bracket(inStr,pos);
        arraystr=['[' inStr(pos:endpos)];
        arraystr=regexprep(arraystr,'"_NaN_"','NaN');
        arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
        arraystr(find(arraystr==sprintf('\n')))=[];
        arraystr(find(arraystr==sprintf('\r')))=[];
        %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
        if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
            astr=inStr((e1l+1):(e1r-1));
            astr=regexprep(astr,'"_NaN_"','NaN');
            astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
            astr(find(astr==sprintf('\n')))=[];
            astr(find(astr==sprintf('\r')))=[];
            astr(find(astr==' '))='';
            if(isempty(find(astr=='[', 1))) % array is 2D
                dim2=length(sscanf(astr,'%f,',[1 inf]));
            end
        else % array is 1D
            astr=arraystr(2:end-1);
            astr(find(astr==' '))='';
            [obj count errmsg nextidx]=sscanf(astr,'%f,',[1,inf]);
            if(nextidx>=length(astr)-1)
                object=obj;
                pos=endpos;
                parse_char(']');
                return;
            end
        end
        if(~isempty(dim2))
            astr=arraystr;
            astr(find(astr=='['))='';
            astr(find(astr==']'))='';
            astr(find(astr==' '))='';
            [obj count errmsg nextidx]=sscanf(astr,'%f,',inf);
            if(nextidx>=length(astr)-1)
                object=reshape(obj,dim2,numel(obj)/dim2)';
                pos=endpos;
                parse_char(']');
                return;
            end
        end
        arraystr=regexprep(arraystr,'\]\s*,','];');
        try
           if(isoct && regexp(arraystr,'"','once'))
                error('Octave eval can produce empty cells for JSON-like input');
           end
           object=eval(arraystr);
           pos=endpos;
        catch
         while 1
            val = parse_value(varargin{:});
            object{end+1} = val;
            if next_char == ']'
                break;
            end
            parse_char(',');
         end
        end
    end
    if(jsonopt('SimplifyCell',0,varargin{:})==1)
      try
        oldobj=object;
        object=cell2mat(object')';
        if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
            object=oldobj;
        elseif(size(object,1)>1 && ndims(object)==2)
            object=object';
        end
      catch
      end
    end
    parse_char(']');

%%-------------------------------------------------------------------------

function parse_char(c)
    global pos inStr len
    skip_whitespace;
    if pos > len || inStr(pos) ~= c
        error_pos(sprintf('Expected %c at position %%d', c));
    else
        pos = pos + 1;
        skip_whitespace;
    end

%%-------------------------------------------------------------------------

function c = next_char
    global pos inStr len
    skip_whitespace;
    if pos > len
        c = [];
    else
        c = inStr(pos);
    end

%%-------------------------------------------------------------------------

function skip_whitespace
    global pos inStr len
    while pos <= len && isspace(inStr(pos))
        pos = pos + 1;
    end

%%-------------------------------------------------------------------------
function str = parseStr(varargin)
    global pos inStr len  esc index_esc len_esc
 % len, ns = length(inStr), keyboard
    if inStr(pos) ~= '"'
        error_pos('String starting with " expected at position %d');
    else
        pos = pos + 1;
    end
    str = '';
    while pos <= len
        while index_esc <= len_esc && esc(index_esc) < pos
            index_esc = index_esc + 1;
        end
        if index_esc > len_esc
            str = [str inStr(pos:len)];
            pos = len + 1;
            break;
        else
            str = [str inStr(pos:esc(index_esc)-1)];
            pos = esc(index_esc);
        end
        nstr = length(str); switch inStr(pos)
            case '"'
                pos = pos + 1;
                if(~isempty(str))
                    if(strcmp(str,'_Inf_'))
                        str=Inf;
                    elseif(strcmp(str,'-_Inf_'))
                        str=-Inf;
                    elseif(strcmp(str,'_NaN_'))
                        str=NaN;
                    end
                end
                return;
            case '\'
                if pos+1 > len
                    error_pos('End of file reached right after escape character');
                end
                pos = pos + 1;
                switch inStr(pos)
                    case {'"' '\' '/'}
                        str(nstr+1) = inStr(pos);
                        pos = pos + 1;
                    case {'b' 'f' 'n' 'r' 't'}
                        str(nstr+1) = sprintf(['\' inStr(pos)]);
                        pos = pos + 1;
                    case 'u'
                        if pos+4 > len
                            error_pos('End of file reached in escaped unicode character');
                        end
                        str(nstr+(1:6)) = inStr(pos-1:pos+4);
                        pos = pos + 5;
                end
            otherwise % should never happen
                str(nstr+1) = inStr(pos), keyboard
                pos = pos + 1;
        end
    end
    error_pos('End of file while expecting end of inStr');

%%-------------------------------------------------------------------------

function num = parse_number(varargin)
    global pos inStr len isoct
    currstr=inStr(pos:end);
    numstr=0;
    if(isoct~=0)
        numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
        [num, one] = sscanf(currstr, '%f', 1);
        delta=numstr+1;
    else
        [num, one, err, delta] = sscanf(currstr, '%f', 1);
        if ~isempty(err)
            error_pos('Error reading number at position %d');
        end
    end
    pos = pos + delta-1;

%%-------------------------------------------------------------------------

function val = parse_value(varargin)
    global pos inStr len
    % true = 1; false = 0;

    switch(inStr(pos))
        case '"'
            val = parseStr(varargin{:});
            return;
        case '['
            val = parse_array(varargin{:});
            return;
        case '{'
            val = parse_object(varargin{:});
            if isstruct(val)
                if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
                    val=jstruct2array(val);
                end
            elseif isempty(val)
                val = struct;
            end
            return;
        case {'-','0','1','2','3','4','5','6','7','8','9'}
            val = parse_number(varargin{:});
            return;
        case 't'
            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
                val = true;
                pos = pos + 4;
                return;
            end
        case 'f'
            if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
                val = false;
                pos = pos + 5;
                return;
            end
        case 'n'
            if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
                val = NaN;
                pos = pos + 4;
                return;
            end
    end
    error_pos('Value expected at position %d');
%%-------------------------------------------------------------------------

function error_pos(msg)
    global pos inStr len
    poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
    if poShow(3) == poShow(2)
        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
    end
    msg = [sprintf(msg, pos) ': ' ...
    inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
    error( ['JSONparser:invalidFormat: ' msg] );

%%-------------------------------------------------------------------------

function str = valid_field(str)
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
    pos=regexp(str,'^[^A-Za-z]','once');
    if(~isempty(pos))
        if(~isoct)
            str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
        else
            str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
        end
    end
    if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return;  end
    if(~isoct)
        str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
    else
        pos=regexp(str,'[^0-9A-Za-z_]');
        if(isempty(pos)) return; end
        str0=str;
        pos0=[0 pos(:)' length(str)];
        str='';
        for i=1:length(pos)
            str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
        end
        if(pos(end)~=length(str))
            str=[str str0(pos0(end-1)+1:pos0(end))];
        end
    end
    %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';

%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
len=length(str);
while(pos<len)
    if(str(pos)=='"')
        if(~(pos>1 && str(pos-1)=='\'))
            endpos=pos;
            return;
        end
    end
    pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
    c=tokens(pos);
    if(c==']')
        level=level-1;
        if(isempty(e1r)) e1r=bpos(pos); end
        if(level==0)
            endpos=bpos(pos);
            return
        end
    end
    if(c=='[')
        if(isempty(e1l)) e1l=bpos(pos); end
        level=level+1;
        maxlevel=max(maxlevel,level);
    end
    if(c=='"')
        pos=matching_quote(tokens,pos+1);
    end
    pos=pos+1;
end
if(endpos==0)
    error('unmatched "]"');
end


% SFM
% See also
%
% Visualization
%  montageView           Used to display collections of 2D/3D points
%  playAnim              Display a point cloud animation
%  viewAnimSimilarity    View the similarities within an anim or between 2 anims


function res = badsamples(this, chanind, sampind, trialind)
% Returns an array of 0/1 marking bad data based on artefact events and bad flags
% FORMAT res = badsamples(this, chanind, sampind, trialind)
% _______________________________________________________________________
% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: badsamples.m 7199 2017-11-01 16:42:12Z vladimir $

if ischar(chanind) && isequal(chanind, ':')
    chanind = 1:nchannels(this);
end

if ischar(sampind) && isequal(sampind, ':')
    sampind = 1:nsamples(this);
end

if ischar(trialind) && isequal(trialind, ':')
    trialind = 1:ntrials(this);
end

if ~isequal(type(this), 'continuous') && ~any(trialonset(this))
    error('Trial onset information is not available. Cannot map artefact events to samples.');
end

res = false(length(chanind), nsamples(this), length(trialind));
for i = 1:length(trialind)

    ev = events(this, trialind(i));
    if iscell(ev)
        ev = ev{1};
    end

    if ~isempty(ev)
        ev = ev(intersect(strmatch('artefact', {ev.type}),...
            find(cellfun(@ischar, {ev.value}))));
        for k = 1:numel(ev)
            [dum, chan] = intersect(chanind, selectchannels(this, ev(k).value));
            samples     = find((trialonset(this, trialind(i))+time(this))>=ev(k).time & ...
                (trialonset(this, trialind(i))+time(this))<=(ev(k).time+ev(k).duration));
            res(chan, samples, i) = true;
        end
    end
end

res = res(:, sampind, :);
res(badchannels(this, chanind), :, :) = true;
res(:, :, badtrials(this, trialind))  = true;