function transformFullMap2XML(xmlStruct, map, fileName)
% Creates a new XML file from the information contained in the map
% structure. Uses the function "struct2xml" to transform a matlab
% structure into an XML text format.
%
% USAGE:
%
%   transformFullMap2XML(xmlStruct, map, fileName)
%
% INPUTS:
%   xmlStruct:      XML structure obtained from the function
%                   "xml2struct". Used by the function "struct2xml"
%                   to obtain the XML file.
%   map:            Matlab structure of the map with the relevant
%                   information. This information is then transfered to
%                   the xmlStruct for the conversion.
%   fileName:       Path and name of the new XML file.
%
% .. Author: - N.Sompairac - Institut Curie, Paris, 24/07/2017

    tic

    % Loop over molecules to put the info back to the struct for XML
    % conversion
    for mol = 1:length(map.molAlias)
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.id = map.molAlias{mol};
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.species = map.molID{mol};
        % Check if the info on compartment exists
        if ~isempty(map.molCompartAlias{mol})
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.Attributes.compartmentAlias = map.molCompartAlias{mol};
        end
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.x = map.molXPos{mol};
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.y = map.molYPos{mol};
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.w = map.molWidth{mol};
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_bounds.Attributes.h = map.molHeight{mol};
        xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfSpeciesAliases.celldesigner_colon_speciesAlias{mol}.celldesigner_colon_usualView.celldesigner_colon_paint.Attributes.color = map.molColor{mol};
    end
    clearvars mol

    % Loop over species to put the info back to the struct for XML
    % conversion
    for spec = 1:length(map.specID)
        xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.id = map.specID{spec};
        xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.metaid = map.specMetaID{spec};
        xmlStruct.sbml.model.listOfSpecies.species{spec}.Attributes.name = map.specName{spec};
        xmlStruct.sbml.model.listOfSpecies.species{spec}.annotation.celldesigner_colon_extension.celldesigner_colon_speciesIdentity.celldesigner_colon_name.Text = map.specName{spec};
        xmlStruct.sbml.model.listOfSpecies.species{spec}.annotation.celldesigner_colon_extension.celldesigner_colon_speciesIdentity.celldesigner_colon_class.Text = map.specType{spec};
        % Check if there are notes for the species
        if ~isempty(map.specNotes{spec})
            xmlStruct.sbml.model.listOfSpecies.species{spec}.notes.html.body.Text = map.specNotes{spec};
        end
    end
    clearvars spec

    % Check if there is any information on Compartments
    if ~isempty(map.complexAlias)
        % Loop over complexes to put the info back to the struct for XML
        % conversion
        for k = 1:length(map.complexAlias)
            map.complexAlias{k, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.Attributes.id;
            map.complexID{k, 1} = xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.Attributes.species;
            % Test if info on compartment exists
            if ~isempty(map.complexCompartAlias{k})
                xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.Attributes.compartmentAlias = map.complexCompartAlias{k};
            end
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.celldesigner_colon_bounds.Attributes.x = map.complexXPos{k};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.celldesigner_colon_bounds.Attributes.y = map.complexYPos{k};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.celldesigner_colon_bounds.Attributes.w = map.complexWidth{k};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.celldesigner_colon_bounds.Attributes.h = map.complexHeight{k};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfComplexSpeciesAliases.celldesigner_colon_complexSpeciesAlias{k}.celldesigner_colon_usualView.celldesigner_colon_paint.Attributes.color = map.complexColor{k};
        end
    end

    % Test if included species exist in the map
    if ~isempty(map.specIncID)
        % Loop over included species to get the need information and
        % store it in a structure. Included species refer to each
        % individual species included inside a k.
        for included = 1:length(map.specIncID)
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfIncludedSpecies.celldesigner_colon_species{included}.Attributes.id = map.specIncID{included};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfIncludedSpecies.celldesigner_colon_species{included}.Attributes.name = map.specIncName{included};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfIncludedSpecies.celldesigner_colon_species{included}.celldesigner_colon_annotation.celldesigner_colon_complexSpecies.Text = map.specIncCplxID{included};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfIncludedSpecies.celldesigner_colon_species{included}.celldesigner_colon_annotation.celldesigner_colon_speciesIdentity.celldesigner_colon_class.Text = map.specIncType{included};
            % Test if there are notes for the included species
            if ~isempty(map.specIncNotes)
                xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfIncludedSpecies.celldesigner_colon_species{included}.celldesigner_colon_notes.html.body.Text = map.specIncNotes{included};
            end
        end
    end

    % Loop over reactions to put the info back to the struct for XML
    % conversion
    for react = 1:length(map.rxnID)
        % Check if there is a reaction ID
        if ~isempty(map.rxnID{react})
            xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.id = map.rxnID{react};
        else
            xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.id = 'No_ID';
        end
        xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.metaid = map.rxnMetaID{react};
        % Check if the reaction has a Name
        if ~isempty(map.rxnName{react})
            xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.name = map.rxnName{react};
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_name.Text = map.rxnName{react};
        else
            xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.name = 'No_Name';
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_name.Text = 'No_Name';
        end
        xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_reactionType.Text = map.rxnType{react};
        xmlStruct.sbml.model.listOfReactions.reaction{react}.Attributes.reversible = map.rxnReversibility{react};
        % Test if there is only 1 base reactant
        if length(map.rxnBaseReactantAlias{react}) == 1
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant(1).Attributes.alias = map.rxnBaseReactantAlias{react}{1};
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant(1).Attributes.species = map.rxnBaseReactantID{react}{1};
        else
            for x = 1:length(map.rxnBaseReactantAlias{react})
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant{x}.Attributes.alias = map.rxnBaseReactantAlias{react}{x};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseReactants.celldesigner_colon_baseReactant{x}.Attributes.species = map.rxnBaseReactantID{react}{x};
            end
            clearvars x
        end

        % Test if there is only 1 base product
        if length(map.rxnBaseProductAlias{react}) == 1
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct(1).Attributes.alias = map.rxnBaseProductAlias{react}{1};
            xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct(1).Attributes.species = map.rxnBaseProductID{react}{1};
        else
            for x = 1:length(map.rxnBaseProductAlias{react})
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct{x}.Attributes.alias = map.rxnBaseProductAlias{react}{x};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_baseProducts.celldesigner_colon_baseProduct{x}.Attributes.species = map.rxnBaseProductID{react}{x};
            end
        end
        % Test if there are some reactants in the reaction
        if ~isempty(map.rxnReactantAlias{react})
            % Test if there is only 1 reactant
            if length(map.rxnReactantAlias{react}) == 1
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink.Attributes.alias = map.rxnReactantAlias{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink.Attributes.reactant = map.rxnReactantID{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink.celldesigner_colon_line.Attributes.type = map.rxnReactantLineType{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink.celldesigner_colon_line.Attributes.color = map.rxnReactantLineColor{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink.celldesigner_colon_line.Attributes.width = map.rxnReactantLineWidth{react}{1};
            else
                for x = 1:length(map.rxnReactantAlias{react})
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.Attributes.alias = map.rxnReactantAlias{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.Attributes.reactant = map.rxnReactantID{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.celldesigner_colon_line.Attributes.type = map.rxnReactantLineType{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.celldesigner_colon_line.Attributes.color = map.rxnReactantLineColor{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfReactantLinks.celldesigner_colon_reactantLink{x}.celldesigner_colon_line.Attributes.width = map.rxnReactantLineWidth{react}{x};
                end
                clearvars x
            end
        end

        % Test if there are some products in the reaction
        if ~isempty(map.rxnProductAlias{react})
            % Test if there is only 1 product
            if length(map.rxnProductAlias{react}) == 1
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink.Attributes.alias = map.rxnProductAlias{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink.Attributes.product = map.rxnProductID{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink.celldesigner_colon_line.Attributes.type = map.rxnProductLineType{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink.celldesigner_colon_line.Attributes.color = map.rxnProductLineColor{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink.celldesigner_colon_line.Attributes.width = map.rxnProductLineWidth{react}{1};
            else
                for x = 1:length(map.rxnProductAlias{react})
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.Attributes.alias = map.rxnProductAlias{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.Attributes.product = map.rxnProductID{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.celldesigner_colon_line.Attributes.type = map.rxnProductLineType{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.celldesigner_colon_line.Attributes.color = map.rxnProductLineColor{react}{x};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfProductLinks.celldesigner_colon_productLink{x}.celldesigner_colon_line.Attributes.width = map.rxnProductLineWidth{react}{x};
                end
                clearvars x
            end
        end

        % Check if there are modifications for the reaction
        if ~isempty(map.rxnModAlias{react})
            % Test if there is only one modification
            if length(map.rxnModAlias{react}) == 1
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.aliases = map.rxnModAlias{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.modifiers = map.rxnModID{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).Attributes.type = map.rxnModType{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).celldesigner_colon_line.Attributes.color = map.rxnModColor{react}{1};
                xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification(1).celldesigner_colon_line.Attributes.width = map.rxnModWidth{react}{1};
            else
                for m = 1:length(map.rxnModAlias{react})
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{m}.Attributes.aliases = map.rxnModAlias{react}{m};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{m}.Attributes.modifiers = map.rxnModID{react}{m};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{m}.Attributes.type = map.rxnModType{react}{m};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{m}.celldesigner_colon_line.Attributes.color = map.rxnModColor{react}{m};
                    xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_listOfModification.celldesigner_colon_modification{m}.celldesigner_colon_line.Attributes.width = map.rxnModWidth{react}{m};
                end
                clearvars m
            end
        end

        xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_line.Attributes.color = map.rxnColor{react};
        xmlStruct.sbml.model.listOfReactions.reaction{react}.annotation.celldesigner_colon_extension.celldesigner_colon_line.Attributes.width = map.rxnWidth{react};

        % Check if there are notes for the reaction
        if ~isempty(map.rxnNotes{react})
            xmlStruct.sbml.model.listOfReactions.reaction{react}.notes.html.body.Text = map.rxnNotes{react};
        end
    end
    clearvars react

    % Check if there is any information on Compartments
    if ~isempty(map.compartAlias)
        % Test if there is only 1 compartment
        if length(map.compartAlias) == 1
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias(1).Attributes.id = map.compartAlias{1};
            xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias(1).Attributes.compartment = map.compartName{1};
        else
            % Loop over compartments to put the info back to the struct for XML
            % conversion
            for compart = 1:length(map.compartAlias)
                xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias{compart}.Attributes.id = map.compartAlias{compart};
                xmlStruct.sbml.model.annotation.celldesigner_colon_extension.celldesigner_colon_listOfCompartmentAliases.celldesigner_colon_compartmentAlias{compart}.Attributes.compartment = map.compartName{compart};
            end
            clearvars compart
        end
    end

    struct2xml(xmlStruct, fileName);
    toc

end


classdef VideoWriter < handle
    %VIDEOWRITER  Video Writer class
    %
    % The class provides API for writing video files or image sequences.
    %
    % Note: When querying a property that is not supported by the backend
    % used by the cv.VideoWriter instance, value 0 is returned.
    %
    % ## Example
    % Here is how to write to a video file:
    %
    %     vid = cv.VideoWriter('myvideo.mpg', [640,480]);
    %     vid.write(im);         % add a frame
    %     clear vid;             % finish
    %
    % See also: cv.VideoWriter.VideoWriter, cv.VideoWriter.write,
    %  cv.VideoCapture, VideoWriter, avifile, movie2avi,
    %  vision.VideoFileWriter
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    properties (Dependent)
        % Current quality (0..100%) of the encoded videostream. Can be
        % adjusted dynamically in some codecs.
        Quality

        % Number of stripes for parallel encoding. -1 for auto detection
        NStripes
    end

    properties (Dependent, SetAccess = private)
        % Size of just encoded video frame; note that the encoding order may
        % be different from representation order.
        FrameBytes
    end

    methods
        function this = VideoWriter(varargin)
            %VIDEOWRITER  VideoWriter constructor
            %
            %     vid = cv.VideoWriter()
            %     vid = cv.VideoWriter(filename, frameSize)
            %     vid = cv.VideoWriter(filename, frameSize, 'OptionName',optionValue, ...)
            %
            % ## Output
            % * __vid__ New instance of the VideoWriter
            %
            % The constructor initializes a video writer. When arguments are
            % supplied, the constructor calls the cv.VideoWriter.open method
            % right after creating the object.
            %
            % Accepts the same inputs and options as the cv.VideoWriter.open
            % method.
            %
            % See also: cv.VideoWriter.open, cv.VideoWriter.write
            %
            this.id = VideoWriter_(0, 'new');
            if nargin > 0
                this.open(varargin{:});
            end
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     vid.delete()
            %
            % The method first calls cv.VideoWriter.release to close the
            % already opened file.
            %
            % See also: cv.VideoWriter.release
            %
            if isempty(this.id), return; end
            VideoWriter_(this.id, 'delete');
        end

        function successFlag = open(this, filename, frameSize, varargin)
            %OPEN  Initializes or reinitializes video writer
            %
            %     successFlag = vid.open(filename, frameSize)
            %     successFlag = vid.open(filename, frameSize, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __filename__ Name of the output video file
            % * __frameSize__ Size of the video frames `[width, height]`.
            %
            % ## Output
            % * __successFlag__ bool, true if video writer has been
            %   successfully initialized.
            %
            % ## Options
            % * __API__ The parameter allows to specify API backends to use.
            %   Can be used to enforce a specific writer implementation if
            %   multiple are available: e.g. 'FFMPEG' or 'GStreamer'
            %   * __Any__ (default) Auto detect
            %   * __VfW__ Video For Windows
            %   * __QuickTime__ QuickTime
            %   * __AVFoundation__ AVFoundation framework for iOS
            %   * __MediaFoundation__ Microsoft Media Foundation
            %   * __GStreamer__ GStreamer
            %   * __FFMPEG__ FFMPEG library
            %   * __Images__ OpenCV Image Sequence (e.g. `img_%02d.jpg`)
            %   * __MotionJPEG__ Built-in OpenCV MotionJPEG codec
            %   * __MediaSDK__ Intel Media SDK
            % * __FourCC__ 4-character code of codec used to compress the
            %   frames. List of codes can be obtained at [FOURCC]. FFMPEG
            %   backend with MP4 container natively uses other values as
            %   FourCC code: see [ObjectType], so you may receive a warning
            %   message from OpenCV about fourcc code conversion. Examples are:
            %   * __PIM1__ MPEG-1 codec
            %   * __MJPG__ Motion-JPEG codec (default)
            %   * __MP42__ MPEG-4 (Microsoft)
            %   * __DIV3__ DivX MPEG-4 Part 2
            %   * __DIVX__ DivX codec
            %   * __XVID__ XVID MPEG-4 Part 2
            %   * __U263__ H263
            %   * __I263__ ITU H.263
            %   * __FLV1__ Sorenson Spark (Flash Video)
            %   * __X264__ H.264
            %   * __AVC1__ MPEG-4 Part 10/H.264 (Apple)
            %   * __WMV1__ Windows Media Video 7 (Microsoft)
            %   * __WMV2__ Windows Media Video 8 (Microsoft)
            %   * __-1__ prompts with codec selection dialog (Windows only)
            % * __FPS__ Framerate of the created video stream. default 25.
            % * __Color__ If true, the encoder will expect and encode color
            %   frames, otherwise it will work with grayscale frames (the flag
            %   is currently supported on Windows only). default true
            %
            % The method first calls cv.VideoWriter.release to close the
            % already opened file.
            %
            % The method opens a video writer:
            %
            % * On Linux FFMPEG is used to write videos;
            % * On Windows FFMPEG or VFW is used;
            % * On MacOSX QTKit is used.
            %
            % ### Tips
            % * With some backends `FourCC=-1` pops up the codec selection
            %   dialog from the system.
            % * To save image sequence use a proper filename (eg.
            %   `img_%02d.jpg`) and `FourCC=0` OR `FPS=0`. Use uncompressed
            %   image format (eg. `img_%02d.BMP`) to save raw frames.
            % * Most codecs are lossy. If you want lossless video file you
            %   need to use a lossless codecs (eg. FFMPEG FFV1, Huffman HFYU,
            %   Lagarith LAGS, etc...)
            % * If FFMPEG is enabled, using `codec=0; fps=0;` you can create
            %   an uncompressed (raw) video file.
            %
            % ## References
            % [FOURCC]:
            % > Video Codecs by [FOURCC](http://www.fourcc.org/codecs.php)
            %
            % [ObjectType]:
            % > [Codecs](http://www.mp4ra.org/codecs.html)
            %
            % See also: cv.VideoWriter.VideoWriter, cv.VideoWriter.isOpened
            %
            successFlag = VideoWriter_(this.id, 'open', filename, frameSize, varargin{:});
        end

        function retval = isOpened(this)
            %ISOPENED  Returns true if video writer has been successfully initialized
            %
            %     retval = vid.isOpened()
            %
            % ## Output
            % * __val__ bool, return value
            %
            % Returns true if video writer has been successfully initialized.
            %
            % See also: cv.VideoWriter.open
            %
            retval = VideoWriter_(this.id, 'isOpened');
        end

        function release(this)
            %RELEASE  Closes the video writer
            %
            %     vid.release()
            %
            % The method is automatically called by subsequent
            % cv.VideoWriter.open and by the cv.VideoWriter destructor.
            %
            % See also: cv.VideoWriter.open
            %
            VideoWriter_(this.id, 'release');
        end

        function write(this, frame, varargin)
            %WRITE  Writes the next video frame
            %
            %     vid.write(frame)
            %     vid.write(frame, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __frame__ The written frame
            %
            % ## Options
            % * __FlipChannels__ in case the input is color image, flips the
            %   color order from MATLAB's RGB to OpenCV's BGR order.
            %   default true
            %
            % The method writes the specified image to video file. It must
            % have the same size as has been specified when opening the video
            % writer.
            %
            % See also: cv.VideoWriter.open
            %
            VideoWriter_(this.id, 'write', frame, varargin{:});
        end

        function value = get(this, prop)
            %GET  Returns the specified VideoWriter property
            %
            %     value = vid.get(prop)
            %
            % ## Input
            % * __prop__ Property identifier. It can be specified as a string
            %   (one of the recognized properties), or directly as its
            %   corresponding integer code.
            %
            % ## Output
            % * __value__ Value for the specified property (as a `double`).
            %   Value 0 is returned when querying a property that is not
            %   supported by the backend used by the VideoWriter instance.
            %
            % See also: cv.VideoWriter.set
            %
            value = VideoWriter_(this.id, 'get', prop);
        end

        function set(this, prop, value)
            %SET  Sets a property in the VideoWriter
            %
            %     vid.set(prop, value)
            %
            % ## Input
            % * __prop__ Property identifier. It can be specified as a string
            %   (one of the recognized properties), or directly as its
            %   corresponding integer code.
            % * __value__ Value of the property (as a `double`).
            %
            % On failure (unsupported property by backend), the function
            % issues a warning.
            %
            % See also: cv.VideoWriter.get
            %
            VideoWriter_(this.id, 'set', prop, value);
        end
    end

    %% Getters/Setters
    methods
        function value = get.Quality(this)
            value = VideoWriter_(this.id, 'get', 'Quality');
        end
        function set.Quality(this, value)
            VideoWriter_(this.id, 'set', 'Quality', value);
        end

        function value = get.NStripes(this)
            value = VideoWriter_(this.id, 'get', 'NStripes');
        end
        function set.NStripes(this, value)
            VideoWriter_(this.id, 'set', 'NStripes', value);
        end

        function value = get.FrameBytes(this)
            value = VideoWriter_(this.id, 'get', 'FrameBytes');
        end
    end

end


%% plotV
% Below is a demonstration of the features of the |plotV| function

%%
clear; close all; clc;

%% Syntax
% |varargout=plotV(V,varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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 3 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, see <http://www.gnu.org/licenses/>.


function varargout = subdir(varargin)
%SUBDIR Performs a recursive file search
%
% subdir
% subdir(name)
% files = subdir(...)
%
% This function performs a recursive file search.  The input and output
% format is identical to the dir function.
%
% Input variables:
%
%   name:   pathname or filename for search, can be absolute or relative
%           and wildcards (*) are allowed.  If ommitted, the files in the
%           current working directory and its child folders are returned
%
% Output variables:
%
%   files:  m x 1 structure with the following fields:
%           name:   full filename
%           date:   modification date timestamp
%           bytes:  number of bytes allocated to the file
%           isdir:  1 if name is a directory; 0 if no
%
% Example:
%
%   >> a = subdir(fullfile(matlabroot, 'toolbox', 'matlab', '*.mat'))
%
%   a =
%
%   67x1 struct array with fields:
%       name
%       date
%       bytes
%       isdir
%
%   >> a(2)
%
%   ans =
%
%        name: '/Applications/MATLAB73/toolbox/matlab/audiovideo/chirp.mat'
%        date: '14-Mar-2004 07:31:48'
%       bytes: 25276
%       isdir: 0
%
% See also:
%
%   dir

% Copyright 2006 Kelly Kearney

%---------------------------
% Get folder and filter
%---------------------------

narginchk(0,1);
nargoutchk(0,1);

if nargin == 0
    folder = pwd;
    filter = '*';
else
    [folder, name, ext] = fileparts(varargin{1});
    if isempty(folder)
        folder = pwd;
    end
    if isempty(ext)
        if isdir(fullfile(folder, name))
            folder = fullfile(folder, name);
            filter = '*';
        else
            filter = [name ext];
        end
    else
        filter = [name ext];
    end
    if ~isdir(folder)
        error('Folder (%s) not found', folder);
    end
end

%---------------------------
% Search all folders
%---------------------------

pathstr = genpath_local(folder);
pathfolders = regexp(pathstr, pathsep, 'split');  % Same as strsplit without the error checking
pathfolders = pathfolders(~cellfun('isempty', pathfolders));  % Remove any empty cells

Files = [];
pathandfilt = fullfile(pathfolders, filter);
for ifolder = 1:length(pathandfilt)
    NewFiles = dir(pathandfilt{ifolder});
    if ~isempty(NewFiles)
        fullnames = cellfun(@(a) fullfile(pathfolders{ifolder}, a), {NewFiles.name}, 'UniformOutput', false);
        [NewFiles.name] = deal(fullnames{:});
        Files = [Files; NewFiles];
    end
end

%---------------------------
% Prune . and ..
%---------------------------

if ~isempty(Files)
    [~, ~, tail] = cellfun(@fileparts, {Files(:).name}, 'UniformOutput', false);
    dottest = cellfun(@(x) isempty(regexp(x, '\.+(\w+$)', 'once')), tail);
    Files(dottest & [Files(:).isdir]) = [];
end

%---------------------------
% Output
%---------------------------

if nargout == 0
    if ~isempty(Files)
        fprintf('\n');
        fprintf('%s\n', Files.name);
        fprintf('\n');
    end
elseif nargout == 1
    varargout{1} = Files;
end

function [p] = genpath_local(d)
% Modified genpath that doesn't ignore:
%     - Folders named 'private'
%     - MATLAB class folders (folder name starts with '@')
%     - MATLAB package folders (folder name starts with '+')

files = dir(d);
if isempty(files)
  return
end
p = '';  % Initialize output

% Add d to the path even if it is empty.
p = [p d pathsep];

% Set logical vector for subdirectory entries in d
isdir = logical(cat(1,files.isdir));
dirs = files(isdir);  % Select only directory entries from the current listing

for i=1:length(dirs)
   dirname = dirs(i).name;
   if    ~strcmp( dirname,'.') && ~strcmp( dirname,'..')
       p = [p genpath(fullfile(d,dirname))];  % Recursive calling of this function.
   end
end


% Prepares DSS calculation environment. Currently only compiles the
% testkeypress MEX function.

% Copyright (C) 2004, 2005 DSS MATLAB package team (dss@cis.hut.fi).
% Distributed by Laboratory of Computer and Information Science,
% Helsinki University of Technology. http://www.cis.hut.fi/projects/dss/.
% $Id$

disp('Initializing DSS environment');
disp('Compiling testkeypress executable');

mex src/testkeypress.c;

disp('Environment initialized successfully');


function layer = clean_network_layer(layer)
fields = {'a', 'grad', 'grad_W', 'grad_b', 'acc', 'weights', 'grad_W_raw', 'grad2', 'idx', 'X2', 'ft', 'it', 'ot', 'Ct_raw', 'Ct', 'Ct0', 'ht0', 'post', 'validFrameMask'};
for i=1:length(layer)
    for j=1:length(fields)
        if isfield(layer{i}, fields{j})
            layer{i} = rmfield(layer{i}, fields{j});
        end
    end
end
end


function GUI = sessionGUI_addStudy(study, session, studyDir);
% Add a study to the mrVista GUI, selecting it in the process, and
% initializing with one session.
%
% <GUI> = sessionGUI_addStudy(<study=dialog>, <session=dialog>, <studyDir=''>);
%
% This function will update or create the saved studies file
% (saved in the mrVista 2 repository: mrVista2/study/studies.mat)
% with the new session, as well as adding it to the GUI.
%
%
% ras, 07/06.
mrGlobals2;

if notDefined('studyDir'), studyDir = ''; end

if notDefined('study')              % dialog
    study = inputdlg({'Name of the new study'}, mfilename);
    if isempty(study), return; end
    study = study{1};
end

if notDefined('session')            % dialog
    p = 'Select a first session to add to this study ';
    session = sessionSelectDialog(1, p);
end

% create the new study
n = length(GUI.studies) + 1; % index into new study
GUI.studies(n) = studyCreate(study);
GUI.studies(n).studyDir = studyDir;

% select the study
GUI = sessionGUI_selectStudy(study);

% add the first session to it
GUI = sessionGUI_addSession(session);

% save the updated studies file
studyPath = studySave(GUI.studies);
fprintf('Studies file %s updated.\n', studyPath);

return


% --------------------------
% XML TOOLBOX FOR MATLAB 3.1
% --------------------------
%
% FUNCTIONS:
%  xml_format       converts a Matlab variable into XML string
%  xml_formatany    converts a Matlab variable into XML string with attributes
%  xml_parse        parses & converts XML string into Matlab structure
%  xml_parseany     parses & converts XML string into Matlab structure with attributes
%  xml_save         saves a Matlab variable/structure in XML format in a file
%  xml_load         loads the .xml file written with xml_save back into a variable
%  xml_help         this file, displays info about available xml_* commands
%  tests/xml_tests  tests the xml toolbox by writing/reading a number of xml test files
%  strsplit         utility function which splits a string at specified characters
%  unblank          utility function which removes leading and trailing spaces
%
% FILES:
%  doc/xml_matlab   documentation containing info on installation, usage, implementation, etc.
%  matlab.xsd       contains the Schema to validate xml files for the toolbox
%                   (if not present, look at http://www.geodise.org/matlab.xsd)
%
% RELATED:
%  xmlread, xmlwrite (shipped with Matlab from version 6.5)
%
% Further information can be obtained by using the help command on
% a specific function, e.g. help xml_format or by visiting
% http://www.geodise.org

% Copyright (C) 2002-2005, University of Southampton
% Author: Dr Marc Molinari <m.molinari@soton.ac.uk>
% $Revision: 1.1 $ $Date: 2005/04/15 17:12:14 $ $Tag$


function model = gpReversibleDynamicsExpandParam(model, params)

% GPREVERSIBLEDYNAMICSEXPANDPARAM Place the parameters vector into the model for GP dynamics.

% FGPLVM

model = gpDynamicsExpandParam(model, params);


classdef LaunchVehicleBasicElectricalBatteryState < AbstractLaunchVehicleEpsStorageState
    %LaunchVehicleBasicElectricalBatteryState Summary of this class goes here
    %   Detailed explanation goes here

    properties
        stageState = LaunchVehicleStageState.empty(1,0)% LaunchVehicleStageState
        battery% LaunchVehicleBasicElectricalBattery

        stateOfCharge = 0%(1,1) double = 0; %mT
        active(1,1) logical = true;
    end

    methods
        function obj = LaunchVehicleBasicElectricalBatteryState(stageState, battery)
            obj.stageState = stageState;
            obj.battery = battery;
        end

        function epsStorageComponent = getEpsStorageComponent(obj)
            epsStorageComponent = [obj.battery];
        end

        function active = getActiveState(obj)
            active = [obj.active];
        end

        function setActiveState(obj,active)
            obj.active = active;
        end

        function stateOfCharge = getStateOfCharge(obj)
            stateOfCharge = obj.stateOfCharge;
        end

        function setStateOfCharge(obj, stateOfCharge)
            obj.stateOfCharge = stateOfCharge;
        end
    end
end


function benchmark_tracker_wrapper(tracker_name, runfile_name, do_cleanup)

if nargin < 3
    do_cleanup = true;
end

% *************************************************************
% VOT: Always call exit command at the end to terminate Matlab!
% *************************************************************
if do_cleanup
    cleanup = onCleanup(@() exit() );
else
    [pathstr, ~, ~] = fileparts(mfilename('fullpath'));
    cd_ind = strfind(pathstr, filesep());
    pathstr = pathstr(1:cd_ind(end)-1);
    cleanup = onCleanup(@() cd(pathstr));
end

try

% *************************************************************
% VOT: Set random seed to a different value every time.
% *************************************************************
RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', sum(clock)));

seq.format = 'vot';

setup_tracker_paths(tracker_name);

disp([runfile_name '(seq, [], []);']);
res = eval([runfile_name '(seq, [], []);']);

catch err
    [wrapper_pathstr, ~, ~] = fileparts(mfilename('fullpath'));
    cd_ind = strfind(wrapper_pathstr, filesep());
    VOT_path = wrapper_pathstr(1:cd_ind(end));

    error_report_path = [VOT_path 'error_reports/'];
    if ~exist(error_report_path, 'dir')
        mkdir(error_report_path);
    end

    report_file_name = [error_report_path tracker_name '_' runfile_name datestr(now,'_yymmdd_HHMM') '.mat'];

    save(report_file_name, 'err')

    rethrow(err);
end


function [outputMovie] = createSideBySide(primaryMovie,secondaryMovie,varargin)
	% Auto-create side-by-side, either save output as hdf5 or return a matrix
	% Biafra Ahanonu
	% started: 2014.01.04 (code taken from controllerAnalysis)
	% inputs
		% primaryMovie - string pointing to the video file (.avi, .tif, or .hdf5 supported, auto-detects based on extension) OR a matrix
		% secondaryMovie - string pointing to the video file (.avi, .tif, or .hdf5 supported, auto-detects based on extension) OR a matrix
	% outputs
		% outputMovie - horizontally concatenated movie
	% changelog
		% 2014.01.27 [22:57:19] - changed to allow input of either a path or a matrix, more generalized
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		% allow option for vertical concat?
		% spatio-temporal should be one abstracted for-loop, no? - DONE 2014.01.27 [21:52:37]

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	% ========================
	% number of frames in each movie to load, [] = all, 1:500 would be 1st to 500th frame.
	options.frameList = [];
	% if want a different set of frames loaded for the second movie
	options.frameListSecondary = [];
	% whether to convert movie to double on load, not recommended
	options.convertToDouble = 0;
	% name of HDF5 dataset name to load
	options.inputDatasetName = '/1';
	% string to a movie, preferably AVI
	options.recordMovie = 0;
	% amount of pixels around the border to crop in primary movie
	options.pxToCrop = [];
	% downsample combined movie
	options.downsampleFactorFinal = 1;
	% make movies equal by using NaN instead of temporal downsampling.
	options.makeTimeEqualUsingNans = 0;
	% 1 = yes, 0 = no. whether to normalize each movies pixel distribution between [0 1]
	options.normalizeMovies = 1;
	% rotate xy dims of second movie
	options.rotateSecondMovie = 0;
	% rotate xy dims of primary movie
	options.rotatePrimaryMovie = 0;
	% Binary: 1 = increase to largest movie instead of downsampling to the smallest movie.
	options.increaseToLargestMovie = 0;
	% Binary: 1 = display info
	options.displayInfo = 1;
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	try
		% ========================
		% get the movie
		if strcmp(class(primaryMovie),'char')|strcmp(class(primaryMovie),'cell')
			primaryMovie = loadMovieList(primaryMovie,'convertToDouble',options.convertToDouble,'frameList',options.frameList,'inputDatasetName',options.inputDatasetName);
		end

		% load secondary movie
		if isempty(options.frameListSecondary)
			if strcmp(class(secondaryMovie),'char')|strcmp(class(secondaryMovie),'cell')
				secondaryMovie = loadMovieList(secondaryMovie,'convertToDouble',options.convertToDouble,'frameList',options.frameList);
			end
		else
			if strcmp(class(secondaryMovie),'char')|strcmp(class(secondaryMovie),'cell')
				secondaryMovie = loadMovieList(secondaryMovie,'convertToDouble',options.convertToDouble,'frameList',options.frameListSecondary);
			end
		end
		% ========================
		% If movies are 4D rgb ([x y t c] where c = 3 for RGB colors) then call function again again for each dimension then concat the resulting individual RGB movies into a single output movie
		primaryDimNum = length(size(primaryMovie));
		secondaryDimNum = length(size(secondaryMovie));
		if primaryDimNum==4|secondaryDimNum==4
			subfxnDisp('4D movie detected...')

			% get size of 4th dim depending on which input is 4D
			if secondaryDimNum==4&primaryDimNum~=4
				nColorDims = size(secondaryMovie,4);
			else
				nColorDims = size(primaryMovie,4);
			end
			sideBySideMatrix = {};
			for colorNo = 1:nColorDims
				subfxnDisp(repmat('=',1,21))
				subfxnDisp(['color: ' num2str(colorNo) '/' num2str(nColorDims)])
				if secondaryDimNum==4
					if primaryDimNum==4
						sideBySideMatrix{colorNo} = createSideBySide(squeeze(primaryMovie(:,:,:,colorNo)),squeeze(secondaryMovie(:,:,:,colorNo)),'options',options);
					else
						sideBySideMatrix{colorNo} = createSideBySide(primaryMovie,squeeze(secondaryMovie(:,:,:,colorNo)),'options',options);
					end
				else
					sideBySideMatrix{colorNo} = createSideBySide(squeeze(primaryMovie(:,:,:,colorNo)),secondaryMovie,'options',options);
				end
			end
			outputMovie = cat(4,sideBySideMatrix{:});
			return;
		end

		if options.rotatePrimaryMovie==1
			subfxnDisp('rotating...')
			subfxnDisp(['pre-rotation dims: ' num2str(size(primaryMovie))])
			primaryMovie = permute(primaryMovie,[2 1 3]);
			subfxnDisp(['post-rotation dims: ' num2str(size(primaryMovie))])
		end
		if options.rotateSecondMovie==1
			subfxnDisp('rotating...')
			subfxnDisp(['pre-rotation dims: ' num2str(size(secondaryMovie))])
			secondaryMovie = permute(secondaryMovie,[2 1 3]);
			subfxnDisp(['post-rotation dims: ' num2str(size(secondaryMovie))])
		end

		% ========================
		% make movies single for calculations sake
		% primaryMovie = single(primaryMovie);
		% secondaryMovie = single(secondaryMovie);

		% ========================
		subfxnDisp('cropping primary movie...')
		% Get the x and y corner coordinates as integers
		if ~isempty(options.pxToCrop)
			if size(primaryMovie,2)>=size(primaryMovie,1)
				coords(1) = options.pxToCrop; %xmin
				coords(2) = options.pxToCrop; %ymin
				coords(3) = size(primaryMovie,1)-options.pxToCrop;   %xmax
				coords(4) = size(primaryMovie,2)-options.pxToCrop;   %ymax
			else
				coords(1) = options.pxToCrop; %xmin
				coords(2) = options.pxToCrop; %ymin
				coords(4) = size(primaryMovie,1)-options.pxToCrop;   %xmax
				coords(3) = size(primaryMovie,2)-options.pxToCrop;   %ymax
			end
			rowLen = size(primaryMovie,1);
			colLen = size(primaryMovie,2);
			% a,b are left/right column values
			a = coords(1);
			b = coords(3);
			% c,d are top/bottom row values
			c = coords(2);
			d = coords(4);
			cropChoice = 2;
			switch cropChoice
				case 1
					primaryMovie(1:rowLen,1:a,:) = NaN;
					primaryMovie(1:rowLen,b:colLen,:) = NaN;
					primaryMovie(1:c,1:colLen,:) = NaN;
					primaryMovie(d:rowLen,1:colLen,:) = NaN;
				case 2
					primaryMovie = primaryMovie(coords(2):coords(4), coords(1): coords(3),:);
				otherwise

			end
		end
		% ========================
		subfxnDisp('making movies spatially and temporally identical...')
		% to generalize out downsampling, create cell arrays to call that contain the dimension information
		dimensionList = {3, 2, 1};
		dimensionNameList = {'time','space','space'};
		% loop over each of the dimensions to resize to
		loopList = [1 3]; %1:length(dimensionList)
		for i=loopList
			thisDim = dimensionList{i};
			thisDimName = dimensionNameList{i};
			lengthPrimary = size(primaryMovie,thisDim);
			lengthSecond = size(secondaryMovie,thisDim);
			subfxnDisp(['length primary: ' num2str(lengthPrimary)])
			subfxnDisp(['length secondary: ' num2str(lengthSecond)])
			if options.makeTimeEqualUsingNans==1&strcmp(thisDimName,'time')
				if lengthPrimary>lengthSecond
					subfxnDisp('adding NaNs to end of second movie...')
					movieDiff = lengthPrimary-lengthSecond;
					secondaryMovie(:,:,end+movieDiff) = NaN;
				elseif lengthSecond>lengthPrimary
					subfxnDisp('adding NaNs to end of first movie...')
					movieDiff = lengthSecond-lengthPrimary;
					primaryMovie(:,:,end+movieDiff) = NaN;
				end
				continue
			end
			if lengthPrimary>lengthSecond
				% display(['downsampling: ' movieList{1}]);
				if options.increaseToLargestMovie==1
					downsampleFactor = lengthSecond/lengthPrimary;
					secondaryMovie = downsampleMovie(secondaryMovie,'downsampleDimension',thisDimName,'downsampleFactor',downsampleFactor,'downsampleZ',lengthPrimary,'downsampleX',lengthPrimary);
				else
					downsampleFactor = lengthPrimary/lengthSecond;
					primaryMovie = downsampleMovie(primaryMovie,'downsampleDimension',thisDimName,'downsampleFactor',downsampleFactor,'downsampleZ',lengthSecond,'downsampleX',lengthSecond);
				end
			elseif lengthSecond>lengthPrimary
				% display(['downsampling: ' vidList{1}]);
				if options.increaseToLargestMovie==1
					downsampleFactor = lengthPrimary/lengthSecond;
					primaryMovie = downsampleMovie(primaryMovie,'downsampleDimension',thisDimName,'downsampleFactor',downsampleFactor,'downsampleZ',lengthSecond,'downsampleX',lengthSecond);
				else
					downsampleFactor = lengthSecond/lengthPrimary;
					secondaryMovie = downsampleMovie(secondaryMovie,'downsampleDimension',thisDimName,'downsampleFactor',downsampleFactor,'downsampleZ',lengthPrimary,'downsampleX',lengthPrimary);
				end
			end
		end
		%========================
		% normalize movies between 0 and 1 so they display correctly together, better if their distributions are the same
		if options.normalizeMovies==1
			subfxnDisp('normalizing movies...')
			[primaryMovie] = normalizeVector(single(primaryMovie),'normRange','zeroToOne');
			[primaryMovie] = normalizeMovie(primaryMovie,'normalizationType','meanSubtraction');
			[secondaryMovie] = normalizeVector(single(secondaryMovie),'normRange','zeroToOne');
			[secondaryMovie] = normalizeMovie(secondaryMovie,'normalizationType','meanSubtraction');
		end
		% ========================
		% horizontally concat the movies
		subfxnDisp('concatenating movies...')
		subfxnDisp(['size primary: ' num2str(size(primaryMovie))])
		subfxnDisp(['size secondary: ' num2str(size(secondaryMovie))])
		outputMovie = horzcat(primaryMovie,secondaryMovie);
		clear primaryMovie secondaryMovie
		if options.downsampleFactorFinal>1
			subfxnDisp('downsampling final movie...')
			outputMovie = downsampleMovie(outputMovie,'downsampleDimension','space','downsampleFactor',options.downsampleFactorFinal);
		end

		% if user ask to save movie, do so.
		if options.recordMovie~=0
			writerObj = VideoWriter(options.recordMovie);
			open(writerObj);
			nFrames = size(outputMovie,3);
			reverseStr = '';
			for frame=1:nFrames
				writeVideo(writerObj,squeeze(outputMovie(:,:,frame)));
				if frame==1||mod(frame,5)==0||frame==nFrames
					reverseStr = cmdWaitbar(frame,nFrames,reverseStr,'inputStr','writing movie');drawnow;
				end
			end
			close(writerObj);
		end
	catch err
		display(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		display(repmat('@',1,7))
	end
	% subfxnDisp: function description
	function subfxnDisp(txt)
		if options.displayInfo==1
			display(txt)
		end
	end
end


function et = start(t)
% TIMETIC/START Start a timer.
%
% et = start(t) starts timer t and returns the current elapsed time.  This
% function does not reset the current elapsed time like tic.  The start
% function is designed to be used with pause to continue accumulating time.
%
% Example:
%   t = timertic;
%   start(t);
%   sphere;
%   axis square;
%   et = pause(t)
%
% See also TIMETIC/PAUSE

%
% David Gleich
% Stanford University
% 27 September 2006
%

t.start();
et = t.elapsed();


function [Y,FS,NBITS,OPTS] = mp3read(FILE,N,MONO,DOWNSAMP,DELAY)
% MP3READ   Read MP3 audio file via use of external binaries.
%   Y = MP3READ(FILE) reads an mp3-encoded audio file into the
%     vector Y just like wavread reads a wav-encoded file (one channel
%     per column).  Extension ".mp3" is added if FILE has none.
%     Also accepts other formats of wavread, such as
%   Y = MP3READ(FILE,N) to read just the first N sample frames (N
%     scalar), or the frames from N(1) to N(2) if N is a two-element vector.
%   Y = MP3READ(FILE,FMT) or Y = mp3read(FILE,N,FMT)
%     with FMT as 'native' returns int16 samples instead of doubles;
%     FMT can be 'double' for default behavior (to exactly mirror the
%     syntax of wavread).
%
%   [Y,FS,NBITS,OPTS] = MP3READ(FILE...) returns extra information:
%     FS is the sampling rate,  NBITS is the bit depth (always 16),
%     OPTS.fmt is a format info string; OPTS has multiple other
%     fields, see WAVREAD.
%
%   SIZ = MP3READ(FILE,'size') returns the size of the audio data contained
%     in the file in place of the actual audio data, returning the
%     2-element vector SIZ=[samples channels].
%
%   [Y...] = MP3READ(FILE,N,MONO,DOWNSAMP,DELAY) extends the
%     WAVREAD syntax to allow access to special features of the
%     mpg123 engine:  MONO = 1 forces output to be mono (by
%     averaging stereo channels); DOWNSAMP = 2 or 4 downsamples by
%     a factor of 2 or 4 (thus FS returns as 22050 or 11025
%     respectively for a 44 kHz mp3 file); DELAY controls how many
%     "warm up" samples to drop at the start of the file; the
%     default value of 2257 makes an mp3write/mp3read loop for a 44
%     kHz mp3 file be as close as possible to being temporally
%     aligned; specify as 0 to prevent discard of initial samples.
%
%   Example:
%   To read an mp3 file as doubles at its original width and sampling rate:
%     [Y,FS] = mp3read('piano.mp3');
%   To read the first 1 second of the same file, downsampled by a
%   factor of 4, cast to mono, using the default filename
%   extension:
%     [Y,FS4] = mp3read('piano', FS/4, 1, 4);
%
%   Note: Because the mp3 format encodes samples in blocks of 26 ms (at
%   44 kHz), and because of the "warm up" period of the encoder,
%   the file length may not be exactly what you expect.
%
%   Note: requires external binaries mpg123 and mp3info; you
%   can find binaries for several platforms at:
%     http://labrosa.ee.columbia.edu/matlab/mp3read.html
%
%   See also mp3write, wavread.

% 2003-07-20 dpwe@ee.columbia.edu  This version calls mpg123.
% 2004-08-31 Fixed to read whole files correctly
% 2004-09-08 Uses mp3info to get info about mp3 files too
% 2004-09-18 Reports all mp3info fields in OPTS.fmt; handles MPG2LSF sizes
%            + added MONO, DOWNSAMP flags, changed default behavior.
% 2005-09-28 Fixed bug reading full-rate stereo as 1ch (thx bjoerns@vjk.dk)
% 2006-09-17 Chop off initial 2257 sample delay (for 44.1 kHz mp3)
%            so read-write loop doesn't get progressively delayed.
%            You can suppress this with a 5th argument of 0.
% 2007-02-04 Added support for FMT argument to match wavread
%            Added automatic selection of binary etc. to allow it
%            to work cross-platform without editing prior to
%            submitting to Matlab File Exchange
% 2007-07-23 Tweaks to 'size' mode so it exactly agrees with read data.

% find our baseline directory
path = fileparts(which('mp3read'));

% %%%%% Directory for temporary file (if needed)
% % Try to read from environment, or use /tmp if it exists, or use CWD
tmpdir = getenv('TMPDIR');
if isempty(tmpdir) || exist(tmpdir,'file')==0
  tmpdir = '/tmp';
end
if exist(tmpdir,'file')==0
  tmpdir = '';
end
% ensure it exists
%if length(tmpdir) > 0 && exist(tmpdir,'file')==0
%  mkdir(tmpdir);
%end

%%%%%% Command to delete temporary file (if needed)
rmcmd = 'rm';

%%%%%% Location of the binaries - attempt to choose automatically
%%%%%% (or edit to be hard-coded for your installation)
ext = lower(computer);
if ispc
  ext = 'exe';
  rmcmd = 'del';
end
mpg123 = fullfile(path,['mpg123.',ext]);
mp3info = fullfile(path,['mp3info.',ext]);

%%%%% Process input arguments
if nargin < 2
  N = 0;
end

% Check for FMT spec (per wavread)
FMT = 'double';
if ischar(N)
  FMT = lower(N);
  N = 0;
end

if length(N) == 1
  % Specified N was upper limit
  N = [1 N];
end
if nargin < 3
  forcemono = 0;
else
  % Check for 3rd arg as FMT
  if ischar(MONO)
    FMT = lower(MONO);
    MONO = 0;
  end
  forcemono = (MONO ~= 0);
end
if nargin < 4
  downsamp = 1;
else
  downsamp = DOWNSAMP;
end
if downsamp ~= 1 && downsamp ~= 2 && downsamp ~= 4
  error('DOWNSAMP can only be 1, 2, or 4');
end
if nargin < 5
  mpg123delay44kHz = 2257;  % empirical delay of lame/mpg123 loop
  delay = round(mpg123delay44kHz/downsamp);
else
  delay = DELAY;
end

if strcmp(FMT,'native') == 0 && strcmp(FMT,'double') == 0 && ...
      strcmp(FMT,'size') == 0
  error(['FMT must be ''native'' or ''double'' (or ''size''), not ''',FMT,'''']);
end

%%%%%% Constants
NBITS=16;

%%%%% add extension if none (like wavread)
[path,file,ext] = fileparts(FILE);
if isempty(ext)
  FILE = [FILE, '.mp3'];
end

%%%%%% Probe file to find format, size, etc. using "mp3info" utility
cmd = ['"',mp3info, '" -r m -p "%Q %u %b %r %v * %C %e %E %L %O %o %p" "', FILE,'"'];
% Q = samprate, u = #frames, b = #badframes (needed to get right answer from %u)
% r = bitrate, v = mpeg version (1/2/2.5)
% C = Copyright, e = emph, E = CRC, L = layer, O = orig, o = mono, p = pad
w = mysystem(cmd);
% Break into numerical and ascii parts by finding the delimiter we put in
starpos = findstr(w,'*');
nums = str2num(w(1:(starpos - 2)));
strs = tokenize(w((starpos+2):end));

SR = nums(1);
nframes = nums(2);
nchans = 2 - strcmp(strs{6}, 'mono');
layer = length(strs{4});
bitrate = nums(4)*1000;
mpgv = nums(5);
% Figure samples per frame, after
% http://board.mp3-tech.org/view.php3?bn=agora_mp3techorg&key=1019510889
if layer == 1
  smpspfrm = 384;
elseif SR < 32000 && layer ==3
  smpspfrm = 576;
  if mpgv == 1
    error('SR < 32000 but mpeg version = 1');
  end
else
  smpspfrm = 1152;
end

OPTS.fmt.mpgBitrate = bitrate;
OPTS.fmt.mpgVersion = mpgv;
% fields from wavread's OPTS
OPTS.fmt.nAvgBytesPerSec = bitrate/8;
OPTS.fmt.nSamplesPerSec = SR;
OPTS.fmt.nChannels = nchans;
OPTS.fmt.nBlockAlign = smpspfrm/SR*bitrate/8;
OPTS.fmt.nBitsPerSample = NBITS;
OPTS.fmt.mpgNFrames = nframes;
OPTS.fmt.mpgCopyright = strs{1};
OPTS.fmt.mpgEmphasis = strs{2};
OPTS.fmt.mpgCRC = strs{3};
OPTS.fmt.mpgLayer = strs{4};
OPTS.fmt.mpgOriginal = strs{5};
OPTS.fmt.mpgChanmode = strs{6};
OPTS.fmt.mpgPad = strs{7};
OPTS.fmt.mpgSampsPerFrame = smpspfrm;

if SR == 16000 && downsamp == 4
  error('mpg123 will not downsample 16 kHz files by 4 (only 2)');
end

if downsamp == 1
  downsampstr = '';
else
  downsampstr = [' -',num2str(downsamp)];
end
FS = SR/downsamp;

if forcemono == 1
  nchans = 1;
  chansstr = ' -m';
else
  chansstr = '';
end

% Size-reading version
if strcmp(FMT,'size') == 1
   Y = [floor(smpspfrm*nframes/downsamp)-delay, nchans];
else

  % Temporary file to use
  tmpfile = fullfile(tmpdir, ['tmp',num2str(round(1000*rand(1))),'.wav']);

  skipx = 0;
  skipblks = 0;
  skipstr = '';
  sttfrm = N(1)-1;

  % chop off transcoding delay?
  %sttfrm = sttfrm + delay;  % empirically measured
  % no, we want to *decode* those samples, then drop them
  % so delay gets added to skipx instead

  if sttfrm > 0
    skipblks = floor(sttfrm*downsamp/smpspfrm);
    skipx = sttfrm - (skipblks*smpspfrm/downsamp);
    skipstr = [' -k ', num2str(skipblks)];
  end
  skipx = skipx + delay;

  lenstr = '';
  endfrm = -1;
  decblk = 0;
  if length(N) > 1
    endfrm = N(2);
    if endfrm > sttfrm
      decblk = ceil((endfrm+delay)*downsamp/smpspfrm) - skipblks + 10;
      % we read 10 extra blks (+10) to cover the case where up to 10 bad
      % blocks are included in the part we are trying to read (it happened)
      lenstr = [' -n ', num2str(decblk)];
      % This generates a spurious "Warn: requested..." if reading right
      % to the last sample by index (or bad blks), but no matter.
    end
 end

  % Run the decode
  cmd=['"',mpg123,'"', downsampstr, chansstr, skipstr, lenstr, ...
       ' -q -w "', tmpfile,'"  "',FILE,'"'];
  %w =
  mysystem(cmd);

  % Load the data
  Y = wavread(tmpfile);

%  % pad delay on to end, just in case
%  Y = [Y; zeros(delay,size(Y,2))];
%  % no, the saved file is just longer

  if decblk > 0 && length(Y) < decblk*smpspfrm/downsamp
    % This will happen if the selected block range includes >1 bad block
    disp(['Warn: requested ', num2str(decblk*smpspfrm/downsamp),' frames, returned ',num2str(length(Y))]);
  end

  % Delete tmp file
  mysystem([rmcmd,' "', tmpfile,'"']);

  % debug
%  disp(['sttfrm=',num2str(sttfrm),' endfrm=',num2str(endfrm),' skipx=',num2str(skipx),' delay=',num2str(delay),' len=',num2str(length(Y))]);

  % Select the desired part
  if skipx+endfrm-sttfrm > length(Y)
      endfrm = length(Y)+sttfrm-skipx;
  end

  if endfrm > sttfrm
    Y = Y(skipx+(1:(endfrm-sttfrm)),:);
  elseif skipx > 0
    Y = Y((skipx+1):end,:);
  end

  % Convert to int if format = 'native'
  if strcmp(FMT,'native')
    Y = int16((2^15)*Y);
  end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function w = mysystem(cmd)
% Run system command; report error; strip all but last line
[s,w] = system(cmd);
if s ~= 0
  error(['unable to execute ',cmd,' (',w,')']);
end
% Keep just final line
w = w((1+max([0,findstr(w,10)])):end);
% Debug
%disp([cmd,' -> ','*',w,'*']);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function a = tokenize(s)
% Break space-separated string into cell array of strings
% 2004-09-18 dpwe@ee.columbia.edu
a = [];
p = 1;
n = 1;
l = length(s);
nss = findstr([s(p:end),' '],' ');
for ns = nss
  % Skip initial spaces
  if ns == p
    p = p+1;
  else
    if p <= l
      a{n} = s(p:(ns-1));
      n = n+1;
      p = ns+1;
    end
  end
end