R/bimets_ts_functions.R

Defines functions VERIFY_MAGNITUDE TSTRIM TSPROJECT TSMERGE TSLOOK TSLEAD TSLAG TSJOIN TSINFO TSEXTEND TSDELTAP TSDELTALOG TSDELTA TSERIES TABIT SEMIANNUAL QUARTERLY NOELS NAMELIST MOVTOT MOVAVG MONTHLY LOCS INTS INDEXNUM GETYEARPERIOD GETRANGE GETDATE ELIMELS DAILY CUMULO CUMSUM CUMPROD ANNUAL A1D yq2yp ym2yp setBIMETSconf normalizeYP is.bimets getBIMETSconf fromXTStoTS fromTStoXTS fromBIMETStoXTS fromBIMETStoTS frequency.xts date2yp as.bimets .TRIM .numberOfStartingMissing .numberOfEndingMissing .NOELSCompliantInput .monthToSemiAnnual .monthToQuarter .MAKENAMES .isUnivariate .isLastDateOnSemiAnnual .isLastDateOnQuarter .isLastDateOnMonth .isFirstDateOnSemiAnnual .isFirstDateOnQuarter .isFirstDateOnMonth .isCompliantYP .isCompliantXTS .isCompliantTS .isCompliantF .isCompliant .isBisextile .getFunArgsNames .gBc .fixTsp .A1DCompliantInput .onLoad .onAttach

Documented in A1D ANNUAL as.bimets CUMPROD CUMSUM CUMULO DAILY date2yp ELIMELS frequency.xts fromBIMETStoTS fromBIMETStoXTS fromTStoXTS fromXTStoTS getBIMETSconf GETDATE GETRANGE GETYEARPERIOD INDEXNUM INTS is.bimets LOCS MONTHLY MOVAVG MOVTOT NAMELIST NOELS normalizeYP QUARTERLY SEMIANNUAL setBIMETSconf TABIT TSDELTA TSDELTALOG TSDELTAP TSERIES TSEXTEND TSINFO TSJOIN TSLAG TSLEAD TSLOOK TSMERGE TSPROJECT TSTRIM VERIFY_MAGNITUDE ym2yp yq2yp

#############################################################################
#
# Copyright (C) 2021-2031 Bank of Italy
#  
# 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/>.
#
#
# @description: BIMETS - Time Series FUNs 		    
#
# @authors: ANDREA LUCIANI 
#
# @copyright: Bank of Italy
#
# @license: GPL-3 - GNU GENERAL PUBLIC LICENSE - Version 3
#
#############################################################################

#called when pkg is attached
.onAttach <- function(...) {
  
  #set version
  options('BIMETS_VERSION'='4.0.3') 
  
  packageStartupMessage(gsub("\\$","",paste0('bimets is active - version ',getOption('BIMETS_VERSION'),'\nFor help type \'?bimets\'\n')))
  
}

.onLoad <- function(...) {

	tryCatch({
	
	  #init default configuration day in period
    if (is.null(getOption('BIMETS_CONF_DIP'))) 
    {
      #day in the period setup
      options('BIMETS_CONF_DIP'='LAST') 
    }
    
    #init default configuration constructor class type
    if (is.null(getOption('BIMETS_CONF_CCT'))) 
    {
      #day in the period setup
      options('BIMETS_CONF_CCT'='TS') 
    }
    
    #init default configuration on compliance behaviour
    if (is.null(getOption('BIMETS_CONF_NOC'))) 
    {
      #day in the period setup
       options('BIMETS_CONF_NOC'=FALSE) 
    }
    
    
    #overload ts operators
    
    #address ts data by year period 
    registerS3method('[[','ts' , function(x, idx, jdx, EXTEND=FALSE, avoidCompliance=FALSE) {
      
      #single operator case
      if (missing(jdx))
      {
        if ((!(missing(idx))) && (!(is.null(idx)))  && all(is.finite(idx)) ) 
        {
          #deal with vector input
          if ( length(idx)==2 ){
          	
          	if (! avoidCompliance ) 
          	{
          		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[c(year,period)]]: ',e$message) }) 
          	}
            
            return(x[[idx[1],idx[2],avoidCompliance=TRUE]])
            
          } else {
            
          	return(NextMethod()) 
          }
        }
        
        return(NextMethod()) 
      }
      
      #two operators case
      #if numeric take in charge
      if ((!(missing(idx))) && (!(missing(jdx))) && (!(is.null(idx))) && (!(is.null(jdx))) 
          && all(is.finite(idx)) && all(is.finite(jdx))  ) 
      {
        
        #deal with scalar inputs
        if ( length(idx)==1 && length(jdx)==1 )
        {
          if ( (idx %%1 !=0 ) || (jdx %%1 !=0 ) ) 
            stop('ts[[year,period]]: year and period must be positive integer. ')  
        	
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[year,period]]: ',e$message) }) 
        	}
          
          tryCatch({
            outI=(1+NUMPERIOD(start(x),normalizeYP(c(idx,jdx),frequency(x)),frequency(x))) 
          },error=function(e){stop('ts[[year,period]]: wrong syntax. ',e$message)}) 
          if ((outI<1)|| (outI>length(x)))
          {
            stop('ts[[year,period]]: index out of range.')
          }
          
          tryCatch({
            
            return(x[outI]) 
            
          },error=function(e){stop('ts[[year,period]]: unknown error. ',e$message)}) 
          return(NULL)  
          
        } else if ( length(idx)==2 && length(jdx)==2 )
        {
          #deal with vector inputs
          if ( (idx[1] %%1 !=0 ) || (jdx[1] %%1 !=0 ) || (idx[2] %%1 !=0 ) || (jdx[2] %%1 !=0 )) 
            stop('ts[[c(year1,period1),c(year2,period2)]]: year1, year2, period1, period2 must be positive integer. ')  
          
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[year,period]]: ',e$message) }) 
        	}
        	
          tryCatch({
            outTS=TSPROJECT(x, TSRANGE=c(idx,jdx), EXTEND=EXTEND, avoidCompliance=TRUE)
          },error=function(e){stop('ts[[c(year1,period1),c(year2,period2)]]: ',e$message)}) 
          
          return(outTS)
          
        } else {
          
        	return(NextMethod()) 
        }
        
      }
      
      return(NextMethod()) 
    }) 
    
    #address xts data by year period
    registerS3method('[[','xts' , function(x, idx, jdx, EXTEND=FALSE, avoidCompliance=FALSE) {
       
      #single operator case
      if (missing(jdx))
      {
        if ((!(missing(idx))) && (!(is.null(idx)))  && all(is.finite(idx)) ) 
        {
          #deal with vector input
          if ( length(idx)==2 ){
          	
          	if (! avoidCompliance ) 
          	{
          		tryCatch({.isCompliant(x) },error=function(e){stop('xts[[c(year,period)]]: ',e$message) }) 
          	}
            
            return(x[[idx[1],idx[2],avoidCompliance=TRUE]])
            
          } else {
            
          	return(NextMethod()) 
          }
        }
        
        return(NextMethod()) 
      }
      
      #two operators case
      #if numeric take in charge
      if ((!(missing(idx))) && (!(missing(jdx))) && (!(is.null(idx))) && (!(is.null(jdx))) 
          && all(is.finite(idx)) && all(is.finite(jdx))  ) 
      {
        
        #deal with scalar inputs
        if ( length(idx)==1 && length(jdx)==1 )
        {
        	
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('xts[[year,period]]: ',e$message) }) 
        	}
          
          #get xts frequency
          xtsF=frequency(x) 
          
          startXTS=index(x)[1] 
          startXTSYP=NULL 
          
          tryCatch({
            
            if (inherits( startXTS ,'Date')  )   startXTSYP=date2yp(startXTS,xtsF) 
            if (inherits( startXTS ,'yearqtr') ) startXTSYP=yq2yp(startXTS) 
            if (inherits( startXTS ,'yearmon') ) startXTSYP=ym2yp(startXTS) 
            if (is.null(startXTSYP)) stop('unknown xts tclass()') 
            
          },error=function(e){stop('xts[[year,period]]: unable to convert start date. ',e$message)})
          
          tryCatch({
            outI=(1+NUMPERIOD(startXTSYP,normalizeYP(c(idx,jdx),xtsF),xtsF)) 
          },error=function(e){stop('xts[[year,period]]: wrong syntax. ',e$message)}) 
          if ((outI<1)|| (outI>length(x)))
          {
            stop('xts[[year,period]]: index out of range.')
          }
          
          tryCatch({
            return(coredata(x[outI])[,1]) 
          },error=function(e){stop('xts[[year,period]]: unknown error. ',e$message)}) 
          
          return(NULL) 
          
        } else if ( length(idx)==2 && length(jdx)==2 )
        {
          #deal with vector inputs
          if ( (idx[1] %%1 !=0 ) || (jdx[1] %%1 !=0 ) || (idx[2] %%1 !=0 ) || (jdx[2] %%1 !=0 )) 
            stop('xts[[c(year1,period1),c(year2,period2)]]: year1, year2, period1, period2 must be positive integer. ') 
          
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('xts[[year,period]]: ',e$message) }) 
        	}
        	
          tryCatch({
            outTS=TSPROJECT(x, TSRANGE=c(idx,jdx), EXTEND=EXTEND, avoidCompliance=TRUE)
          },error=function(e){stop('xts[[c(year1,period1),c(year2,period2)]]: ',e$message)}) 
          
          return(outTS)
          
        } else {
          
        	return(NextMethod()) 
        } 
      }
      
      return(NextMethod()) 
    }) 
    
    #address ts data by date
    registerS3method('[','ts' , function (x, idx, jdx, drop=TRUE, avoidCompliance=FALSE) {
    	
      #if not numeric take in charge
      if ((!(missing(idx))) && (!(is.null(idx))) && 
          ((is.character(idx) || inherits(idx,'Date') || inherits(idx,'yearmon') || inherits(idx,'yearqtr')  )))
      {
        xtsT=NULL 
        
        if (! avoidCompliance ) 
        {
          tryCatch({.isCompliant(x) },error=function(e){stop('ts[date]: ',e$message) }) 
        }
        
        #transform in xts
        tryCatch({
          xtsT=fromTStoXTS(x,avoidCompliance=TRUE) 
        },error=function(e){stop('ts[date]: error in fromTStoXTS. ',e$message) }) 
        
        #return requested data      
        if (length(xtsT[idx])==0) stop('ts[date]: index out of bounds.') 
        return(coredata(xtsT[idx])[,1]) 
      }
      
      return(NextMethod()) 
      
    }) 
    
    #assign ts data by year period
    registerS3method('[[<-','ts' , function(x, idx, jdx, value, EXTEND=FALSE, avoidCompliance=FALSE) {
      
      if ( missing(value) || is.null(value) ) stop('ts[[i,j]] <- value: attempt to assign a NULL value.') 
      
      #single operator case
      if (missing(jdx))
      {
        if ((!(missing(idx))) && (!(is.null(idx)))  && all(is.finite(idx)) ) 
        {
          #deal with vector input
          if ( length(idx)==2 ){
          	
          	if (! avoidCompliance ) 
          	{
          		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[c(year,period)]] <- value: ',e$message) }) 
          	}
            
            x[[idx[1],idx[2],avoidCompliance=TRUE]]=value
            return(x)
              
          } else {
            
          	return(NextMethod()) 
          }
        }
        
        return(NextMethod()) 
      }
      
      #two operators case
      #if numeric take in charge
      if ((!(missing(idx))) && (!(missing(jdx))) && (!(is.null(idx))) && (!(is.null(jdx))) 
          && all(is.finite(idx)) && all(is.finite(jdx))) 
      {
        
        #deal with scalar inputs
        if ( length(idx)==1 && length(jdx)==1 )
        {
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[i,j]] <- value: ',e$message) }) 
        	}
        	
          fTS=frequency(x) 
          tryCatch({
            outI=(1+NUMPERIOD(start(x),normalizeYP(c(idx,jdx),fTS),fTS)) 
          },error=function(e){stop('ts[[year,period]] <- value: wrong syntax. ',e$message)}) 
          if (outI<1)
          {
            stop('ts[[year,period]] <- value: index out of range.')
          }
          
          coreTS=coredata(x) 
          for(tmpIdx in (1:length(value)))
          { 
            coreTS[outI-1+tmpIdx]=value[tmpIdx] 
          }
          
          outF=ts(coreTS,start=start(x),frequency=fTS)
          
          return(outF) 
          
        } else if ( length(idx)==2 && length(jdx)==2 )
        {
          #deal with vector inputs
          if ( (idx[1] %%1 !=0 ) || (jdx[1] %%1 !=0 ) || (idx[2] %%1 !=0 ) || (jdx[2] %%1 !=0 )) 
            stop('ts[[c(year1,period1),c(year2,period2)]] <- value: year1, year2, period1, period2 must be positive integer.')  
          
        	if (! avoidCompliance ) 
        	{
        		tryCatch({.isCompliant(x) },error=function(e){stop('ts[[i,j]] <- value: ',e$message) }) 
        	}
        	
          #project x in requested range
          tryCatch({
            outTS=TSPROJECT(x, TSRANGE=c(idx,jdx), EXTEND=EXTEND, avoidCompliance=TRUE)
          },error=function(e){stop('ts[[c(year1,period1),c(year2,period2)]] <- value: ',e$message)}) 
          
          #check value has length 1 or same length than range
          if (length(value)!=1 && length(value) != length(outTS))
          {
            stop('ts[[c(year1,period1),c(year2,period2)]] <- value: number of items to replace is not equal to replacement length.')  
          }
          
          #assign values to subrange
          if (length(value==1))
          {
            outTS[]=value
          } else {
            coredata(outTS)=value
          }
          
          #merge original and modified ts
          outTS=TSMERGE(outTS,x,avoidCompliance=TRUE)
          
          return(outTS)
          
        } else {
          
        	return(NextMethod()) 
        }
      }
      
      return(NextMethod()) 
    }) 
    
    #assign xts data by year period
    registerS3method('[[<-','xts' , function(x, idx, jdx, value, EXTEND=FALSE, avoidCompliance=FALSE) {
      
      tryCatch({
          
          if (! avoidCompliance ) 
          {
            #do not add text to stop message due to overinformation in output
            tryCatch({.isCompliant(x) },error=function(e){stop(e$message) }) 
          }
        
          #convert to TS  
          tmpTS=fromXTStoTS(x,avoidCompliance=TRUE) 
      
          #apply request to ts
          tmpTS[[idx,jdx,EXTEND=EXTEND,avoidCompliance=TRUE]]=value 
          
          #get back to xts
          outTS=fromTStoXTS(tmpTS,avoidCompliance=TRUE)
          
          return(outTS)
          
        },error=function(e){stop(e$message) }) 
      
        return(NULL) 
      }
    )
    
    #assign ts data by date
    registerS3method('[<-','ts' , function (x, idx, jdx, value, avoidCompliance=FALSE) {
       
      #if not numeric take in charge
      if ((!(missing(idx))) && (!(is.null(idx))) && ((is.character(idx) || inherits(idx,'Date') || inherits(idx,'yearmon') || inherits(idx,'yearqtr') )))
      {
        tsT=NULL 
        xtsT=NULL 
        if (is.null(value)) stop('ts[date]: attempt to assign a NULL value.') 
        if (! avoidCompliance ) 
        {
          tryCatch({.isCompliant(x) },error=function(e){stop('ts[date]: ',e$message) }) 
        }
        
        #transform to xts
        tryCatch({
          xtsT=fromTStoXTS(x,avoidCompliance=TRUE) 
        },error=function(e){stop('ts[date]: error in fromTStoXTS. ',e$message) }) 
        #apply changes to xts
        tryCatch({
          xtsT[idx]=value 
        },error=function(e){stop('ts[date]: error in assignment. ',e$message) }) 
        #get back to ts
        tryCatch({
          tsT=fromXTStoTS(xtsT,avoidCompliance=TRUE) 
        },error=function(e){stop('ts[date]: error in fromXTStoTS. ',e$message) }) 
        return(tsT) 
      }
      return(NextMethod()) 
    }) 
   
   },error=function(e){stop('BIMETS not fully loaded. ',e$message)})
 
}

# internal core funs ----------------------------------

#A1D support function
.A1DCompliantInput <- function(x=NULL)
{
  
  if (is.null(x)) return(FALSE) 
  if (is.numeric(x)) return(TRUE) 
  if (is.xts(x)) return(TRUE) 
  if (is.ts(x)) return(TRUE) 
  if (all(is.na(x))) return(TRUE) 
  return(FALSE) 
}

#fix ts tsp. window bug workaround
.fixTsp <- function(x=NULL)
{
  if (! is.ts(x)) stop('.fixTsp(): input must be of class ts()')
  
  starty=start(x)[1]
  startp=start(x)[2]
  
  endy=end(x)[1]
  endp=end(x)[2]
  
  freq=frequency(x)
  
  attr(x,'tsp')=c(starty+(startp-1)/freq,endy+(endp-1)/freq,freq)
  
  return(x)
}

#fast BIMETS configuration check
.gBc <- function()
{
  return(cat(getBIMETSconf('BIMETS_CONF_DIP'),getBIMETSconf('BIMETS_CONF_CCT'),getBIMETSconf('BIMETS_CONF_NOC'),'\n')) 
}

#get arguments passed to function call, used in TABIT and others
.getFunArgsNames <- function(...)
{ 
  tryCatch({
    dots=substitute(list(...))[-1] 
    return(c(sapply(dots, deparse))) 
  },error=function(e){stop('getArgsNames(): ',e$message) }) 
  return(NULL) 
}

#convert year-period range to string dates
.getStaticDates <- function (start=NULL,end=NULL,freq=NULL)
{
  tryCatch({
    .isCompliantYP(start,freq) 
    if (is.null(end)) {
      end=start 
    } else {
      .isCompliantYP(end,freq) 
    }    
  },error=function(e){stop('.getStaticDates(): ',e$message) })
  
  if (NUMPERIOD(start,end,freq)<0) stop('.getStaticDates(): "end" is before "start".') 
  if (start[1]<.__bimets__data__static_startYear___ || start[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('.getStaticDates(): year must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  if (end[1]<.__bimets__data__static_startYear___ || end[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('.getStaticDates(): year must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  
  #get date from bimets system static dataset
  if (freq==366)
  { 
    return(.__bimets__data__366_YP2D__[((start[1]-.__bimets__data__static_startYear___)*366+start[2]):((end[1]-.__bimets__data__static_startYear___)*366+end[2])]) 
  } else
    if (freq==36)
    { 
      if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
        return(.__bimets__data__36L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*36+start[2]):((end[1]-.__bimets__data__static_startYear___)*36+end[2])]) 
      } else {
        return(.__bimets__data__36F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*36+start[2]):((end[1]-.__bimets__data__static_startYear___)*36+end[2])]) 
      }
    } else
      if (freq==53)
      { 
        if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
          return(.__bimets__data__53L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*53+start[2]):((end[1]-.__bimets__data__static_startYear___)*53+end[2])]) 
        } else {
          return(.__bimets__data__53F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*53+start[2]):((end[1]-.__bimets__data__static_startYear___)*53+end[2])]) 
        }
      } else
        if (freq==24)
        { 
          if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
            return(.__bimets__data__24L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*24+start[2]):((end[1]-.__bimets__data__static_startYear___)*24+end[2])]) 
          } else {
            return(.__bimets__data__24F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*24+start[2]):((end[1]-.__bimets__data__static_startYear___)*24+end[2])]) 
          }
        } else
          if (freq==12)
          { 
            if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
              return(.__bimets__data__12L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*12+start[2]):((end[1]-.__bimets__data__static_startYear___)*12+end[2])]) 
            } else {
              return(.__bimets__data__12F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*12+start[2]):((end[1]-.__bimets__data__static_startYear___)*12+end[2])]) 
            }
          } else
            if (freq==4)
            { 
              if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
                return(.__bimets__data__4L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*4+start[2]):((end[1]-.__bimets__data__static_startYear___)*4+end[2])]) 
              } else {
                return(.__bimets__data__4F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*4+start[2]):((end[1]-.__bimets__data__static_startYear___)*4+end[2])]) 
              }
            } else
              if (freq==3)
              { 
                if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
                  return(.__bimets__data__3L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*3+start[2]):((end[1]-.__bimets__data__static_startYear___)*3+end[2])]) 
                } else {
                  return(.__bimets__data__3F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*3+start[2]):((end[1]-.__bimets__data__static_startYear___)*3+end[2])]) 
                }
              } else
                if (freq==2)
                { 
                  if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
                    return(.__bimets__data__2L_YP2D__[((start[1]-.__bimets__data__static_startYear___)*2+start[2]):((end[1]-.__bimets__data__static_startYear___)*2+end[2])]) 
                  } else {
                    return(.__bimets__data__2F_YP2D__[((start[1]-.__bimets__data__static_startYear___)*2+start[2]):((end[1]-.__bimets__data__static_startYear___)*2+end[2])]) 
                  }
                } else
                  if (freq==1)
                  { 
                    if (getBIMETSconf('BIMETS_CONF_DIP')=='LAST') {
                      return(.__bimets__data__1L_YP2D__[((start[1]-.__bimets__data__static_startYear___)+start[2]):((end[1]-.__bimets__data__static_startYear___)+end[2])]) 
                    } else {
                      return(.__bimets__data__1F_YP2D__[((start[1]-.__bimets__data__static_startYear___)+start[2]):((end[1]-.__bimets__data__static_startYear___)+end[2])]) 
                    }
                  } else stop(paste0('.getStaticDates(): unsupported frequency.'))
  
}

#convert dates to year-periods 
.getStaticYP <- function (start=NULL,end=NULL,freq=NULL)
{
  
  if (! inherits( start,'Date')) stop('.getStaticYP(): "start" must be of class Date().') 
  if (!is.null(end)) if (! inherits( end,'Date')) stop('.getStaticYP(): "end" must be of class Date().') 
  if (!.isCompliantF(freq)) stop('.getStaticYP(): uncompliant frequency.') 
  startY=as.numeric(format(start,format='%Y')) 
  if (any(startY<.__bimets__data__static_startYear___) || any(startY>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1)) ) 
    stop(paste0('.getStaticYP(): time series must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  if (!is.null(end)) 
  {
    endY=as.numeric(format(end,format='%Y')) 
    if (endY<.__bimets__data__static_startYear___ || endY>(.__bimets__data__static_startYear___   + .__bimets__data__static_totalLength___ -1) ) 
      stop(paste0('.getStaticYP(): time series must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  }
  
  startNum=as.numeric(start)-as.numeric(as.Date(paste0(.__bimets__data__static_startYear___,'-01-01')))+1 
  
  if (is.null(end))
  {
    range=startNum 
  } else {
    endNum=as.numeric(end)-as.numeric(as.Date(paste0(.__bimets__data__static_startYear___,'-01-01')))+1 
    range=startNum:endNum 
  }
  
  if (freq==366)
  { 
    startP=as.numeric(format(start,format='%j')) 
    startNum=(startY-.__bimets__data__static_startYear___)*366+startP 
    if (is.null(end))
    {
      range=startNum 
    } else {
      
      endP=as.numeric(format(end,format='%j')) 
      endNum=(endY-.__bimets__data__static_startYear___)*366+endP 
      range=startNum:endNum 
    }
    return(.__bimets__data__366_D2YP__[range,]) 
  } else if (freq==12)
  {
    return(.__bimets__data__12_D2YP__[range,]) 
  } else if (freq==4)
  {
    return(.__bimets__data__4_D2YP__[range,]) 
  } else if (freq==3)
  {
    return(.__bimets__data__3_D2YP__[range,]) 
  } else if (freq==2)
  {
    return(.__bimets__data__2_D2YP__[range,]) 
  } else if (freq==1)
  {
    return(.__bimets__data__1_D2YP__[range,]) 
  }else if (freq==24)
  {
    return(.__bimets__data__24_D2YP__[range,]) 
  }else if (freq==36)
  {
    return(.__bimets__data__36_D2YP__[range,]) 
  } else if (freq==53)
  {
    return(.__bimets__data__53_D2YP__[range,]) 
  } else stop('.getStaticYP(): unsupported frequency.')
  
  return(NA) 
}

#bisextile year check
.isBisextile <- function(year=NULL)
{
  if (length(year)==1)
  {
    if (!(is.numeric(year) && year>0) ) stop('.isBisextile(): year must be a positive integer.') 
    if (!(year%%1==0))  stop('.isBisextile(): non-integer year.') 
    return((year %% 4 == 0 && (year %% 100 != 0 || year %% 400 == 0))) 
  } else {
    if (!(is.numeric(year) ) ) stop('.isBisextile(): year must be a positive integer.') 
    outF=c()
    for (idxTmp in 1:length(year))
    {
      outF=c(outF,.isBisextile(year[idxTmp]))
    }
    
    return(outF)
  }
  
  return(NULL)
} 

#check if ts/xts is compliant
.isCompliant <- function(x=NULL,suppressErrors=FALSE,...)
{
  #avoid test if global option set
  if (getBIMETSconf('BIMETS_CONF_NOC')==TRUE) return(TRUE) 
  
  #return FALSE instead of error
  if (suppressErrors==TRUE){
    outF=FALSE 
    tryCatch({.isCompliant(x);outF=TRUE },error=function(e){}) 
    return(outF) 
  }
  
  if (is.null(x)) stop('.isCompliant(): input needs to be instance of ts() or xts() class.') 
  
  #check if class is correct with default
  if (getBIMETSconf(opt='BIMETS_CONF_CCT')=='TS' && (! is.ts(x)))
  {
    if (! suppressErrors) 
    {
      stop('.isCompliant(): input needs to be instance of class ts(). BIMETS_CONF_CCT value is TS.') 
    } else {
      return(FALSE) 
    }
  }
  
  if (getBIMETSconf(opt='BIMETS_CONF_CCT')=='XTS' && (! is.xts(x)))
  {
    if (! suppressErrors) 
    {
      stop('.isCompliant(): input needs to be instance of class xts(). BIMETS_CONF_CCT value is XTS.') 
    } else {
      return(FALSE) 
    }
  }
  
  if (is.xts(x))
  {
    return(.isCompliantXTS(x)) 
  }
  else if (is.ts(x))
  {
    return(.isCompliantTS(x)) 
  }
  else {stop('.isCompliant(): input needs to be instance of ts() or xts() class.') }
}

#check if f is integer>0
.isCompliantF <- function(f=NULL)
{
  if (is.null(f)) stop('.isCompliantF(): NULL frequency.') 
  if (is.na(f)) stop('.isCompliantF(): NULL frequency.') 
  if (!(is.numeric(f) && f>0) ) stop('.isCompliantF(): frequency must be a positive integer.') 
  if (!(f%%1==0))  stop('.isCompliantF(): non-integer frequency.') 
  return(TRUE) 
}

#check if ts is compliant: 
.isCompliantTS <- function(x=NULL)
{
  if (is.null(x)) stop('.isCompliantTS(): input needs to be instance of ts() class.') 
  if (! (is.ts(x))) stop('.isCompliantTS(): input needs to be instance of ts() class.') 
  if (!.isUnivariate(x)) stop('.isCompliantTS(): input needs to be univariate with at least one observation.') 
  fTS=frequency(x) 
  if (! (fTS %in% c(1,2,3,4,12,24,36,53,366))) stop(".isCompliantTS(): uncompliant frequency in input time series.") 
  start=start(x) 
  end=end(x) 
  #check if date is in bimets allowed range
  if (start[1]<.__bimets__data__static_startYear___ || start[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('.isCompliantTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  if (end[1]<.__bimets__data__static_startYear___ || end[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('.isCompliantTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  return(TRUE) 
}

#check if xts is compliant: i.e. stricty regular on daily, monthly, quarterly, semiannual or yearly
.isCompliantXTS <- function(x=NULL)
{
  if (is.null(x)) stop('.isCompliantXTS(): input needs to be instance of xts() class.') 
  if (!is.xts(x)) stop(".isCompliantXTS(): input needs to be instance of xts() class.") 
  if (!.isUnivariate(x)) stop('.isCompliantXTS(): input needs to be univariate with at least one observation.') 
  if(is.null(tclass( x )) ) stop(".isCompliantXTS(): input needs to be instance of xts() class.") 
  if ((tclass( x )=='yearmon') || (tclass( x )=='yearqtr')) #monthly&quarterly
  {
    if ((! is.regular(x,strict=TRUE)) && (length(x)>1)) stop(paste('.isCompliantXTS(): input of class',tclass( x ),'is not strictly regular.')) 
    if ((length(x)>1) && (min(diff(.index(x)))==0)) stop(".isCompliantXTS(): there are duplicated observations at position ",which.min(diff(.index(x)))) 
    if (tclass( x )=='yearmon')
    {
      start=ym2yp(start(x)) 
      end=ym2yp(end(x)) 
    }
    
    if (tclass( x )=='yearqtr')
    {
      start=yq2yp(start(x)) 
      end=yq2yp(end(x)) 
    }
    
    #check if date in bimets allowed range
    if (start[1]<.__bimets__data__static_startYear___ || start[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
      stop(paste0('.isCompliantXTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
    if (end[1]<.__bimets__data__static_startYear___ || end[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
      stop(paste0('.isCompliantXTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
    #is.regular bug doesnt work if irregularity is regular...
    theoNumPer=NUMPERIOD(start,end,f=frequency(x))+1
    if (length(x)!=theoNumPer) stop(".isCompliantXTS(): input is not strictly regular.") 
  }
  else if ((tclass( x )=='Date'))
  { 
    fXTS=frequency(x) 
    start=date2yp(start(x),f=fXTS) 
    end=date2yp(end(x),f=fXTS) 
    #check if date in bimets allowed range
    if (start[1]<.__bimets__data__static_startYear___ || start[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
      stop(paste0('.isCompliantXTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
    if (end[1]<.__bimets__data__static_startYear___ || end[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
      stop(paste0('.isCompliantXTS(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
    if (fXTS ==12) stop('.isCompliantXTS(): uncompliant index class for monthly time series.') 
    if (fXTS ==4) stop('.isCompliantXTS(): uncompliant index class for quarterly time series.') 
    startD=start(x) 
    startYP=date2yp(startD,f=fXTS) 
    endD=end(x) 
    endYP=date2yp(endD,f=fXTS) 
    len=length(x) 
    tryCatch({
      referenceDates=as.Date(.getStaticDates(startYP,endYP,fXTS)) 
      whichNa=which(is.na(referenceDates)) 
      if (length(whichNa)>0) referenceDates=referenceDates[-whichNa] 
    },error=function(e){stop('.isCompliantXTS(): ',e$message) }) 
    suppressWarnings({
      diffArr=which(index(x)!=referenceDates)
    }) 
    if (length(diffArr>0)) stop('.isCompliantXTS(): uncompliant date on sample ',diffArr[1]) 
  }# endif class date
  else {#not Date or yearmon or yearqtr index class
    stop('.isCompliantXTS(): uncompliant index class.')
  }
  
  return(TRUE) 
}

#check if c(y,p) is compliant
.isCompliantYP <- function(x=NULL,f=NULL)
{
  
  if (is.null(x)) stop('.isCompliantYP(): Uncompliant input.') 
  if (is.null(f)) stop('.isCompliantYP(): NULL frequency.') 
  if (!(.isCompliantF(f))) stop('.isCompliantYP(): uncompliant frequency') 
  if (!(is.vector(x) && length(x)==2))  stop('.isCompliantYP(): uncompliant input.') 
  if (!(is.numeric(x[1]) ) )  stop('.isCompliantYP(): year must be a positive integer.') 
  if (!(is.numeric(x[2]) ) )  stop('.isCompliantYP(): period must be a positive integer.') 
  if (is.na(x[1])  )  stop('.isCompliantYP(): year must be a positive integer.') 
  if (is.na(x[2])  )  stop('.isCompliantYP(): period must be a positive integer.') 
  if (!( x[1]>=0) )  stop('.isCompliantYP(): year must be a positive integer.') 
  if (!( x[2]>=0) )  stop('.isCompliantYP(): period must be a positive integer.') 
  if (!(x[1]%%1==0))  stop('.isCompliantYP(): non-integer year.') 
  if (!(x[2]%%1==0))  stop('.isCompliantYP(): non-integer period.') 
  if (x[2]>f) stop('.isCompliantYP(): period greater than frequency. Consider using normalizeYP(c(y,p),f)') 
  return(TRUE) 
}

#TRUE if x1=c(x11,x12) is equal to x2=c(x21,x22)
.isEqualPeriodYP <- function (x1,x2,f=NULL)
{
  if (is.null(f)) stop('.isEqualPeriodYP(): NULL frequency.') 
  if (!(.isCompliantF(f))) stop('.isEqualPeriodYP(): uncompliant frequency') 
  if (!( .isCompliantYP(x1,f) && .isCompliantYP(x2,f)))	stop('.isEqualPeriodYP(): uncompliant inputs.') 
  if (x1[1] == x2[1] && x1[2] == x2[2]) return(TRUE) 
  return(FALSE) 
}

.isFirstDateOnMonth <- function(date)
{
  day=date[3]
  if (day==1) return(TRUE)
  else return(FALSE)
}

.isFirstDateOnQuarter <- function(date)
{
  day=date[3]
  month=date[2]
  if (
    (day==1 && month==1) ||
    (day==1 && month==4) ||
    (day==1 && month==7) ||
    (day==1 && month==10) 
  ) return(TRUE)
  else return(FALSE)
}

.isFirstDateOnSemiAnnual <- function(date)
{
  day=date[3]
  month=date[2]
  if (
    (day==1 && month==1) ||
    (day==1 && month==7) 
  ) return(TRUE)
  else return(FALSE)
}

.isLastDateOnMonth <- function(date)
{
  year=date[1]
  month=date[2]
  day=date[3]
  
  if  (
    (month==1  && day== 31) ||
    (month==2  && day== 29 && .isBisextile(year)) ||
    (month==2  && day== 28 && (!.isBisextile(year))) ||
    (month==3  && day== 31) ||
    (month==4  && day== 30) ||
    (month==5  && day== 31) ||
    (month==6  && day== 30) ||
    (month==7  && day== 31) ||
    (month==8  && day== 31) ||
    (month==9  && day== 30) ||
    (month==10  && day== 31) ||
    (month==11  && day== 30) ||
    (month==12  && day== 31) 
  ) return(TRUE)
  else return(FALSE)
  
}

.isLastDateOnQuarter <- function(date)
{
  day=date[3]
  month=date[2]
  if (
    (day==31 && month==3) ||
    (day==30 && month==6) ||
    (day==30 && month==9) ||
    (day==31 && month==12) 
  ) return(TRUE)
  else return(FALSE)
}

.isLastDateOnSemiAnnual <- function(date)
{
  day=date[3]
  month=date[2]
  if (
    (day==30 && month==6) ||
    (day==31 && month==12) 
  ) return(TRUE)
  else return(FALSE)
}

#TRUE if x1=c(x11,x12) is earlier then x2=c(x21,x22)
.isMinorPeriodYP <- function (x1,x2,f=NULL)
{
  
  if (is.null(f)) stop('.isMinorPeriodYP(): NULL frequency.') 
  if (!( .isCompliantYP(x1,f) && .isCompliantYP(x2,f)))	stop('.isMinorPeriodYP(): uncompliant inputs.') 
  if (x1[1]<x2[1]) return(TRUE) 
  if (x1[1] == x2[1] && x1[2] < x2[2]) return(TRUE) 
  return(FALSE) 
}

#true if xts/ts is univariate && length>1
.isUnivariate <- function(x=NULL)
{
  if (is.null(x)) stop('.isUnivariate(): input needs to be instance of ts() or xts() class.') 
  if (!(is.xts(x) || is.ts(x))) stop(".isUnivariate(): input needs to be instance of xts() or ts() class.") 
  dims=dim(x) 
  if (is.xts(x))
  {
    
    if (length(dims)<2) stop('.isUnivariate(): misformed coredata in input xts.') 
    return (dims[2]==1 && dims[1]>0)  #new: also check there are at least 1 samples
  }
  
  if (is.ts(x))
  {	
    #dim null on univariate ts ....
    if (is.null(dims)) { 
      
      return(length(x)>0)  
    }
    else
    {
      if (length(dims)<2) stop('.isUnivariate(): misformed dimension in input ts.') 
      return (dims[2]==1 && dims[1]>0) #also check there are at least 1 samples
    }
  }
}
 
#make.names convert string in a new string that can be a var name
.MAKENAMES <- function(s=NULL,giveWarning=TRUE,callerName=NULL)
{
  if (is.null(s)) stop('.MAKENAMES(): input must be a either string or an array of strings.') 
  if (! is.character(s)) stop('.MAKENAMES(): input must be either a string or an array of strings.') 
  outF=c() 
  outF=make.names(s,unique=FALSE) 
  #this must be after 'cause make.names adds dots
  outF=gsub('\\.','',outF) 
  suffixVar=0 
  for (idx in 1: length(s)) 
  { 
    #wont allow empty string
    if (outF[idx] == '') 
    { 
      suffixVar=suffixVar+1 
      outF[idx]=paste('var',suffixVar,sep='') 
    }
    
    if (giveWarning==TRUE) 
    { 
      if (s[idx]!=outF[idx]) cat(ifelse(is.null(callerName),'.MAKENAMES(): warning, ',callerName),s[idx],' name will be converted in ',outF[idx],'\n',sep='') 
    }
    
  }
  
  return(outF) 
}

.monthToQuarter <- function(month)
{
  if (month<4)
  {
    return(1)
  } else if(month<7)
  {
    return(2)
  } else if(month<10)
  {
    return(3)
  } else 
  {
    return(4)
  }
  
}

.monthToSemiAnnual <- function(month)
{
  if (month<7)
  {
    return(1)
  } else 
  {
    return(2)
  }
  
}

#NOELS support function
.NOELSCompliantInput <- function(x=NULL)
{
  
  if (is.null(x)) return(FALSE) 
  if (is.numeric(x)) return(TRUE) 
  if (is.xts(x)) return(TRUE) 
  if (is.ts(x)) return(TRUE) 
  if (all(is.na(x))) return(TRUE) 
  return(FALSE) 
}

#return count of missing Values on last samples
.numberOfEndingMissing <- function(x=NULL)
{
  if (is.null(x)) stop('.numberOfEndingMissing(): input needs to be instance of ts() or xts() class.') 
  if (!(is.ts(x) || is.xts(x))) stop('.numberOfEndingMissing(): input needs to be instance of class ts() or xts()') 
  i=1 
  while (i<=length(x) && is.na(x[length(x)+1-i])) i=i+1 
  return(i-1) 
}

#return count of missing Values on first samples
.numberOfStartingMissing <- function(x=NULL)
{
  if (is.null(x)) stop('.numberOfStartingMissing(): input needs to be instance of ts() or xts() class.') 
  if (!(is.ts(x) || is.xts(x))) stop('.numberOfStartingMissing(): input needs to be instance of ts() or xts() class.') 
  i=1 
  while (i<=length(x) && is.na(x[i])) i=i+1 
  return(i-1) 
}
 
#.TRIM delete trailing and leading spaces on a string
.TRIM <- function(s=NULL)
{
  if (is.null(s)) return(NULL) 
  if (! is.character(s)) return(s) 
  outF=c() 
  for(idx in 1:length(s)) {
    
    outF=c(outF,gsub("^\\s+|\\s+$", "", s[idx])) 
  }
  
  return(outF) 
}

#extract periodicity from xts (xts::periodicity dont fit requirements)
.xtsPeriodicity <- function (x=NULL) 
{
  if (is.null(x)) stop('.xtsPeriodicity(): input needs to be instance of xts() class.') 
  if (!is.xts(x)) stop(".xtsPeriodicity(): input needs to be instance of xts() class.") 
  
  #attribute bimetsFreq has priority
  if (is.null(attr(x,'.bimetsFreq')))
  {
    scale=NA
    value=NA
    p=NA
    relFrequency=NA 
    if (!(length(x)<2 )) #NA if single sample
    {	
      
      #diff on index unreliable due to dependance on index class (i.e. in yearmon a diff of 1 is not a day nor really a month...)
      tempDiff=diff(.index(x)) 
      p=suppressWarnings(min(tempDiff[which(tempDiff>0)])) 
      if (!(is.na(p)))
      {
        
        #scale: year as max, second as min
        #xts::.index can include on some hw daysaving settings so there could be a 23h day and a 25h day
        
        if (p < 60) 									{	scale <- "second" 				; value <- 0 		;	relFrequency = 31622400;	} #60 sec
        else if (p < 3600) 						{ scale <- "minute" 				; value <- 1 		; relFrequency = 527040;		} #60*60 = 1h
        else if (p < 3600*23) 				{ scale <- "hour" 					; value <- 2		; relFrequency = 8740;			} #1h*24 = 1d can be daysaving!
        else if (p < 3600*(24*6+23)) 	{ scale <- "day" 						; value <- 3		; relFrequency = 366;				} #1d*7  = 1w
        else if (p < 3600*(24*7+23))	{ scale <- "week"						; value <- 4		; relFrequency = 53;				} #1d*8  = 10days (need end feb as minimum)
        else if (p < 3600*(24*9+23))  { scale <- "10days"					; value <- 5		; relFrequency = 36;				} #1d*10 = 2weeks (need end feb as minimum)
        else if (p < 3600*(24*27+23)) { scale <- "2weeks"					; value <- 6		; relFrequency = 24;				} #1d*28 = 1m (need feb as minimum)
        else if (p < 3600*(24*88+23))	{ scale <- "month"  				; value <- 7		; relFrequency = 12;				} #28feb+31(jan or mar)+30(nov or apr)-daysaving if any! ....
        else if (p < 3600*(24*119+23)){ scale <- "trimestral" 		; value <- 8 		; relFrequency = 4;					} #...+31(oct or may)
        else if (p < 3600*(24*180+23)){ scale <- "quadrimestral" 	; value <- 9 		; relFrequency = 3;					} #
        else if (p < 3600*(24*364+23)){ scale <- "semestral"  	 	; value <- 10		; relFrequency = 2;					} #365 min #days in year
        else 	                        { scale <- "year"     	    ; value <- 11		; relFrequency = 1;					}
      }
    }
    else if(length(x)==1)
    {
      if (tclass( x )=='yearqtr') { scale <- "trimestral"   	; value <- 8 		; relFrequency = 4;					}
      if (tclass( x )=='yearmon') { scale <- "month"    			; value <- 7		; relFrequency = 12;				}
      if (tclass( x )=='Date')    { scale <- "day"      		  ; value <- 3		; relFrequency = 366;				}
      
    }
  } else
  {
    if (attr(x,'.bimetsFreq')==1)            { scale <-  "year"           ; value <- 11   ; relFrequency = 1;         }
    else if (attr(x,'.bimetsFreq')==2)       { scale <- "semestral"     	; value <- 10 	; relFrequency = 2;					}
    else if (attr(x,'.bimetsFreq')==3)       { scale <- "quadrimestral"   ; value <- 9 		; relFrequency = 3;					}
    else if (attr(x,'.bimetsFreq')==4)       { scale <- "trimestral"   	  ; value <- 8 		; relFrequency = 4;					}
    else if (attr(x,'.bimetsFreq')==12)      { scale <- "month"    			  ; value <- 7		; relFrequency = 12;				}
    else if (attr(x,'.bimetsFreq')==24)      { scale <- "2weeks"      		; value <- 6		; relFrequency = 24;				}
    else if (attr(x,'.bimetsFreq')==36)      { scale <- "10days"      		; value <- 5		; relFrequency = 36;				}
    else if (attr(x,'.bimetsFreq')==53)      { scale <- "week"  					; value <- 4		; relFrequency = 53;				}
    else if (attr(x,'.bimetsFreq')==366)     { scale <- "day"   					; value <- 3		; relFrequency = 366;				} 
    else if (attr(x,'.bimetsFreq')==8740)    { scale <- "hour"   				  ; value <- 2	  ; relFrequency = 8740;			}
    else if (attr(x,'.bimetsFreq')==527040)  { scale <- "minute"   			  ; value <- 1 		; relFrequency = 527040;		}
    else if (attr(x,'.bimetsFreq')==31622400){ scale <- "second" 				  ; value <- 0 	  ;	relFrequency = 31622400;	}
    
    else stop('.xtsPeriodicity(): unsupported .bimetsFreq.') 
  } 
  
  #eg. .xtsPeriodicity(xts)$scale...
  return(structure(list( scale=scale, value=value ,relFrequency=relFrequency))) 
}

# exported core funs ----------------------------------

#convert a compliant ts/xts into bimets
as.bimets <- function(x=NULL,FILLVALUE=NA,VERBOSE=FALSE,...)
{
  
  outF=NULL 
  coreD=NULL 
  
  if (is.null(x)) stop('as.bimets(): cannot convert NULL time series.') 
  
  if (! (is.ts(x) || is.xts(x))) stop('as.bimets(): input needs to be instance of ts() or xts() class.') 
  
  if (! is.logical(VERBOSE) || is.na(VERBOSE)) stop('as.bimets(): VERBOSE needs to be TRUE or FALSE.')
  if (! (is.numeric(FILLVALUE) || is.na(FILLVALUE))) stop('as.bimets(): FILLVALUE needs to be numeric or missing NA.')
  
  tryCatch({
    isUv=.isUnivariate(x) 
  },error=function(e){stop('as.bimets(): ',e$message)}) 
  if (! isUv) 
  {
    cat('as.bimets(): warning, input time series is multivariate. Only the first column of data will be returned.\n') 
    coreD=coredata(x)[,1] 
  } else {	
    coreD=coredata(x) 
  }
  
  #deal with frequency
  freqIn=frequency(x) 
  if (! (freqIn %in% c(1,2,3,4,12,24,36,53,366))) stop("as.bimets(): unsupported frequency on input ts().") 
  if (is.ts(x))
  {    
    outF=TSERIES(coreD,START=start(x),FREQ=freqIn) 
  } else { #xts
    
    startDate=c() 
    endDate=c() 
    indexDates=c() 
    if (tclass( x )=='yearqtr' || tclass( x )=='yearmon')
    {
      startDate=as.Date(start(x)) 
      endDate=as.Date(end(x)) 
      indexDates=as.Date(index(x)) 
    } else if (tclass( x )=='Date')
    {
      startDate=start(x) 
      endDate=end(x) 
      indexDates=index(x) 
    } else stop("as.bimets(): unsupported index class.") 
    #get static dates
    tryCatch({
      
      #get YP 
      staticYP=unique(.getStaticYP(start=startDate,end=endDate,freq=freqIn)) 
      localYP=.getStaticYP(start=indexDates,freq=freqIn) 
      #convert to numeric YYYYPPP
      if (startDate==endDate) {
        staticYPn=staticYP[1]*1000+staticYP[2] 
        localYPn=localYP[1]*1000+localYP[2] 
      } else {
        staticYPn=staticYP[,1]*1000+staticYP[,2] 
        localYPn=localYP[,1]*1000+localYP[,2] 
      }
      
    },error=function(e){stop('as.bimets(): ',e$message)}) 
    newValue=FILLVALUE 
    tmpCD=rep(newValue,length(staticYPn)) 
    #find indices
    matchIdx=match(localYPn,staticYPn) 
    if (length(matchIdx)!=length(coreD)) stop('as.bimets(): unknown error.') 
    
    if (VERBOSE)
    {
      #get indexdes filled with new data
      newYPs=base::setdiff(staticYPn,localYPn) 
      newIndexes=match(newYPs,staticYPn) 
      if (length(newIndexes)!=length(newYPs)) stop('as.bimets(): unknown error in "VERBOSE".') 
      if (length(newIndexes)>0) 
      {
        cat('as.bimets(): There are new observations inserted into the non-regular input time series:\n') 
        for (idxNI in 1:length(newIndexes))
        {
          insertedY=trunc(newYPs[idxNI]/1000) 
          insertedP=newYPs[idxNI] %% 1000 
          cat('index: ',newIndexes[idxNI],', YP: ',insertedY,' - ', insertedP,', ','filled with: ',newValue,'\n',sep='') 
        }
        
        cat('\n') 
      }
    }
    
    tmpCD[matchIdx]=coreD 
    #deal with 366 <- 365 if not bisextile
    if (freqIn==366) 
    {
      staticDates=.getStaticDates(start=date2yp(startDate,f=366),end=date2yp(endDate,f=366),freq=freqIn) 
      whicNA=which(is.na(staticDates)) 
      tmpCD[whicNA]=tmpCD[whicNA-1] 
      #add last NA if ends with 365 and not bisextile
      if (date2yp(endDate,f=366)[2]==365 && (! .isBisextile(date2yp(endDate,f=366)[2])))
      {
        tmpCD=c(tmpCD,tmpCD[length(tmpCD)]) 
      }
    }
    
    #output
    if (startDate==endDate) {
      outF=TSERIES(tmpCD,START=staticYP,FREQ=freqIn) 
    } else {
      outF=TSERIES(tmpCD,START=staticYP[1,],FREQ=freqIn) 
    }
    
  }#end if xts
  
  if (! is.bimets(outF)) stop('as.bimets(): cannot convert input time series.') 
  
  #copy attributes 
  if (!(is.null(attr(x,'Source'))))   		attr(outF,'Source')   =attr(x,'Source') 
  if (!(is.null(attr(x,'Title'))))    		attr(outF,'Title')    =attr(x,'Title') 
  if (!(is.null(attr(x,'Units'))))    		attr(outF,'Units')    =attr(x,'Units') 
  if (!(is.null(attr(x,'ScaleFac')))) 		attr(outF,'ScaleFac') =attr(x,'ScaleFac') 
  if (!(is.null(attr(x,'DESCRIZIONE')))) 	attr(outF,'DESCRIZIONE') =attr(x,'DESCRIZIONE') 
  if (!(is.null(attr(x,'OGGETTO')))) 			attr(outF,'OGGETTO') =attr(x,'OGGETTO') 
  if (!(is.null(attr(x,'STATO')))) 				attr(outF,'STATO') =attr(x,'STATO') 
  if (!(is.null(attr(x,'STATUS')))) 			attr(outF,'STATUS') =attr(x,'STATUS') 
  if (!(is.null(attr(x,'ID')))) 					attr(outF,'ID') =attr(x,'ID') 
  return(outF) 
}

#convert date to c(year,period) given f=frequency of ts
date2yp <- function(x=NULL,f=1)
{
  
  if (is.null(x)) stop('date2yp(): input needs to be instance of class Date().') 
  outF=NA 
  if (any(is.na(x)) || (is.null(class( x ))) || !(inherits( x ,'Date'))  ) stop('date2yp(): input needs to be instance of class Date().') 
  if (!(f %in% (c(1,2,4,3,12,24,36,53,366)))) stop('date2yp(): frequency f needs to be 1, 2, 3, 4, 12, 24, 36, 53 or 366.') 
  tryCatch({
    
    outF=.getStaticYP(start=x,freq=f) 
  },error=function(e){stop('date2yp(): ',e$message) }) 
  return(outF) 
}

#override frequency on xts
frequency.xts <- function(x=NULL,...) 
{
  if (is.null(x)) stop('frequency(): NULL input') 
  return(.xtsPeriodicity(x)$relFrequency) 
}

#convert BIMETS to TS 
fromBIMETStoTS <- function(x=NULL,...)
{
  if (! is.bimets(x)) stop('fromBIMETStoTS(): input time series is not bimets compliant.') 
  if (is.ts(x)) 
  {
    return(x) 
  } else if (is.xts(x))
  {
    return(fromXTStoTS(x,avoidCompliance=TRUE)) 
  } else stop('fromBIMETStoTS(): cannot convert time series. Unknown error.' ) 
}

#convert BIMETS to XTS 
fromBIMETStoXTS <- function(x=NULL,...)
{
  if (! is.bimets(x)) stop('fromBIMETStoXTS(): input time series is not bimets compliant.') 
  if (is.xts(x)) 
  {
    return(x) 
  } else if (is.ts(x))
  {
    return(fromTStoXTS(x,avoidCompliance=TRUE)) 
  } else stop('fromBIMETStoXTS(): cannot convert time series. Unknown error.' ) 
}

#convert TS to XTS
fromTStoXTS <- function(x=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('fromTStoXTS(): input needs to be instance of ts() class.') 
  tryCatch({
    if (! avoidCompliance ) 
    {
      .isCompliant(x) 
    }
  },error=function(e){stop('fromTStoXTS(): ',e$message) }) 
  #trivial
  if (is.xts(x)) return(x) 
  if (!is.ts(x)) stop("fromTStoXTS(): input needs to be instance of ts() class.") 
  #getfrequency
  fTS=frequency(x) 
  #get dates
  dateArr=GETDATE(x,avoidCompliance=TRUE) 
  #remove NA and relative data
  naIdxs=-which(is.na(dateArr))
  if (length(naIdxs)>0) dateArr=dateArr[naIdxs] 
  tmpData=coredata(x) 
  if (length(naIdxs)>0) tmpData=tmpData[naIdxs] 
  #special case: a 366 ts with length 1 and start on 366 no bisextile
  if (length(dateArr)==0) stop('fromTStoXTS(): cannot convert input time series.') 
  #deal with index class
  if (fTS==4) 
  {
    dataF=data.frame(as.yearqtr(as.Date(dateArr)),tmpData) 
  } else if (fTS==12)
  {
    dataF=data.frame(as.yearmon(as.Date(dateArr)),tmpData) 
  } else {
    dataF=data.frame(as.Date(dateArr),tmpData) 
  }
  
  #saving hours 1970 bugs
  suppressWarnings({xt=xts(dataF[,2],order.by=dataF[,1],tzone=Sys.getenv("TZ"))}) 
  
  #copy attributes 
  if (!(is.null(attr(x,'Source'))))   		attr(xt,'Source')   =attr(x,'Source') 
  if (!(is.null(attr(x,'Title'))))    		attr(xt,'Title')    =attr(x,'Title') 
  if (!(is.null(attr(x,'Units'))))    		attr(xt,'Units')    =attr(x,'Units') 
  if (!(is.null(attr(x,'ScaleFac')))) 		attr(xt,'ScaleFac') =attr(x,'ScaleFac') 
  if (!(is.null(attr(x,'DESCRIZIONE')))) 	attr(xt,'DESCRIZIONE') =attr(x,'DESCRIZIONE') 
  if (!(is.null(attr(x,'OGGETTO')))) 			attr(xt,'OGGETTO') =attr(x,'OGGETTO') 
  if (!(is.null(attr(x,'STATO')))) 				attr(xt,'STATO') =attr(x,'STATO') 
  if (!(is.null(attr(x,'STATUS')))) 			attr(xt,'STATUS') =attr(x,'STATUS') 
  if (!(is.null(attr(x,'ID')))) 					attr(xt,'ID') =attr(x,'ID') 
  
  #set freqeuncy attrib on xts
  attr(xt,'.bimetsFreq')=fTS 
  
  return(xt) 
}

#convert XTS to TS
fromXTStoTS <- function(x=NULL,avoidCompliance=FALSE,...)
{	
  if (is.null(x)) stop('fromXTStoTS(): input needs to be instance of xts() class.') 
  tryCatch({
    if (! avoidCompliance ) 
    {
      .isCompliant(x) 
    }
  },error=function(e){stop('fromTStoXTS(): ',e$message) }) 
  if (is.ts(x)) return(x) 
  if (!is.xts(x)) stop("fromXTStoTS(): input needs to be instance of xts() class.") 
  xtsF=frequency(x) 
  startYP=c() 
  endYP=c() 
  tmpCD=c() 
  #get start / end year period
  if (xtsF==4) {
    
    startYP=yq2yp(start(x)) 
    endYP=yq2yp(end(x)) 
  } else if (xtsF==12) {
    
    startYP=ym2yp(start(x)) 
    endYP=ym2yp(end(x)) 
  } else {
    
    startYP=date2yp(start(x),f=xtsF) 
    endYP=date2yp(end(x),f=xtsF) 
  }
  
  #get static dates
  tryCatch({
    staticDates=.getStaticDates(start=startYP,end=endYP,freq=xtsF)
  },error=function(e){stop('fromXTStoTS(): ',e$message) })
  
  #get NA indexes
  whichNA=which(is.na(staticDates)) 
  #preallocate data array
  tmpCD=rep(NA,length(staticDates)) 
  #only if daily...
  if (length(whichNA)>0) 
  {
    #set to coredata only in locations != whichNA
    tmpCD[-whichNA]=coredata(x)[,1] 
    #copy 365 on 366 if not bisextile
    tmpCD[whichNA]=tmpCD[whichNA-1] 
  } else
  {
    tmpCD=coredata(x)[,1] 
  }
  
  #add a 366 if last obs is 365 and next is NA    
  if (endYP[2]==365 && is.na(.getStaticDates(start=c(endYP[1],366),freq=xtsF)))
  {
    tmpCD=c(tmpCD,tmpCD[length(tmpCD)]) 
  }
  
  xt=ts(tmpCD,start=startYP,frequency=xtsF) 
  if (!(is.null(attr(x,'Source'))))       attr(xt,'Source')   =attr(x,'Source') 
  if (!(is.null(attr(x,'Title'))))        attr(xt,'Title')    =attr(x,'Title') 
  if (!(is.null(attr(x,'Units'))))        attr(xt,'Units')    =attr(x,'Units') 
  if (!(is.null(attr(x,'ScaleFac'))))     attr(xt,'ScaleFac') =attr(x,'ScaleFac') 
  if (!(is.null(attr(x,'DESCRIZIONE'))))  attr(xt,'DESCRIZIONE') =attr(x,'DESCRIZIONE') 
  if (!(is.null(attr(x,'OGGETTO')))) 			attr(xt,'OGGETTO') =attr(x,'OGGETTO') 
  if (!(is.null(attr(x,'STATO')))) 				attr(xt,'STATO') =attr(x,'STATO') 
  if (!(is.null(attr(x,'STATUS')))) 			attr(xt,'STATUS') =attr(x,'STATUS') 
  if (!(is.null(attr(x,'ID')))) 					attr(xt,'ID') =attr(x,'ID') 
  return(xt) 
}

#get bimets conf
getBIMETSconf <- function(opt=NULL)
{
  if (is.null(opt)) return(NULL) 
  return(toupper(.TRIM(getOption(opt)))) 
}

#test if a time series is compliant and deals with options
is.bimets <- function(x=NULL,suppressErrors=TRUE,...)
{
  outF=FALSE 
  #check if compliant
  tryCatch({
    .isCompliant(x)
    outF=TRUE 
  },error=function(e){if (! suppressErrors) stop('is.bimets(): error. ',e$message) }) 
  return(outF) 
}

#normalize c(y,p) if p>f. e.g. c(2000,5) & f=4 => c(2001,1)
normalizeYP <- function(x=NULL,f=NULL)
{
  if (is.null(x)) stop('normalizeYP(): Uncompliant input.') 
  if (is.null(f)) stop('normalizeYP(): NULL frequency.') 
  if (!(.isCompliantF(f))) stop('normalizeYP(): uncompliant frequency') 
  if (!(is.vector(x) && length(x)==2))  stop('normalizeYP(): Uncompliant input.') 
  if (!(is.numeric(x[1]) ) )  stop('normalizeYP(): year must be a positive integer.') 
  if (!(is.numeric(x[2]) ) )  stop('normalizeYP(): period must be a positive integer.') 
  if (is.na(x[1])  )  stop('normalizeYP(): year must be a positive integer.') 
  if (is.na(x[2])  )  stop('normalizeYP(): period must be a positive integer.') 
  if (!( x[1]>=0) )  stop('normalizeYP(): year must be a positive integer.') 
  if (!(x[1]%%1==0))  stop('normalizeYP(): non-integer year.') 
  if (!(x[2]%%1==0))  stop('normalizeYP(): non-integer period.') 
  return(c(x[1]+((x[2]-1)%/%f ),((x[2]-1)%%f)+1)) 
}

#set bimets conf
setBIMETSconf <- function(opt=NULL,value=NULL,suppressOutput=FALSE)
{
  if (opt=='BIMETS_CONF_DIP') options('BIMETS_CONF_DIP'=value) 
  if (opt=='BIMETS_CONF_CCT') options('BIMETS_CONF_CCT'=value) 
  if (opt=='BIMETS_CONF_NOC') options('BIMETS_CONF_NOC'=value) 
  if (suppressOutput==TRUE) return(invisible()) 
  return(cat(paste(opt,'=',toupper(.TRIM(value)),'\n'))) 
}

#convert yearmon to c(year,period)
ym2yp <- function(x=NULL)
{
  if (is.null(x)) stop('ym2yp(): input needs to be instance of yearmon class.') 
  outF=NA 
  if ( any(is.na(x)) || is.null(class( x )) || !inherits( x ,'yearmon')) stop('ym2yp(): input needs to be instance of class yearmon.') 
  tryCatch({
    
    x=as.Date(x) 
    outF=.getStaticYP(start=x,freq=12) 
  },error=function(e){stop('yq2yp(): ',e$message) }) 
  return(outF) 
}

#convert yearqtr to c(year,period)
yq2yp <- function(x=NULL)
{
  if (is.null(x)) stop('yq2yp(): input needs to be instance of yearqtr class.') 
  outF=NA 
  if ( any(is.na(x)) || (is.null(class( x ))) || !(inherits( x ,'yearqtr'))) stop('yq2yp(): input needs to be instance of class yearqtr.') 
  tryCatch({
    
    x=as.Date(x) 
    outF=.getStaticYP(start=x,freq=4) 
  },error=function(e){stop('yq2yp(): ',e$message) }) 
  return(outF) 
}

# A1D code ----------------------------------------

#A1D defines a one-dimensional array..
A1D <- function(...,length=NULL,avoidCompliance=FALSE)
{
  
  if (!(is.null(length))) 
  {
    if (!(is.numeric(length) ) ) stop('A1D(): length must be an integer.') 
    if (!(length%%1==0))  stop('A1D(): non-integer length.') 
    if (!(length>=0))  stop('A1D(): length must be a positive integer.') 
  }
  
  outF=c() 
  #an input is null
  tryCatch({inputsL=list(...) },error=function(e){stop('A1D(): an input argument is NULL.')}) 
  #no args
  if (is.null(length) && (length(inputsL)==0)) stop('A1D(): at least one parameter is required.') 
  #no values
  if (length(inputsL)==0) 
  {
    if (length==0) return(outF) 
    outF=rep(0,length)
    return(outF) 
  }
  
  #inputs are ts xts or numeric or na
  if (all(as.logical(lapply(inputsL,.A1DCompliantInput))))
  {
    #sum of length of inputs
    totLength=0 
    for (idx in (1:length(inputsL))) 
    {
      #check compliance
      if (!(avoidCompliance) && (is.ts(inputsL[[idx]]) || is.xts(inputsL[[idx]])))
      {
        tryCatch({.isCompliant(inputsL[[idx]]) },error=function(e){stop('A1D(): ',e$message) }) 
      }
      
      totLength=totLength+length(inputsL[[idx]]) 
    }
	
	  if (!(is.null(length)) && (totLength>length)) stop('A1D(): too many elements are specified for given length.') 
    #combine
    for (idx in (1:length(inputsL))) 
    {
      if ((is.ts(inputsL[[idx]])) || (is.xts(inputsL[[idx]]))) 
      {
        outF=c(outF,coredata(inputsL[[idx]])) 
      } else {
        outF=c(outF,inputsL[[idx]]) 
      }
    }
    
    #add tail zeros    
    if ( (!(is.null(length))) && (totLength<length)) 
    {
      for (idx in (1:(length-totLength))) outF=c(outF,0) 
    }
    
    
  } else if (all(as.logical(lapply(inputsL,is.character)))) {
    
    #inputs are strings
    
    if (!(is.null(length)) && (length(inputsL)>length)) stop('A1D(): too many elements are specified for given length.') 
    #length specified and inputs are strings
    if (!(is.null(length)))
    { 
      
      for (idx in (1:length)) 
      {
        if (idx > length(inputsL)) { outF=c(outF,'') } else {outF=c(outF,inputsL[[idx]]) }
        
      }
      
      #length not specified and inputs are strings
    } else {
      for (idx in (1:length(inputsL))) 
      {
        outF=c(outF,inputsL[[idx]]) 
      }
    }
    
  } else {
    stop('A1D(): inputs must be all strings or all instances of the class numeric, NA, ts() or xts().') 
  }
  
  return(outF) 
}

# ANNUAL code ----------------------------------------

#ANNUAL creates a annual/yearly time series from an existing time series.
ANNUAL <- function(x=NULL,fun=NULL,avoidCompliance=FALSE,...)
{
  
  if (is.null(x)) stop('ANNUAL(): input time series needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('ANNUAL(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    #input is annual
    if (frequency(x)==1) {outF=x }
    
    #input is semiannual
    else if (frequency(x)==2)
    {
      if (is.null(fun))
      {
        stop('ANNUAL(): argument "fun" must be provided when converting a semiannual time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even semester add to out
          if ((idx + start(x)[2] -1) %% 2 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even semester add to out
          if ((idx + start(x)[2] -1) %% 2 == 0 ) 
          {
            idx_tmp=0 
            while(is.na(x[idx-idx_tmp] && idx_tmp<1 && idx_tmp < idx-1 )) idx_tmp=idx_tmp+1 
            outCD=c(outCD,x[idx]) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) outCD=c(outCD,sum(x[idx],x[(idx-1)])) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) 
          { 
            #nsum(NA,NA,NA,...)=NA 
            tempV=sum(x[idx],x[(idx-1)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) ) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) outCD=c(outCD,mean(c(x[idx],x[(idx-1)]))) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) 
          { 
            #nave(NA,NA,NA)=NA 
            tempV=mean(c(x[idx],x[(idx-1)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else stop('ANNUAL(): unknown argument "fun".') 
    }
    
    #input is QUARTERLY
    else if (frequency(x)==4)
    {
      if (is.null(fun))
      {
        stop('ANNUAL(): argument "fun" must be provided when converting a quarterly time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter add to out
          if ((idx + start(x)[2] -1) %% 4 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter add to out
          if ((idx + start(x)[2] -1) %% 4 == 0 ) 
          {
            idx_tmp=0 
            while(is.na(x[idx-idx_tmp]) && idx_tmp < 3 && idx_tmp < idx -1) idx_tmp=idx_tmp+1 
            outCD=c(outCD,x[idx-idx_tmp]) 
          }
          
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter and there is 3 qtr before add to out
          if (((idx + start(x)[2] -1) %% 4 == 0 ) && (idx>3)) outCD=c(outCD,sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)])) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter and there is 3 qtr before add to out
          if (((idx + start(x)[2] -1) %% 4 == 0 ) && (idx>3)) 
          { 
            #nsum(NA,NA,NA,...)=NA 
            tempV=sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)])  && is.na(x[(idx-2)]) && is.na(x[(idx-3)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter and there is 3 qtr before add to out
          if (((idx + start(x)[2] -1) %% 4 == 0 ) && (idx>3)) outCD=c(outCD,mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)]))) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if 4th quarter and there is 3 qtr before add to out
          if (((idx + start(x)[2] -1) %% 4 == 0 ) && (idx>3)) 
          { 
            #mean(NA,NA,NA)==NA 
            tempV=mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)])  && is.na(x[(idx-2)]) && is.na(x[(idx-3)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else stop('ANNUAL(): unknown argument "fun".') 
    }
    
    #input is monthly
    else if (frequency(x)==12)
    {
      
      if (is.null(fun))
      {
        stop('ANNUAL(): argument "fun" must be provided when converting a monthly time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) add to out
          if ((idx + start(x)[2] -1) %% 12 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) add to out
          if ((idx + start(x)[2] -1) %% 12 == 0 ) 
          {
            idx_tmp=0 
            while (is.na(x[idx-idx_tmp]) && idx_tmp < 11 && idx_tmp< idx-1) {idx_tmp=idx_tmp+1 }
            outCD=c(outCD,x[idx-idx_tmp]) 
          }
          
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) and there are 11 month before add to out
          if (((idx + start(x)[2] -1) %% 12 == 0 ) && (idx>11)) outCD=c(outCD,sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)],x[idx-6],x[(idx-7)],x[(idx-8)],x[(idx-9)],x[(idx-10)],x[(idx-11)])) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) and there are 11 month before add to out
          if (((idx + start(x)[2] -1) %% 12 == 0 ) && (idx>11)) 
          { 
            #nsum(NA,NA,NA,...)=NA 
            tempV=sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)],x[idx-6],x[(idx-7)],x[(idx-8)],x[(idx-9)],x[(idx-10)],x[(idx-11)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)]) && is.na(x[(idx-3)]) && is.na(x[(idx-4)]) && is.na(x[(idx-5)])
                && is.na(x[(idx-6)]) && is.na(x[(idx-7)]) && is.na(x[(idx-8)]) && is.na(x[(idx-9)]) && is.na(x[(idx-10)]) && is.na(x[(idx-11)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) and there are 11 month before add to out
          if (((idx + start(x)[2] -1) %% 12 == 0 ) && (idx>11)) 
            outCD=c(outCD,mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)],x[idx-6],x[(idx-7)],x[(idx-8)],x[(idx-9)],x[(idx-10)],x[(idx-11)]))) 
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (dec) and there are 11 month before add to out
          if (((idx + start(x)[2] -1) %% 12 == 0 ) && (idx>11)) 
          { 
            #nave(NA,NA,NA)=NA 
            tempV=mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)],x[idx-6],x[(idx-7)],x[(idx-8)],x[(idx-9)],x[(idx-10)],x[(idx-11)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)]) && is.na(x[(idx-3)]) && is.na(x[(idx-4)]) && is.na(x[(idx-5)]) && is.na(x[(idx-6)]) && is.na(x[(idx-7)]) && is.na(x[(idx-8)]) && is.na(x[(idx-9)]) && is.na(x[(idx-10)]) && is.na(x[(idx-11)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else stop('ANNUAL(): unknown argument "fun".') 
    }
    
    #input is daily
    else if (frequency(x)==366)
    {
      #out data
      outCD=NULL 
      
      #get ts dates
      xDates=GETDATE(x,avoidCompliance=TRUE)
      
      #convert to 3-cols matrix: day,month,year
      #if 366 in non-bisextile xDates==NA
      matrixDates=matrix(unlist(lapply(strsplit(xDates,'-'),
                                       function(x) if (is.na(x[1])) return(c(NA,NA,NA)) else return(as.numeric(x)))
      ),
      nrow=length(xDates),ncol=3,byrow=T)
      
      if (is.null(fun))
      {
        stop('ANNUAL(): argument "fun" must be provided when converting a daily time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        outStartP=1 
        
        if (is.na(matrixDates[1,1] )) outStartP=2 
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31 ) outCD=c(outCD,x[idx]) 
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        outStartP=1 
        if (is.na(matrixDates[1,1] )) outStartP=2 
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1] ))
          {
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31 ) 
            {
              idx_tmp=0 
              while (is.na(x[idx-idx_tmp]) && idx_tmp<idx-1 && matrixDates[idx,1]==matrixDates[idx-idx_tmp,1] ) idx_tmp=idx_tmp+1 
              outCD=c(outCD,x[idx-idx_tmp]) 
            }
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='SUM')		 	
      {	
        #skip first year if we dont have all days
        outStartP=2 
        
        if (start(x)[2]<=1) outStartP=1 
        
        #tmp for sum
        tmpOut=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1] ))
          {
            if (matrixDates[idx,2]==1 && matrixDates[idx,3]==1) 
            {
              tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
            }
            
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31)
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NSUM')		 	
      {  
        #skip first year if we dont have all days
        outStartP=2 
        
        if (start(x)[2]<=1) outStartP=1 
        
        #tmp for sum
        tmpOut=NA 
        #flag for skip incomplete years
        canInsert=FALSE 
        
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (matrixDates[idx,2]==1 && matrixDates[idx,3]==1 ) 
            {
              tmpOut=NA 
              if (! is.na(x[idx])) tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx]+tmpOut 
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx] 
            }
            
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31)
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='AVE')		 	
      {  
        #skip first year if we dont have all days
        outStartP=2 
        
        if (start(x)[2]<=1) outStartP=1 
        
        #tmp for ave
        tmpOut=0 
        tmpCnt=1 
        
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (matrixDates[idx,2]==1 && matrixDates[idx,3]==1) 
            {
              tmpOut=x[idx] 
              tmpCnt=1 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
              tmpCnt=1+tmpCnt 
            }
            
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31)
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else if (fun=='NAVE')		 	
      {  
        #skip first year if we dont have all days
        outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        #tmp for sum
        tmpOut=NA 
        tmpCnt=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if (matrixDates[idx,2]==1 && matrixDates[idx,3]==1) 
            {
              tmpOut=NA 
              if (! is.na(x[idx])) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx]+tmpOut 
                tmpCnt=1+tmpCnt 
              }
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
            }
            
            if (matrixDates[idx,2]==12 && matrixDates[idx,3]==31)
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('ANNUAL(): input time series does not span a year. Nothing defined.') 
        if (length(outCD)<2) cat('ANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=1) 
      }
      else stop('ANNUAL(): unknown argument "fun".') 
    }
    
    else {stop('ANNUAL(): unsupported input frequency.') }
    
  }#end is.ts()
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(ANNUAL(fromXTStoTS(x,avoidCompliance=TRUE),fun=fun,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

YEARLY <- ANNUAL

# CUMPROD code ----------------------------------------

#CUMPROD defines the cumulative product of the elements of an input object.
CUMPROD <- function(x=NULL,TSRANGE=NULL,ignoreNA=FALSE,avoidCompliance=FALSE,...)
{
  
  if (is.null(x)) stop('CUMPROD(): input needs to be instance of ts() or xts() class or a numeric array c().') 
  if (!(is.null(TSRANGE)))
  {
    if (length(TSRANGE)==0 && is.na(TSRANGE)) stop('CUMPROD(): null TSRANGE.') 
    if (!(is.numeric(TSRANGE))) stop('CUMPROD(): null TSRANGE.') 
    if (!(length(TSRANGE)==4)) stop('CUMPROD(): null TSRANGE.') 
  }
  
  if (!(is.logical(ignoreNA)) || is.na(ignoreNA))  stop('CUMPROD(): "ignoreNA" must be TRUE or FALSE.') 
  
  outF=x 
  #is xts
  if (is.xts(x)) {
    
    return(fromTStoXTS(CUMPROD(fromXTStoTS(x,avoidCompliance=avoidCompliance),
                               TSRANGE=TSRANGE,
                               ignoreNA=ignoreNA,
                               avoidCompliance=TRUE),
                       avoidCompliance=TRUE)) 
  } else  if (is.ts(x) ) #is ts
  {
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('CUMPROD(): x - ',e$message) }) 
    if (!(is.null(TSRANGE)))
    {
      tryCatch({
        outF=TSPROJECT(outF,TSRANGE=TSRANGE,avoidCompliance=TRUE)
      },error=function(e){stop('CUMPROD(): cannot project time series: ',e$message)}) 
    }
   
  } else {#is array    
    
    if (!(is.numeric(x))) stop('CUMPROD(): input needs to be either an instance of ts() or xts() class, or a numeric array c().') 
  }
  
  #trivial  
  if (length(outF)==1) return(outF) 
  
  if (ignoreNA==FALSE) for (idxTmp in 2:length(outF)) outF[idxTmp]=outF[idxTmp]*outF[idxTmp-1] 
  if (ignoreNA==TRUE) 
  {
    for (idxTmp in 2:length(outF))
      if (! is.na(outF[idxTmp-1]))
      {
        if (! is.na(outF[idxTmp])) 
        {
          outF[idxTmp]=outF[idxTmp]*outF[idxTmp-1]
        } else {
          outF[idxTmp]=outF[idxTmp-1]
        }
      }
  } 
  
  return(outF) 
}

# CUMSUM code ----------------------------------------

#CUMSUM defines the cumulative sum of the elements of an input object.
CUMSUM <- function(x=NULL,TSRANGE=NULL,MODE=NULL,ignoreNA=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('CUMSUM(): input needs to be either an instance of ts() or xts() class, or a numeric array c().') 
  if (!(is.null(TSRANGE)))
  {
    if (length(TSRANGE)==0 && is.na(TSRANGE)) stop('CUMSUM(): error in TSRANGE.') 
    if (!(is.numeric(TSRANGE))) stop('CUMSUM(): error in TSRANGE.') 
    if (!(length(TSRANGE)==4)) stop('CUMSUM(): error in TSRANGE.') 
  }
  
  if (!(is.null(MODE)))
  {
    if (length(MODE)==0 && is.na(MODE)) stop('CUMSUM(): MODE can be YEAR, MONTH or NULL.') 
  }
  
  if (!(is.logical(ignoreNA)) || is.na(ignoreNA))  stop('CUMSUM(): "ignoreNA" must be TRUE or FALSE.') 
  
  outF=x 
  #is xts
  if (is.xts(x)) {
    
    return(fromTStoXTS(CUMSUM(fromXTStoTS(x,avoidCompliance=avoidCompliance),
                              TSRANGE=TSRANGE,
                              MODE=MODE,
                              ignoreNA=ignoreNA,
                              avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  } else  if (is.ts(x) ) #is ts
  {
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('CUMSUM(): x - ',e$message) }) 
    if (!(is.null(TSRANGE)))
    {
      tryCatch({
        outF=TSPROJECT(outF,TSRANGE=TSRANGE,avoidCompliance=TRUE)
      },error=function(e){stop('CUMSUM(): cannot project time series: ',e$message)}) 
    }
    
  } else {#is array    
    
    if (!(is.numeric(x))) stop('CUMSUM(): input needs to be either an instance of ts() or xts() class, or a numeric array.') 
  }
  
  #trivial  
  if (length(outF)==1) return(outF) 
  #array or ts with no mode
  if ( ! is.ts(x) || (is.ts(x) && is.null(MODE) ))
  {
    if (ignoreNA==FALSE) for (idxTmp in 2: length(outF)) outF[idxTmp]=outF[idxTmp]+outF[idxTmp-1] 
    if (ignoreNA==TRUE) 
    {
      for (idxTmp in 2:length(outF))
        if (! is.na(outF[idxTmp-1]))
        {
          if (! is.na(outF[idxTmp])) 
          {
            outF[idxTmp]=outF[idxTmp]+outF[idxTmp-1]
          } else {
            outF[idxTmp]=outF[idxTmp-1]
          }
        }
    } 
  } 
  else { #ts with mode
    
    if (MODE=='YEARLY')
    {
      outFdates=as.integer(GETDATE(outF,NULL,'%Y',avoidCompliance=TRUE)) 
    } else if (MODE=='MONTHLY')
    {
      outFdates=as.integer(GETDATE(outF,NULL,'%m',avoidCompliance=TRUE)) 
    }
    
    if (length(outFdates) != length(outF)) stop('CUMSUM(): unknown error.') 
    if (ignoreNA==FALSE) for (idxTmp in 2: length(outF)) if (outFdates[idxTmp] == outFdates[idxTmp-1]) 
    {
      outF[idxTmp]=outF[idxTmp]+outF[idxTmp-1] 
    }
    
    if (ignoreNA==TRUE) for (idxTmp in 2: length(outF)) 
    {
      if (outFdates[idxTmp] == outFdates[idxTmp-1]) 
      {
        if (! is.na(outF[idxTmp-1]))
        {
          if (! is.na(outF[idxTmp])) 
          {
            outF[idxTmp]=outF[idxTmp]+outF[idxTmp-1]
          } else {
            outF[idxTmp]=outF[idxTmp-1]
          }
        }
      }
    }
  }
  
  return(outF) 
}

# CUMULO code ----------------------------------------

#CUMULO defines the cumulative sum of the elements of an ts in the year
CUMULO <- function(x=NULL,TSRANGE=NULL,ignoreNA=FALSE,avoidCompliance=FALSE,...)
{
  tryCatch({ return(CUMSUM(x,TSRANGE=TSRANGE,MODE='YEARLY',ignoreNA=ignoreNA,avoidCompliance=avoidCompliance)) },error=function(e){stop('CUMULO(): x - ',e$message) }) 
}

# DAILY code ----------------------------------------

#DAILY creates a DAILY time series from an existing time series.
DAILY <- function(x=NULL,fun=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('DAILY(): input time series needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('DAILY(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<2) stop('DAILY(): at least two observations required for interpolation.') 
    #input is daily
    if (frequency(x)==366) {outF=x }
    
    #input is yearly
    else if (frequency(x)==1)
    {
      if (is.null(fun))
      {
        outF=ts(rep(coredata(x),each=366),start=start(x),frequency=366) 
      }
      else if (fun=='INTERP_END')		 	
      {
        #build out data
        inCD=coredata(x) 
        #out data
        outCD=inCD[1] 
        for (idx in (2:length(inCD)))
        {
          #there are no 2 consecutive bisextile years...
          if (.isBisextile(start(x)[1]-2+idx))
          {
            for (idx2 in (1:364))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/365) 
            }           
            
          } else if (.isBisextile(start(x)[1]-1+idx))
          { 
            for (idx2 in (1:366))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/367) 
            }            
          }
          else
          {
            for (idx2 in (1:365))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/366) 
            } 
          }
          
          outCD=c(outCD,inCD[idx]) 
        }
        
        if (.isBisextile(start(x)[1]))
        {
          outF=ts(outCD,start=c(start(x)[1],366),frequency=366) 
        } else
        {
          outF=ts(outCD,start=c(start(x)[1],365),frequency=366) 
        }
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        #build out data
        inCD=coredata(x) 
        #out data
        outCD=inCD[1] 
        for (idx in (2:length(inCD)))
        {
          #there are no 2 consecutive bisextile years...
          if (.isBisextile(start(x)[1]-2+idx))
          {
            for (idx2 in (1:364))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/365) 
            }           
            
          } else if (.isBisextile(start(x)[1]-1+idx))
          { 
            for (idx2 in (1:366))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/367) 
            }            
          }
          else
          {
            for (idx2 in (1:365))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/366) 
            }  
          }
          
          outCD=c(outCD,inCD[idx]) 
        }
        
        if (.isBisextile(start(x)[1]))
        {
          outF=ts(outCD,start=c(start(x)[1],183),frequency=366) 
        } else
        {
          outF=ts(outCD,start=c(start(x)[1],182),frequency=366) 
        }
        
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        #build out data
        inCD=coredata(x) 
        #out data
        outCD=inCD[1] 
        for (idx in (2:length(inCD)))
        {
          if (.isBisextile(start(x)[1]-2+idx))
          {
            for (idx2 in (1:365))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/366) 
            }
            
          } else
          {
            for (idx2 in (1:364))
            {
              outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/365) 
            }
            
            #repeat last obs
            outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/365) 
          }
          
          outCD=c(outCD,inCD[idx]) 
        }
        
        outF=ts(outCD,start=c(start(x)[1],1),frequency=366) 
      }
      else stop('DAILY(): unknown argument "fun".') 
    }
    
    #input is semiannual
    else if (frequency(x)==2)
    {
      if (is.null(fun))
      {
        #out data
        outCD=c() 
        for (idx in (1:length(x)))
        {
          #first semester
          if ((idx +1-start(x)[2])%% 2 == 1) 
          {
            if (.isBisextile(start(x)[1]+trunc((1+(idx-1+start(x)[2]-2))/2)))
            {
              outCD=c(outCD,rep(x[idx],182)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],181)) 
            }
          }else 
          {#second semester
            if (.isBisextile(start(x)[1]+trunc((1+(idx-1+start(x)[2]-2))/2)))
            {
              outCD=c(outCD,rep(x[idx],184)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],185)) 
            }
          }
        }
        
        if (start(x)[2]==1)
        {
          outStart=1 
        } else
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_END')		 	
      {
        #out data
        outCD=c() 
        for (idx in (2:length(x)))
        {
          #first semester
          if ((idx -start(x)[2])%% 2 == 1) 
          {
            
            tmpBY=start(x)[1]+trunc((idx+start(x)[2]-2)/2) 
            outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:183)/184) 
          } else 
          {#second semester
            tmpBY=start(x)[1]+trunc((idx+start(x)[2]-2)/2) 
            if (.isBisextile(tmpBY) )
            {#bisextile
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:182)/183) 
            } else if ( .isBisextile(tmpBY-1))
            {#bisextile beffore
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:180)/181) 
            }
            else
            {#no bisextile
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:181)/182) 
            }
          }
        }
        
        outCD=c(outCD,x[idx]) 
        if (start(x)[2]==1)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=182 
          } else {
            outStart=181 
          }
          
        } else
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=366 
          } else {
            outStart=365 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        #out data
        outCD=c() 
        for (idx in (2:length(x)))
        {
          #first semester
          if ((idx -start(x)[2])%% 2 == 1) 
          {
            
            outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:182)/183) 
          } else 
          {#second semester
            tmpBY=start(x)[1]+trunc((idx+start(x)[2]-2)/2) 
            if (.isBisextile(tmpBY) )
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:183)/184) 
            } else if ( .isBisextile(tmpBY-1))
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:181)/182) 
            }
            else
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:182)/183) 
            }
          }
        }
        
        outCD=c(outCD,x[idx]) 
        if (start(x)[2]==1)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
          
        } else
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        #out data
        outCD=c() 
        for (idx in (2:length(x)))
        {
          #first semester
          if ((idx -start(x)[2])%% 2 == 1) 
          {
            if (.isBisextile(start(x)[1]+trunc((1+(idx-2+start(x)[2]-2))/2)))
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:181)/182) 
            } else
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:180)/181) 
            }
          }else 
          {#second semester
            
            if (.isBisextile(start(x)[1]+trunc((1+(idx-2+start(x)[2]-2))/2)))
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:183)/184) 
            } else
            {
              outCD=c(outCD,x[idx-1]+(x[idx]-x[idx-1])*(0:184)/185) 
            }
          }
        }
        
        outCD=c(outCD,x[idx]) 
        if (start(x)[2]==1)
        {
          outStart=1 
        } else
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else stop('DAILY(): unknown argument "fun".') 
    }
    
    #input is quarterly
    else if (frequency(x)==4)
    {
      if (is.null(fun))
      {
        #out data
        outCD=c() 
        for (idx in (1:length(x)))
        {
          #first quarter
          if ((idx -1+start(x)[2]) %% 4 == 1) 
          { 
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,rep(x[idx],91)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],90)) 
            }
          } else if ((idx -1+start(x)[2]) %% 4 == 2) 
          {#second quarter
            
            outCD=c(outCD,rep(x[idx],91)) 
          } else if ((idx -1+start(x)[2]) %% 4 == 3) 
          {#3 quarter
            
            outCD=c(outCD,rep(x[idx],92)) 
          } else if ((idx -1+start(x)[2]) %% 4 == 0) 
          {#4 quarter
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,rep(x[idx],92)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],93)) 
            }
          }
        }
        
        if (start(x)[2]==1)
        {
          outStart=1 
        } else if (start(x)[2]==2)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_END')  	 	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #first quarter
          if ((idx -1+start(x)[2]) %% 4 == 1) 
          {# 
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:90)/91) 
          } else if ((idx -1+start(x)[2]) %% 4 == 2) 
          {#second quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
          } else if ((idx -1+start(x)[2]) %% 4 == 3) 
          {#3 quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
          } else if ((idx -1+start(x)[2]) %% 4 == 0) 
          {#4 quarter
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:89)/90) 
            } else  if (.isBisextile(1+start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
            } else {
              
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:90)/91) 
            }
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (start(x)[2]==1)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=91 
          } else {
            outStart=90 
          }
          
        } else if (start(x)[2]==2)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=182 
          } else {
            outStart=181 
          }
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=274 
          } else {
            outStart=273 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=366 
          } else {
            outStart=365 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #first quarter
          if ((idx -1+start(x)[2]) %% 4 == 1) 
          {
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:89)/90) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:88)/89) 
            }
          } else if ((idx -1+start(x)[2]) %% 4 == 2) 
          {#second quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
          } else if ((idx -1+start(x)[2]) %% 4 == 3) 
          {#3 quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
          } else if ((idx -1+start(x)[2]) %% 4 == 0) 
          {#4 quarter
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:92)/93) 
            }
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (start(x)[2]==1)
        {
          outStart=46 
        } else if (start(x)[2]==2)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=136 
          } else {
            outStart=135 
          }
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=197 
          } else {
            outStart=196 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=320 
          } else {
            outStart=319 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #first quarter
          if ((idx -1+start(x)[2]) %% 4 == 1) 
          { 
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:90)/91) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:89)/90) 
            }
          } else if ((idx -1+start(x)[2]) %% 4 == 2) 
          {#second quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:90)/91) 
          } else if ((idx -1+start(x)[2]) %% 4 == 3) 
          {#3 quarter
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
          } else if ((idx -1+start(x)[2]) %% 4 == 0) 
          {#4 quarter
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/4)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:91)/92) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:92)/93) 
            }
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (start(x)[2]==1)
        {
          outStart=1 
        } else if (start(x)[2]==2)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else stop('DAILY(): unknown argument "fun".') 
    }
    
    #input is monthly
    else if (frequency(x)==12)
    {
      if (is.null(fun))
      {
        #out data
        outCD=c() 
        for (idx in (1:length(x)))
        {
          #month 1
          if ((idx -1+start(x)[2]) %% 12 == 1) 
          { 
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 2) 
          {#month 2
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,rep(x[idx],29)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],28)) 
            }
            
          } else if ((idx -1+start(x)[2]) %% 12 == 3) 
          {#month 3
            
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 4) 
          {#month 4
            
            outCD=c(outCD,rep(x[idx],30)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 5) 
          {#month 5
            
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 6) 
          {#month 6            
            
            outCD=c(outCD,rep(x[idx],30)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 7) 
          {#month 7
            
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 8) 
          {#month 8
            
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 9) 
          {#month 9
            
            outCD=c(outCD,rep(x[idx],30)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 10) 
          {#month 10
            
            outCD=c(outCD,rep(x[idx],31)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 11) 
          {#month 11
            
            outCD=c(outCD,rep(x[idx],30)) 
          } else if ((idx -1+start(x)[2]) %% 12 == 0) 
          {#month 12
              
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,rep(x[idx],31)) 
            } else
            {
              outCD=c(outCD,rep(x[idx],32)) 
            }
          }
        }
        
        if (start(x)[2]==1)
        {
          outStart=1 
        } else if (start(x)[2]==2)
        {
          
          outStart=32 
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=61 
          } else {
            outStart=60 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
        } else if (start(x)[2]==5)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=122 
          } else {
            outStart=121 
          }
          
        } else if (start(x)[2]==6)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=153 
          } else {
            outStart=152 
          }
        } else if (start(x)[2]==7)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        } else if (start(x)[2]==8)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=214 
          } else {
            outStart=213 
          }
        } else if (start(x)[2]==9)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=245 
          } else {
            outStart=244 
          }
        } else if (start(x)[2]==10)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        } else if (start(x)[2]==11)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=306 
          } else {
            outStart=305 
          }
        } else if (start(x)[2]==12)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=336 
          } else {
            outStart=335 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_END')     	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #month 12
          if ((idx +start(x)[2]) %% 12 == 1) 
          { 
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:31)/32) 
            }
            
            
          } else if ((idx +start(x)[2]) %% 12 == 2) 
          {#month 2-1
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:28)/29) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:27)/28) 
            }
            
          } else if ((idx +start(x)[2]) %% 12 == 3) 
          {#month 3-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx +start(x)[2]) %% 12 == 4) 
          {#month 4-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx +start(x)[2]) %% 12 == 5) 
          {#month 5-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx +start(x)[2]) %% 12 == 6) 
          {#month 6 -1           
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx +start(x)[2]) %% 12 == 7) 
          {#month 7-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx +start(x)[2]) %% 12 == 8) 
          {#month 8-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx +start(x)[2]) %% 12 == 9) 
          {#month 9-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx +start(x)[2]) %% 12 == 10) 
          {#month 10-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx +start(x)[2]) %% 12 == 11) 
          {#month 11-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx +start(x)[2]) %% 12 == 0) 
          {#month 12-1
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (1+start(x)[2]==13)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=366 
          } else {
            outStart=365 
          }
          
        } else if (1+start(x)[2]==2)
        {
          
          outStart=32-1 
        } else if (1+start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=61-1 
          } else {
            outStart=60-1 
          }
        } else if (1+start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92-1 
          } else {
            outStart=91-1 
          }
        } else if (1+start(x)[2]==5)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=122-1 
          } else {
            outStart=121-1 
          }
          
        } else if (1+start(x)[2]==6)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=153-1 
          } else {
            outStart=152-1 
          }
        } else if (1+start(x)[2]==7)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183-1 
          } else {
            outStart=182-1 
          }
        } else if (1+start(x)[2]==8)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=214-1 
          } else {
            outStart=213-1 
          }
        } else if (1+start(x)[2]==9)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=245-1 
          } else {
            outStart=244-1 
          }
        } else if (1+start(x)[2]==10)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275-1 
          } else {
            outStart=274-1 
          }
        } else if (1+start(x)[2]==11)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=306-1 
          } else {
            outStart=305-1 
          }
        } else if (1+start(x)[2]==12)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=336-1 
          } else {
            outStart=335-1 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #month 1
          if ((idx -1+start(x)[2]) %% 12 == 1) 
          { 
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 2) 
          {#month 2
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:28)/29) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:27)/28) 
            }
            
          } else if ((idx -1+start(x)[2]) %% 12 == 3) 
          {#month 3
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 4) 
          {#month 4
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 5) 
          {#month 5
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 6) 
          {#month 6            
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 7) 
          {#month 7
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 8) 
          {#month 8
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 9) 
          {#month 9
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 10) 
          {#month 10
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 11) 
          {#month 11
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 0) 
          {#month 12
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:31)/32) 
            }
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (start(x)[2]==1)
        {
          outStart=1 
        } else if (start(x)[2]==2)
        {
          outStart=32 
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=61 
          } else {
            outStart=60 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
        } else if (start(x)[2]==5)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=122 
          } else {
            outStart=121 
          }
          
        } else if (start(x)[2]==6)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=153 
          } else {
            outStart=152 
          }
        } else if (start(x)[2]==7)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        } else if (start(x)[2]==8)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=214 
          } else {
            outStart=213 
          }
        } else if (start(x)[2]==9)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=245 
          } else {
            outStart=244 
          }
        } else if (start(x)[2]==10)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        } else if (start(x)[2]==11)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=306 
          } else {
            outStart=305 
          }
        } else if (start(x)[2]==12)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=336 
          } else {
            outStart=335 
          }
        }
        
        outStart=outStart+14 
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        #out data
        outCD=c() 
        for (idx in (1:(length(x)-1)))
        {
          #month 1
          if ((idx -1+start(x)[2]) %% 12 == 1) 
          { 
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 2) 
          {#month 2
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:28)/29) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:27)/28) 
            }
            
          } else if ((idx -1+start(x)[2]) %% 12 == 3) 
          {#month 3
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 4) 
          {#month 4
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 5) 
          {#month 5
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 6) 
          {#month 6            
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 7) 
          {#month 7
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 8) 
          {#month 8
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 9) 
          {#month 9
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 10) 
          {#month 10
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
          } else if ((idx -1+start(x)[2]) %% 12 == 11) 
          {#month 11
            
            outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:29)/30) 
          } else if ((idx -1+start(x)[2]) %% 12 == 0) 
          {#month 12
            
            if (.isBisextile(start(x)[1]+trunc((idx-2+start(x)[2])/12)))
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:30)/31) 
            } else
            {
              outCD=c(outCD,x[idx]+(x[idx+1]-x[idx])*(0:31)/32) 
            }
          }
        }
        
        outCD=c(outCD,x[idx+1]) 
        if (start(x)[2]==1)
        {
          outStart=1 
        } else if (start(x)[2]==2)
        {
          
          outStart=32 
        } else if (start(x)[2]==3)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=61 
          } else {
            outStart=60 
          }
        } else if (start(x)[2]==4)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=92 
          } else {
            outStart=91 
          }
        } else if (start(x)[2]==5)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=122 
          } else {
            outStart=121 
          }
          
        } else if (start(x)[2]==6)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=153 
          } else {
            outStart=152 
          }
        } else if (start(x)[2]==7)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=183 
          } else {
            outStart=182 
          }
        } else if (start(x)[2]==8)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=214 
          } else {
            outStart=213 
          }
        } else if (start(x)[2]==9)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=245 
          } else {
            outStart=244 
          }
        } else if (start(x)[2]==10)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=275 
          } else {
            outStart=274 
          }
        } else if (start(x)[2]==11)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=306 
          } else {
            outStart=305 
          }
        } else if (start(x)[2]==12)
        {
          if (.isBisextile(start(x)[1]))
          {
            outStart=336 
          } else {
            outStart=335 
          }
        }
        
        outF=ts(outCD,start=c(start(x)[1],outStart),frequency=366) 
      }
      else stop('DAILY(): unknown argument "fun".') 
    }
    
    else {stop('DAILY(): unsupported input frequency.') }
    
  }#end is.ts()
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(DAILY(fromXTStoTS(x,avoidCompliance=TRUE),fun=fun,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# ELIMELS code ----------------------------------------

#ELIMELS remove selcted elements from array/ts.
ELIMELS <- function(x=NULL,idx=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('ELIMELS(): NULL input.') 
  if (is.null(idx)) stop('ELIMELS(): NULL index.') 
  if (! is.numeric(idx)) stop('ELIMELS(): index must be a numeric array.') 
  if (!(.NOELSCompliantInput(x))) stop('ELIMELS(): inputs must be instances of class array, numeric, ts() or xts().')
  
  if (is.ts(x))
  {
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('ELIMELS(): x - ',e$message) }) 
    tryCatch({
      #get ts data
      tmpData=coredata(x) 
      #r has different time array
      if (frequency(x)==1) 
      {
        tmpTsTime=index(x) 
      } else 
      {
        tmpTsTime=index(x)+1/frequency(x) 
      }
      
      #get indexes of requested obs
      idx=which(tmpTsTime %in% idx) 
      if (length(idx)==0) return(x) 
      if (any(idx < 1)) stop('ELIMELS(): index out of bounds.') 
      if (any(idx > length(x))) stop('ELIMELS(): index out of bounds.') 
      idx=unique(-idx) 
      outF=x[idx] 
      return(outF) 
    },error=function(e){cat('ELIMELS(): ',e$message) }) 
  } else if (is.xts(x))
  {
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('ELIMELS(): x - ',e$message) }) 
    return(ELIMELS(fromXTStoTS(x,avoidCompliance=TRUE),idx=idx)) 
  } else
  { 
    #all indexes must be postive integers
    if (any(idx %% 1 != 0)) stop('ELIMELS(): index must be a positive integer.') 
    if (any(idx < 1)) stop('ELIMELS(): index out of bounds.') 
    if (any(idx > length(x))) stop('ELIMELS(): index out of bounds.') 
    idx=unique(-idx) 
    outF=x[idx] 
    return(outF) 
  }
  
}

# GETDATE code ----------------------------------------

#GETDATE get dates of selected observations.
GETDATE <- function(x=NULL,index=NULL,format='%Y-%m-%d',avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('GETDATE(): input time series needs to be instance of ts() or xts() class.') 
  if (!(is.null(index)))
  {
    if (!(is.numeric(index) && index>0) ) stop('GETDATE(): index must be a positive integer.') 
    if (!(index%%1==0))  stop('GETDATE(): non-integer index') 
  }  
  
  if (is.null(format)) stop('GETDATE(): format needs to be a valid string.') 
  outF=NULL 
  #is xts
  if (is.xts(x)) {
    
    return(GETDATE(fromXTStoTS(x,avoidCompliance=avoidCompliance),index=index,format=format,avoidCompliance=TRUE)) 
  } else  if (is.ts(x) ) #is ts
  {
    
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){stop('GETDATE(): x - ',e$message) }) 
    #get frequency
    locF=frequency(x) 
    outF=c() 
    #if null index get all dates
    if (is.null(index))
    {       
      tryCatch({
        outF=.getStaticDates(start=start(x),end=end(x),freq=locF) 
      },error=function(e){stop('GETDATE(): ',e$message) }) 
    } else {
      
      startY=start(x)[1] 
      startP=start(x)[2] 
      #normalized year-period
      normYP=normalizeYP(c(startY,startP+index-1),locF) 
      normY=normYP[1] 
      normP=normYP[2] 
      if (index>length(x)) stop('GETDATE(): index is greater than time series length.') 
      tryCatch({
        outF=.getStaticDates(start=normYP,freq=locF) 
      },error=function(e){stop('GETDATE(): ',e$message) }) 
    }
    
  } else stop('GETDATE(): input needs to be instance of class ts() or xts().') 
  #asked for quarter?
  if (length(grep('%q', format ))>0)
  {
    tryCatch({outF=format(as.yearqtr(as.Date(outF)),format) },error=function(e){'GETDATE(): format needs to be a valid string.'}) 
  } else
  { 
    tryCatch({outF=format(as.Date(outF),format) },error=function(e){'GETDATE(): format needs to be a valid string.'}) 
  }
  
  return(outF) 
}

# GETRANGE code -------------------------------------------------------------------------

#get intersection or union of input time series ranges
GETRANGE <- function(x=list(),type='INNER',avoidCompliance=FALSE,...)
{
  #check args
  if (! (is.list(x) || is.ts(x) || is.xts(x))) stop('GETRANGE(): "x" must be a time series or a list of time series.')
  if (! is.logical(avoidCompliance) || is.na(avoidCompliance)) stop('GETRANGE(): "verbose" must be TRUE or FALSE.')
  if (! is.character(type) || (type!='INNER' && type!='OUTER' ) ) stop('GETRANGE(): "type" must be "INNER" or "OUTER".')
  #if single ts then transform to list
  if ( (is.ts(x) || is.xts(x))) x=list(x)
  
  if (length(x)==0) stop('GETRANGE(): "x" is an empty list.')
  
  #check list of time series
  isTimeSeries=unlist(lapply(x,function(x) is.ts(x) || is.xts(x)))
  if (! all(isTimeSeries))
  {
    stop('GETRANGE(): "x" must be a time series list of class ts() or xts(). Objects related to the following list indices are not time series: ',
         paste(which(! isTimeSeries),collapse=', '))
  }
  
  localF=frequency(x[[1]])
  
  if (length(x)>1) 
    for (idx in 2:length(x))
    { 
      if (frequency(x[[idx]]) != localF)
        stop('GETRANGE(): time series in the input list must have the same frequency.') 
    }
  
  #get ts metadata
  localTSL=TSLOOK(x[[1]],avoidCompliance=avoidCompliance)
  localStart=c(localTSL$STARTY,localTSL$STARTP)
  localEnd=c(localTSL$ENDY,localTSL$ENDP)
  
  if (length(x)>1) 
    for (idx in 2:length(x))
    {
      tmpTSL=TSLOOK(x[[idx]],avoidCompliance=avoidCompliance)
      tmpStart=c(tmpTSL$STARTY,tmpTSL$STARTP)
      tmpEnd=c(tmpTSL$ENDY,tmpTSL$ENDP)
      
      if (type=='INNER')
      {
        if (NUMPERIOD(localStart,tmpStart,localF)>0)
        {
          localStart=tmpStart
        }
        
        if (NUMPERIOD(localEnd,tmpEnd,localF)<0)
        {
          localEnd=tmpEnd
        }
      }
      
      if (type=='OUTER')
      {
        if (NUMPERIOD(localStart,tmpStart,localF)<0)
        {
          localStart=tmpStart
        }
        
        if (NUMPERIOD(localEnd,tmpEnd,localF)>0)
        {
          localEnd=tmpEnd
        }
      }
    }
  
  #if INNER we can have no intersection
  if(NUMPERIOD(localStart,localEnd,localF)<0) return(NULL)
  
  return(c(localStart,localEnd))
  
}

# GETYEARPERIOD code ----------------------------------------

#GETYEARPERIOD get the year and period arrays of a time series.
GETYEARPERIOD <- function(x=NULL,YEARS='YEAR',PERIODS='PRD',JOIN=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('GETYEARPERIOD(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(YEARS)) stop('GETYEARPERIOD(): NULL YEARS.') 
  if (is.null(PERIODS)) stop('GETYEARPERIOD(): NULL PERIODS.') 
  if (!(is.character(YEARS))) stop('GETYEARPERIOD(): YEARS must be a string.') 
  if (!(is.character(PERIODS))) stop('GETYEARPERIOD(): PERIODS must be a string.') 
  if (nchar(YEARS)==0) stop('GETYEARPERIOD(): YEARS must be a string.') 
  if (nchar(PERIODS)==0) stop('GETYEARPERIOD(): PERIODS must be a string.') 
  if (! is.logical(JOIN)) stop('GETYEARPERIOD(): JOIN must be TRUE or FALSE.') 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){cat('GETYEARPERIOD(): x - ',e$message) }) 
  }
  
  freq=frequency(x)
  
  if (is.ts(x) )
  {			
    localStart=start(x)
    
    outY=vector(length=length(x),mode='numeric')
    outP=vector(length=length(x),mode='numeric')
    
    for (idx in 1:length(x))
    {
      tempYP=normalizeYP(c(localStart[1],localStart[2]-1+idx),f=freq)
      outY[idx]=tempYP[1]
      outP[idx]=tempYP[2]
    }
    
    if (!JOIN)
    {
      outF=list() 
      #assign years
      outF[[YEARS]]=outY
      
      #assign prds
      outF[[PERIODS]]=outP
      
    } else
    {
      outF=cbind(outY,outP)
    }
  }
  
  if (is.xts(x) )
  {
    return(TSDATES(fromXTStoTS(x,avoidCompliance=TRUE),YEARS=YEARS, PERIODS=PERIODS,avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

#legacy compatibility
TSDATES <- GETYEARPERIOD 

# INDEXNUM code -------------------------------------------------------------------------

#rebase a time series to 100 in a given period
INDEXNUM <- function(x=NULL,BASEYEAR=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('INDEXNUM(): input needs to be an instance of BIMETS class.') 
  if (is.null(BASEYEAR)) stop('INDEXNUM(): NULL BASEYEAR.') 
  if (! is.numeric(BASEYEAR) || BASEYEAR<0 || (BASEYEAR %% 1 !=0)) stop('INDEXNUM(): BASEYEAR must be a positive integer.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('INDEXNUM(): x - ',e$message) }) 
  }
  
  #create annual time series
  annualTmp=ANNUAL(x,fun='AVE',avoidCompliance=TRUE) 
  urtslookTmp=TSLOOK(annualTmp,avoidCompliance=TRUE)
  
  #check if base year is in ts range
  if (BASEYEAR<urtslookTmp$START || BASEYEAR>urtslookTmp$ENDY) stop('INDEXNUM(): the time series is not defined in the base year.')
  
  #check if factor is finite  
  if (is.na(annualTmp[[BASEYEAR,1]])) stop('INDEXNUM(): the base year contains some missing value.')  
  if (annualTmp[[BASEYEAR,1]]==0) stop('INDEXNUM(): the base year average is zero.')
  
  #calc factor
  factor=100/annualTmp[[BASEYEAR,1]]
  
  #normalize input
  outF=x*factor 
  return(outF) 
}

# INTS code ----------------------------------------

#INTS defines an array of integers.
INTS <- function(FROM=NULL,TO=NULL,BY=NULL,...)
{
  if (is.null(FROM)) stop('INTS(): at least one input is required.') 
  if (!(is.numeric(FROM) ) ) stop('INTS(): inputs must be integers.') 
  if (!(FROM%%1==0))  stop('INTS(): inputs must be integers.') 
  if (!(is.null(TO))) {
    if (!(is.numeric(TO) ) ) stop('INTS(): inputs must be integers.') 
    if (!(TO%%1==0))  stop('INTS(): inputs must be integers.') 
  }
  
  if (!(is.null(BY))) {
    if (!(is.numeric(BY) ) ) stop('INTS(): inputs must be integers.') 
    if (!(BY%%1==0))  stop('INTS(): inputs must be integers.') 
  }
  
  if (is.null(TO) && is.null(BY)) 
  {
    if (FROM==0) stop('INTS(): magnitude must be greater than 1') 
    if (FROM>0) return(seq(1,FROM)) 
    if (FROM<0) return(seq(-1,FROM)) 
  }
  
  if (is.null(BY)) return(seq(FROM,TO)) 
  return(seq(FROM,TO,BY)) 
}

# LOCS code ----------------------------------------

#LOCS find array indexes by condition
LOCS <- function(x=NULL,options='ALL',...)
{
  
  if (is.null(x)) stop('LOCS(): NULL input.') 
  if (!(is.logical(x))) 
  {
    stop('LOCS(): input must be logical.') 
  }
  
  outF=c() 
  if (is.null(options)) stop('LOCS(): NULL options.') 
  if (!(is.character(options))) stop('LOCS(): allowed options are: ALL, UNIQUE, FIRST, LAST.') 
  #univariate check
  if (  (!(is.null(dim(x)))) && (length(dim(x))>1) ) stop('LOCS(): input must be univariate.') 
  tryCatch({
    outF=which(x) 
  },error=function(s){stop('LOCS(): misformed input.')}) 
  if (options=='ALL')
  {
    if (length(outF)==0) outF=c(0) 
    return(outF) 
  } else if (options=='UNIQUE')
  {
    if (length(outF)==0) stop('LOCS(): input has no true elements.') 
    if (length(outF)!=1) stop('LOCS(): input has more than one true element.') 
    return(outF[1]) 
  } else if (options=='FIRST')
  {
    
    if (length(outF)==0) stop('LOCS(): input has no true elements.') 
    return(outF[1]) 
  } else if (options=='LAST')
  {
    if (length(outF)==0) stop('LOCS(): input has no true elements.') 
    return(outF[length(outF)]) 
  } else
  {
    stop('LOCS(): allowed options are: ALL, UNIQUE, FIRST, LAST.') 
  }
  
  return(outF) 
}

# MONTHLY code ----------------------------------------

#MONTHLY creates a monthly time series from an existing time series.
MONTHLY <- function(x=NULL,fun=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('MONTHLY(): input time series needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('MONTHLY(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<2) stop('MONTHLY(): at least two observations required for interpolation.') 
    #input is monthly
    if (frequency(x)==12) {outF=x }
    
    #input is yearly
    else if (frequency(x)==1)
    {
      #build out data
      inCD=coredata(x) 
      #out data
      outCD=inCD[1] 
      for (idx in (2:length(inCD)))
      {
        for (idx2 in (1:11))
        {
          outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/12) 
        }
        
        outCD=c(outCD,inCD[idx]) 
      }
      
      if (is.null(fun))
      {
        outF=ts(rep(coredata(x),each=12),start=start(x),frequency=12) 
      }
      else if (fun=='INTERP_END')		 	
      {
        outF=ts(outCD,start=c(start(x)[1],12),frequency=12) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        outF=ts(outCD,start=c(start(x)[1],7),frequency=12) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        outF=ts(outCD,start=c(start(x)[1],1),frequency=12) 
      }
      else stop('MONTHLY(): unknown argument "fun".') 
    }
    
    #input is semiannual
    else if (frequency(x)==2)
    {
      #build out data
      inCD=coredata(x) 
      #out data
      outCD=inCD[1] 
      for (idx in (2:length(inCD)))
      {
        for (idx2 in (1:5))
        {
          outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/6)
        }
        
        outCD=c(outCD,inCD[idx]) 
      }
      
      if (is.null(fun))
      {
        if (start(x)[2]==1) outF=ts(rep(coredata(x),each=6),start=c(start(x)[1],1),frequency=12) 
        else if (start(x)[2]==2) outF=ts(rep(coredata(x),each=6),start=c(start(x)[1],7),frequency=12) 
      }
      else if (fun=='INTERP_END')		 	
      {
        if (start(x)[2]==1) outF=ts(outCD,start=c(start(x)[1],6),frequency=12) 
        else if (start(x)[2]==2) outF=ts(outCD,start=c(start(x)[1],12),frequency=12) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],4),frequency=12) 
        else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],10),frequency=12) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {	
        if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],1),frequency=12) 
        else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],7),frequency=12) 
      }
      else stop('MONTHLY(): unknown argument "fun".') 
    }
    
    #input is quarterly
    else if (frequency(x)==4)
    {
      #build out data
      inCD=coredata(x) 
      #out data
      outCD=inCD[1] 
      for (idx in (2:length(inCD)))
      {
        for (idx2 in (1:2))
        {
          outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/3)
        }
        
        outCD=c(outCD,inCD[idx]) 
      }
      
      if (is.null(fun))
      {
        if (start(x)[2]==1) outF=ts(rep(coredata(x),each=3),start=c(start(x)[1],1),frequency=12) 
        else if (start(x)[2]==2) outF=ts(rep(coredata(x),each=3),start=c(start(x)[1],4),frequency=12) 
        else if (start(x)[2]==3) outF=ts(rep(coredata(x),each=3),start=c(start(x)[1],7),frequency=12) 
        else if (start(x)[2]==4) outF=ts(rep(coredata(x),each=3),start=c(start(x)[1],10),frequency=12) 
      }
      else if (fun=='INTERP_END')		 	
      {
        if (start(x)[2]==1) outF=ts(outCD,start=c(start(x)[1],3),frequency=12) 
        else if (start(x)[2]==2) outF=ts(outCD,start=c(start(x)[1],6),frequency=12) 
        else if (start(x)[2]==3) outF=ts(outCD,start=c(start(x)[1],9),frequency=12) 
        else if (start(x)[2]==4) outF=ts(outCD,start=c(start(x)[1],12),frequency=12) 
      }
      else if (fun=='INTERP_CENTER')		 	
      {
        if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],2),frequency=12) 
        else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],5),frequency=12) 
        else if (start(x)[2]==3) 	outF=ts(outCD,start=c(start(x)[1],8),frequency=12) 
        else if (start(x)[2]==4) 	outF=ts(outCD,start=c(start(x)[1],11),frequency=12) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {	
        if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],1),frequency=12) 
        else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],4),frequency=12) 
        else if (start(x)[2]==3) 	outF=ts(outCD,start=c(start(x)[1],7),frequency=12) 
        else if (start(x)[2]==4) 	outF=ts(outCD,start=c(start(x)[1],10),frequency=12) 
      }
      else stop('MONTHLY(): unknown argument "fun".') 
    }
    
    #input is daily
    else if (frequency(x)==366)
    {
      #start period of out ts
      outStartP=NA 
      #out data
      outCD=NULL 
      
      #get ts dates
      xDates=GETDATE(x,avoidCompliance=TRUE)
      
      #convert to 3-cols matrix
      #if 366 in non-bisextile xDates==NA
      matrixDates=matrix(unlist(lapply(strsplit(xDates,'-'),
                                       function(x) if (is.na(x[1])) return(c(NA,NA,NA)) else return(as.numeric(x)))
      ),
      nrow=length(xDates),ncol=3,byrow=T)
      
      if (is.null(fun))
      {
        stop('MONTHLY(): argument "fun" must be provided when converting a daily time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else 
        {
          outStartP=matrixDates[1,2]
        } 
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isLastDateOnMonth(matrixDates[idx,]) ) outCD=c(outCD,x[idx]) 
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else 
        {
          outStartP=matrixDates[1,2]
        } 
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1] ))
          {
            if (.isLastDateOnMonth(matrixDates[idx,]) ) 
            {
              idx_tmp=0 
              while (is.na(x[idx-idx_tmp]) && idx_tmp<idx-1 
                     && matrixDates[idx-idx_tmp,2]==matrixDates[idx,2]) idx_tmp=idx_tmp+1
              outCD=c(outCD,x[idx-idx_tmp])
            }
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else if (fun=='SUM')		 	
      {	
        #skip first m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else if (.isFirstDateOnMonth(matrixDates[1,]))
        {
          outStartP=matrixDates[1,2] 
        } else {
          outStartP=matrixDates[1,2]+1 
        }
        
        #tmp for sum
        tmpOut=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]  ))
          {
            if (.isFirstDateOnMonth(matrixDates[idx,]) )
            {
              tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
            }
            
            if (.isLastDateOnMonth(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else if (fun=='NSUM')		 	
      { 
        #skip first m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else if (.isFirstDateOnMonth(matrixDates[1,]))
        {
          outStartP=matrixDates[1,2]
        } else {
          outStartP=matrixDates[1,2]+1
        }
        
        #tmp for sum
        tmpOut=NA 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnMonth(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx]+tmpOut 
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx] 
            }
            
            if (.isLastDateOnMonth(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else if (fun=='AVE')		 	
      {  
        #skip first m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else if (.isFirstDateOnMonth(matrixDates[1,]))
        {
          outStartP=matrixDates[1,2]
        } else {
          outStartP=matrixDates[1,2]+1
        }
        
        #tmp for ave
        tmpOut=0 
        tmpCnt=1 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnMonth(matrixDates[idx,]))
            {
              tmpOut=x[idx] 
              tmpCnt=1 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
              tmpCnt=1+tmpCnt 
            }
            
            if (.isLastDateOnMonth(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else if (fun=='NAVE')		 	
      {  
        #skip first m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=13 
        } else if (.isFirstDateOnMonth(matrixDates[1,]))
        {
          outStartP=matrixDates[1,2]
        } else {
          outStartP=matrixDates[1,2]+1
        }
        
        #tmp for sum
        tmpOut=NA 
        tmpCnt=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnMonth(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx]+tmpOut 
                tmpCnt=1+tmpCnt 
              }
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
            }
            
            if (.isLastDateOnMonth(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('MONTHLY(): input time series does not span a month. Nothing defined.') 
        if (length(outCD)<2) cat('MONTHLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=12) 
      }
      else stop('MONTHLY(): unknown argument "fun".') 
    }
    
    else {stop('MONTHLY(): unsupported input frequency.') }
    
  }#end is.ts()
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(MONTHLY(fromXTStoTS(x,avoidCompliance=TRUE),fun=fun,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# MOVAVG code ----------------------------------------

#MOVAVG moving average
MOVAVG <- function(x=NULL,L=NULL,DIRECTION=NULL,ignoreNA=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('MOVAVG(): input needs to be instance of ts() or xts() class or a numeric array c().') 
  if (is.null(L)) stop('MOVAVG(): NULL lag "L".') 
  if (!(is.numeric(L) ) ) stop('MOVAVG(): lag "L" must be a positive integer.') 
  if (!(L%%1==0))  stop('MOVAVG(): non-integer lag "L".') 
  if (!(L>0))  stop('MOVAVG(): lag "L" must be a positive integer.') 
  if (!(is.logical(ignoreNA)) || is.na(ignoreNA))  stop('MOVAVG(): "ignoreNA" must be TRUE or FALSE.') 
  
  outF=x 
  #is xts
  if (is.xts(x)) {
    
    return(fromTStoXTS(MOVAVG(fromXTStoTS(x,avoidCompliance=avoidCompliance),
                              L=L,
                              DIRECTION=DIRECTION,
                              ignoreNA=ignoreNA,
                              avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  } else  if (is.ts(x) ) #is ts
  {
    
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('MOVAVG(): x - ',e$message) }) 
    #get frequency
    locF=frequency(x) 
    #get data
    locData=coredata(x) 
    #getStartDate
    locStartDateY=start(x)[1] 
    locStartDateP=start(x)[2] 
    #gen out
    if ((! is.null(DIRECTION)) && (DIRECTION=='AHEAD') )
    {
      outF=ts(MOVAVG(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP),frequency=locF) 
    } else if ((! is.null(DIRECTION)) && (DIRECTION=='CENTER') )
    {
      outF=ts(MOVAVG(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP+as.integer(trunc(L/2))),frequency=locF) 
    } else 
    {
      outF=ts(MOVAVG(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP+L-1),frequency=locF) 
    }
    
  } else {#is array
    
    if (!(is.numeric(x) || is.na(x))) stop('MOVAVG(): input needs to be instance of ts() or xts() class or a numeric array c().') 
    #not enough observation
    if (length(x)<L) stop('MOVAVG(): input has not enough observations as required by lag argument "L".') 
    if (1==L) return(outF) 
    outF=c() 
    #do math
    
    if (ignoreNA==FALSE)
      for (idx in (1:(1+length(x)-L))) 
      { 
        tempSum=x[idx] 
        for (idx2 in (1:(L-1))) tempSum=tempSum+x[idx+idx2] 
        outF=c(outF,tempSum/L) 
      }
    
    if (ignoreNA==TRUE)
      for (idx in (1:(1+length(x)-L))) 
      { 
        tempSum=x[idx] 
        tmpCount=1
        for (idx2 in (1:(L-1)))
        {
          if (is.na(tempSum)) 
          {
            tempSum=x[idx+idx2]
          } else {
            if (! is.na(x[idx+idx2]))
            {
              tempSum=tempSum+x[idx+idx2] 
              tmpCount=1+tmpCount
            }
          }
        }
        outF=c(outF,tempSum/tmpCount) 
      }
  }
  
  return(outF) 
}

MAVE <- MOVAVG 

# MOVTOT code ----------------------------------------

MOVTOT <- function(x=NULL,L=NULL,DIRECTION=NULL,ignoreNA=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('MOVTOT(): input needs to be instance of ts() or xts() class or a numeric array c().') 
  if (is.null(L)) stop('MOVTOT(): NULL lag "L".') 
  if (!(is.numeric(L) ) ) stop('MOVTOT(): lag "L" must be a positive integer.') 
  if (!(L%%1==0))  stop('MOVTOT(): non-integer lag "L".') 
  if (!(L>0))  stop('MOVTOT(): lag "L" must be a positive integer.') 
  if (!(is.logical(ignoreNA)) || is.na(ignoreNA))  stop('MOVTOT(): "ignoreNA" must be TRUE or FALSE.') 
  
  outF=x 
  #is xts
  if (is.xts(x)) {
    
    return(fromTStoXTS(MOVTOT(fromXTStoTS(x,avoidCompliance=avoidCompliance),
                              L=L,
                              DIRECTION=DIRECTION,
                              ignoreNA=ignoreNA,
                              avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  } else  if (is.ts(x) ) #is ts
  {
    
    if (! avoidCompliance ) tryCatch({.isCompliant(x) },error=function(e){cat('MOVTOT(): x - ',e$message) }) 
    #get frequency
    locF=frequency(x) 
    #get data
    locData=coredata(x) 
    #getStartDate
    locStartDateY=start(x)[1] 
    locStartDateP=start(x)[2] 
    #gen out
    if ((! is.null(DIRECTION)) && (DIRECTION=='AHEAD') )
    {
      outF=ts(MOVTOT(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP),frequency=locF) 
    } else if ((! is.null(DIRECTION)) && (DIRECTION=='CENTER') )
    {
      outF=ts(MOVTOT(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP+as.integer(trunc(L/2))),frequency=locF) 
    } else 
    {
      outF=ts(MOVTOT(locData,L,
                     ignoreNA=ignoreNA,avoidCompliance=avoidCompliance),start=c(locStartDateY,locStartDateP+L-1),frequency=locF) 
    }
    
  } else {#is array
    
    if (!(is.numeric(x) || is.na(x))) stop('MOVTOT(): input needs to be instance of ts() or xts() class or a numeric array c().') 
    #not enough observation
    if (length(x)<L) stop('MOVTOT(): input has not enough observations as required by lag argument "L".') 
    if (1==L) return(outF) 
    outF=c() 
    #do math
    
    if (ignoreNA==FALSE)
      for (idx in (1:(1+length(x)-L))) 
      { 
        tempSum=x[idx] 
        for (idx2 in (1:(L-1))) tempSum=tempSum+x[idx+idx2] 
        outF=c(outF,tempSum) 
      }
    
    if (ignoreNA==TRUE)
      for (idx in (1:(1+length(x)-L))) 
      { 
        tempSum=x[idx] 
        for (idx2 in (1:(L-1)))
        {
          if (is.na(tempSum)) 
          {
            tempSum=x[idx+idx2]
          } else {
            if (! is.na(x[idx+idx2]))
            {
              tempSum=tempSum+x[idx+idx2] 
            }
          }
        }
        outF=c(outF,tempSum) 
      }
    
    return(outF) 
    
  }
}

MOVSUM <- MOVTOT 
MTOT <- MOVTOT 
MSUM <- MTOT 

# NAMELIST code ----------------------------------------

#NAMELIST defines a list of names...
NAMELIST <- function(...)
{
  outF=c() 
  #an input is null
  tryCatch({inputsL=list(...)},error=function(e){stop('NAMELIST(): an input argument is NULL')}) 
  #no args
  if (is.null(inputsL) ) stop('NAMELIST(): at least one parameter is required.') 
  if (length(inputsL)==0) stop('NAMELIST(): at least one parameter is required.') 
  #inputs must be chars
  if (all(as.logical(lapply(inputsL,is.character)))) {
    
    for (idx in (1:(length(inputsL)))) 
    { 
      #verify that string is a variable name i.e. '9', '', 'special chars', etc...
      #remove dots
      tmpName=.MAKENAMES(inputsL[[idx]],callerName='NAMELIST(): ') 
      
      outF=c(outF,tmpName) 
    }
    
    return(outF) 
  } else if (all(as.logical(lapply(inputsL,is.ts))) || all(as.logical(lapply(inputsL,is.xts)))) {
    
    outF=list() 
    tmpNames=.MAKENAMES(.getFunArgsNames(...),callerName='NAMELIST(): ') 
    for (idx in (1:(length(inputsL)))) 
    { 
      outF[[tmpNames[idx]]]=inputsL[[idx]] 
    }
    
  } else {
    stop('NAMELIST(): all inputs must be either string or instances of class ts() or xts().') 
  }
  
  return(outF) 
}

# NOELS code ----------------------------------------

#NOELS returns the number of elements of input arguments
NOELS <- function(...)
{
  outF=c() 
  #an input is null
  tryCatch({inputsL=list(...)},error=function(e){stop('NOELS(): an input argument is NULL.')}) 
  #no args
  if (length(inputsL)==0) stop('NOELS(): at least one parameter is required.') 
  #inputs are ts xts or numeric or na
  if (all(as.logical(lapply(inputsL,.NOELSCompliantInput))))
  {
    #combine array/ts length
    for (idx in (1:length(inputsL))) 
    {
      outF=c(outF,length(inputsL[[idx]])) 
    }
    
  } else if (all(as.logical(lapply(inputsL,is.character)))) 
  {
    for (idx in (1:length(inputsL))) 
    {
      outF=c(outF,nchar(inputsL[[idx]])) 
    }
    
  } else {
    stop('NOELS(): inputs must be either strings or instances of class numeric, NA, ts(), or xts().') 
  }
  
  return(outF) 
}

# NUMPERIOD code ----------------------------------------

#numbers of periods between two c(year, period)
NUMPERIOD <- function (x1,x2,f=NULL)
{
  outF=NA 
  if (is.null(f)) stop('NUMPERIOD(): NULL frequency.') 
  if (!(.isCompliantF(f))) stop('NUMPERIOD(): uncompliant frequency') 
  if (!( .isCompliantYP(x1,f) && .isCompliantYP(x2,f)))	stop('NUMPERIOD(): uncompliant input x1 or x2.') 
  outF=x2[2]-x1[2]+(x2[1]-x1[1])*f 
  return(outF) 
}

# QUARTERLY code ----------------------------------------

#QUARTERLY creates a quarterly time series from an existing time series.
QUARTERLY <- function(x=NULL,fun=NULL,avoidCompliance=FALSE,...)
{
  
  if (is.null(x)) stop('QUARTERLY(): input time series needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('QUARTERLY(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    #input is quarterly
    if (frequency(x)==4) {outF=x }
    
    #input is yearly
    else if (frequency(x)==1)
    {
      if (length(x)<2) stop('QUARTERLY(): at least two observations required for interpolation.') 
      
      if (is.null(fun))
      {
        outF=ts(rep(coredata(x),each=4),start=start(x),frequency=4) 
      }
      else 
      {
        #build out data
        inCD=coredata(x) 
        #out data
        outCD=inCD[1] 
        for (idx in (2:length(inCD)))
        {
          for (idx2 in (1:3))
          {
            outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/4) 
          }
          
          outCD=c(outCD,inCD[idx]) 
        }
        
        if (fun=='INTERP_END')		 	
        {
          
          outF=ts(outCD,start=c(start(x)[1],4),frequency=4) 
        }
        else if (fun=='INTERP_CENTER')		 	
        {
          
          outF=ts(outCD,start=c(start(x)[1],3),frequency=4) 
        }
        else if (fun=='INTERP_BEGIN')		 	
        {
          outF=ts(outCD,start=c(start(x)[1],1),frequency=4) 
        }
        else stop('QUARTERLY(): unknown argument "fun".') 
      }
    }
    
    #input is semiannual
    else if (frequency(x)==2)
    {
      if (length(x)<2) stop('QUARTERLY(): at least two observations required for interpolation.') 
      
      if (is.null(fun))
      {
        if (start(x)[2]==1) outF=ts(rep(coredata(x),each=2),start=c(start(x)[1],1),frequency=4) 
        else if (start(x)[2]==2) outF=ts(rep(coredata(x),each=2),start=c(start(x)[1],3),frequency=4) 
      }
      else
      {
        #build out data
        inCD=coredata(x) 
        #out data
        outCD=inCD[1] 
        for (idx in (2:length(inCD)))
        {
          for (idx2 in (1:1))
          {
            outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/2)
          }
          
          outCD=c(outCD,inCD[idx]) 
        }
        
        if (fun=='INTERP_END')		 	
        {
          if (start(x)[2]==1) outF=ts(outCD,start=c(start(x)[1],2),frequency=4) 
          else if (start(x)[2]==2) outF=ts(outCD,start=c(start(x)[1],4),frequency=4) 
        }
        else if (fun=='INTERP_CENTER')		 	
        {
          if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],2),frequency=4) 
          else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],4),frequency=4) 
        }
        else if (fun=='INTERP_BEGIN')		 	
        {	
          if (start(x)[2]==1) 	outF=ts(outCD,start=c(start(x)[1],1),frequency=4) 
          else if (start(x)[2]==2) 	outF=ts(outCD,start=c(start(x)[1],3),frequency=4) 
        }
        else stop('QUARTERLY(): unknown argument "fun".') 
      }
    }
    
    #input is monthly
    else if (frequency(x)==12)
    {
      if (is.null(fun))
      {
        stop('QUARTERLY(): argument "fun" must be provided when converting a monthly time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=12) outStartP=4 
        if (start(x)[2]<=9) outStartP=3 
        if (start(x)[2]<=6) outStartP=2 
        if (start(x)[2]<=3) outStartP=1 
        
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) add to out
          if ((idx + start(x)[2] -1) %% 3 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=12) outStartP=4 
        if (start(x)[2]<=9) outStartP=3 
        if (start(x)[2]<=6) outStartP=2 
        if (start(x)[2]<=3) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) add to out
          if ((idx + start(x)[2] -1) %% 3 == 0 ) 
          {
            idx_tmp=0 
            while (is.na(x[idx-idx_tmp]) && idx_tmp<2 && idx_tmp< idx-1) idx_tmp=idx_tmp+1 
            outCD=c(outCD,x[idx-idx_tmp]) 
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=5 
        if (start(x)[2]<=10) outStartP=4 
        if (start(x)[2]<=7) outStartP=3 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) and there are 2 month before add to out
          if (((idx + start(x)[2] -1) %% 3 == 0 ) && (idx>2)) outCD=c(outCD,sum(x[idx],x[(idx-1)],x[(idx-2)])) 
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=5 
        if (start(x)[2]<=10) outStartP=4 
        if (start(x)[2]<=7) outStartP=3 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) and there are 2 month before add to out
          if (((idx + start(x)[2] -1) %% 3 == 0 ) && (idx>2)) 
          { 
            #nsum(NA,NA,NA)=NA 
            tempV=sum(x[idx],x[(idx-1)],x[(idx-2)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=5 
        if (start(x)[2]<=10) outStartP=4 
        if (start(x)[2]<=7) outStartP=3 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) and there are 2 month before add to out
          if (((idx + start(x)[2] -1) %% 3 == 0 ) && (idx>2)) outCD=c(outCD,mean(c(x[idx],x[(idx-1)],x[(idx-2)]))) 
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=5 
        if (start(x)[2]<=10) outStartP=4 
        if (start(x)[2]<=7) outStartP=3 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (mar jun sep dec) and there are 2 month before add to out
          if (((idx + start(x)[2] -1) %% 3 == 0 ) && (idx>2)) 
          { 
            #nave(NA,NA,NA)=NA 
            tempV=mean(c(x[idx],x[(idx-1)],x[(idx-2)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else stop('QUARTERLY(): unknown argument "fun".') 
    }
    
    #input is daily
    else if (frequency(x)==366)
    {
      #start period of out ts
      outStartP=NA 
      #out data
      outCD=NULL 
      
      #get ts dates
      xDates=GETDATE(x,avoidCompliance=TRUE)
      
      #convert to 3-cols matrix
      #if 366 in non-bisextile xDates==NA
      matrixDates=matrix(unlist(lapply(strsplit(xDates,'-'),
                                       function(x) if (is.na(x[1])) return(c(NA,NA,NA)) else return(as.numeric(x)))
      ),
      nrow=length(xDates),ncol=3,byrow=T)
      
      if (is.null(fun))
      {
        stop('QUARTERLY(): argument "fun" must be provided when converting a daily time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        if (is.na(matrixDates[1,1]))
        {
          #x starts in 366 period in non bisextile
          outStartP=5 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        }
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if(.isLastDateOnQuarter(matrixDates[idx,])) outCD=c(outCD,x[idx])
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=5 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        }
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if(.isLastDateOnQuarter(matrixDates[idx,])) 
            {
              baseQuarter=.monthToQuarter(matrixDates[idx,2])
              
              idx_tmp=0 
              while (is.na(x[idx-idx_tmp]) && idx_tmp<idx-1 && .monthToQuarter(matrixDates[idx-idx_tmp,2])==baseQuarter) idx_tmp=idx_tmp+1
              outCD=c(outCD,x[idx-idx_tmp]) 
            }
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='SUM')		 	
      {	
        #skip first q if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=5 
        } else if (.isFirstDateOnQuarter(matrixDates[1,]))
        {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2])+1
        }
        
        #tmp for sum
        tmpOut=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnQuarter(matrixDates[idx,]))
            {
              tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
            }
            
            if (.isLastDateOnQuarter(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NSUM')		 	
      {  
        #skip first q if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=5 
        } else if (.isFirstDateOnQuarter(matrixDates[1,]))
        {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2])+1
        }
        
        #tmp for sum
        tmpOut=NA 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnQuarter(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx]+tmpOut 
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx] 
            }
            
            if (.isLastDateOnQuarter(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='AVE')		 	
      {  
        #skip first q if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=5 
        } else if (.isFirstDateOnQuarter(matrixDates[1,]))
        {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2])+1
        }
        
        #tmp for ave
        tmpOut=0 
        tmpCnt=1 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnQuarter(matrixDates[idx,]))
            {
              tmpOut=x[idx] 
              tmpCnt=1 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
              tmpCnt=1+tmpCnt 
            }
            
            if ((.isLastDateOnQuarter(matrixDates[idx,])))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else if (fun=='NAVE')		 	
      {  
        #skip first q if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=5 
        } else if (.isFirstDateOnQuarter(matrixDates[1,]))
        {
          outStartP=.monthToQuarter(matrixDates[1,2]) 
        } else {
          outStartP=.monthToQuarter(matrixDates[1,2])+1
        }
        
        #tmp for sum
        tmpOut=NA 
        tmpCnt=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnQuarter(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx]+tmpOut 
                tmpCnt=1+tmpCnt 
              }
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
            }
            
            if (.isLastDateOnQuarter(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
          
        }
        
        if (is.null(outCD)) stop('QUARTERLY(): input time series does not span a quarter. Nothing defined.') 
        if (length(outCD)<2) cat('QUARTERLY(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=4) 
      }
      else stop('QUARTERLY(): unknown argument "fun".') 
    }
    
    else {stop('QUARTERLY(): unsupported input frequency.') }
    
  }#end is.ts()
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(QUARTERLY(fromXTStoTS(x,avoidCompliance=TRUE),fun=fun,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# SEMIANNUAL code ----------------------------------------

#SEMIANNUAL creates a semiannual time series from an existing time series.
SEMIANNUAL <- function(x=NULL,fun=NULL,avoidCompliance=FALSE,...)
{
  
  if (is.null(x)) stop('SEMIANNUAL(): input time series needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('SEMIANNUAL(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    #input is semiannual
    if (frequency(x)==2) {outF=x }
    
    #input is yearly
    else if (frequency(x)==1)
    {
      if (length(x)<2) stop('SEMIANNUAL(): at least two observations required for interpolation.') 
      #build out data
      inCD=coredata(x) 
      #out data
      outCD=inCD[1] 
      for (idx in (2:length(inCD)))
      {
        for (idx2 in (1:1))
        {
          outCD=c(outCD,inCD[(idx-1)]+idx2*(inCD[idx]-inCD[(idx-1)])/2) 
        }
        
        outCD=c(outCD,inCD[idx]) 
      }
      
      if (is.null(fun))
      {
        outF=ts(rep(coredata(x),each=2),start=start(x),frequency=2) 
      }
      else if (fun=='INTERP_END')		 	
      {			
        
        outF=ts(outCD,start=c(start(x)[1],2),frequency=2) 
      }
      else if (fun=='INTERP_BEGIN')		 	
      {
        
        outF=ts(outCD,start=c(start(x)[1],1),frequency=2) 
      }
      else stop('SEMIANNUAL(): unknown argument "fun".') 
    }
    
    #input is quarterly
    else if (frequency(x)==4)
    {
      if (is.null(fun))
      {
        stop('SEMIANNUAL(): argument "fun" must be provided when converting a quarterly time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=2) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter add to out
          if ((idx + start(x)[2] -1) %% 2 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 2 quarters. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=4) outStartP=2 
        if (start(x)[2]<=2) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter add to out
          if ((idx + start(x)[2] -1) %% 2 == 0 ) 
          {
            idx_tmp=0 
            while (is.na(x[idx-idx_tmp]) && idx_tmp<1 && idx_tmp<idx-1) idx_tmp=idx_tmp+1 
            outCD=c(outCD,x[idx-idx_tmp]) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=3) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) outCD=c(outCD,sum(x[idx],x[(idx-1)])) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 2 quarters. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=3) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) 
          { 
            # nsum(NA,NA,NA,...)=NA 
            tempV=sum(x[idx],x[(idx-1)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) ) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 2 quarters. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=3) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) outCD=c(outCD,mean(c(x[idx],x[(idx-1)]))) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 2 quarters. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=3) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if even quarter and there is 1 qtr before add to out
          if (((idx + start(x)[2] -1) %% 2 == 0 ) && (idx>1)) 
          { 
            #nave(NA,NA,NA)=NA 
            tempV=mean(c(x[idx],x[(idx-1)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 2 quarters. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else stop('SEMIANNUAL(): unknown argument "fun".') 
    }
    
    #input is monthly
    else if (frequency(x)==12)
    {
      if (is.null(fun))
      {
        stop('SEMIANNUAL(): argument "fun" must be provided when converting a monthly time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=12) outStartP=2 
        if (start(x)[2]<=6) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun  dec) add to out
          if ((idx + start(x)[2] -1) %% 6 == 0 ) outCD=c(outCD,x[idx]) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        if (start(x)[2]<=12) outStartP=2 
        if (start(x)[2]<=6) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun  dec) add to out
          if ((idx + start(x)[2] -1) %% 6 == 0 ) 
          {
            idx_tmp=0 
            while (is.na(x[idx-idx_tmp]) && idx_tmp<5 && idx_tmp<idx-1) idx_tmp=idx_tmp+1 
            outCD=c(outCD,x[idx-idx_tmp]) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='SUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=7) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun  dec) and there are 6 month before add to out
          if (((idx + start(x)[2] -1) %% 6 == 0 ) && (idx>5)) outCD=c(outCD,sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)])) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSUM')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=7) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun dec) and there are 6 month before add to out
          if (((idx + start(x)[2] -1) %% 6 == 0 ) && (idx>5)) 
          { 
            #nsum(NA,NA,NA,...)=NA 
            tempV=sum(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)],na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)]) && is.na(x[(idx-3)]) && is.na(x[(idx-4)]) && is.na(x[(idx-5)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='AVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=7) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun  dec) and there are 6 month before add to out
          if (((idx + start(x)[2] -1) %% 6 == 0 ) && (idx>5)) outCD=c(outCD,mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)]))) 
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NAVE')		 	
      {	
        #start period of out ts
        outStartP=NA 
        #out data
        outCD=NULL 
        outStartP=3 
        if (start(x)[2]<=7) outStartP=2 
        if (start(x)[2]<=1) outStartP=1 
        for (idx in (1:length(x)))
        {
          #if month == (jun  dec) and there are 6 month before add to out
          if (((idx + start(x)[2] -1) %% 6 == 0 ) && (idx>5)) 
          { 
            #nave(NA,NA,NA)=NA 
            tempV=mean(c(x[idx],x[(idx-1)],x[(idx-2)],x[(idx-3)],x[(idx-4)],x[(idx-5)]),na.rm=TRUE) 
            if (is.na(x[(idx)]) && is.na(x[(idx-1)]) && is.na(x[(idx-2)]) && is.na(x[(idx-3)]) && is.na(x[(idx-4)]) && is.na(x[(idx-5)])) tempV=NA 
            outCD=c(outCD,tempV) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span 6 months. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else stop('SEMIANNUAL(): unknown argument "fun".') 
    }
    
    #input is daily
    else if (frequency(x)==366)
    {
      #start period of out ts
      outStartP=NA 
      #out data
      outCD=NULL 
      
      #get ts dates
      xDates=GETDATE(x,avoidCompliance=TRUE)
      
      #convert to 3-cols matrix
      #if 366 in non-bisextile xDates==NA
      matrixDates=matrix(unlist(lapply(strsplit(xDates,'-'),
                                       function(x) if (is.na(x[1])) return(c(NA,NA,NA)) else return(as.numeric(x)))
                          ),
                          nrow=length(xDates),ncol=3,byrow=T)
      
      if (is.null(fun))
      {
        stop('SEMIANNUAL(): argument "fun" must be provided when converting a daily time series.') 
      }
      else if (fun=='STOCK')		 	
      {	
        if (is.na(matrixDates[1,1]) )
        { #day is 366 and not bisextile
          outStartP=3 
        } else { 
          outStartP=.monthToSemiAnnual(matrixDates[1,2]) 
        }
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isLastDateOnSemiAnnual(matrixDates[idx,])) outCD=c(outCD,x[idx]) 
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSTOCK')		 	
      {	
        
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=3 
        } else {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])
        }
        
        for (idx in (1:length(x)))
        {
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isLastDateOnSemiAnnual(matrixDates[idx,])) 
            {
              baseSemiAnnual=.monthToSemiAnnual(matrixDates[idx,2])
              
              idx_tmp=0 
              while (is.na(x[idx-idx_tmp]) && idx_tmp<idx-1 && .monthToSemiAnnual(matrixDates[idx-idx_tmp,2])==baseSemiAnnual) idx_tmp=idx_tmp+1
              outCD=c(outCD,x[idx-idx_tmp]) 
            }
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='SUM')		 	
      {	
        
        #skip first 6m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=3 
        } else if (.isFirstDateOnSemiAnnual(matrixDates[1,]))
        {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])
        } else  {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])+1 
        }
        
        #tmp for sum
        tmpOut=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnSemiAnnual(matrixDates[idx,]))
            {
              tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
            }
            
            if (.isLastDateOnSemiAnnual(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NSUM')		 	
      {  
       
        #skip first 6m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=3 
        } else if (.isFirstDateOnSemiAnnual(matrixDates[1,]))
        {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])
        } else  {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])+1 
        }
        
        #tmp for sum
        tmpOut=NA 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnSemiAnnual(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) tmpOut=x[idx] 
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx]+tmpOut 
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) tmpOut=x[idx] 
            }
            
            if (.isLastDateOnSemiAnnual(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut) 
            }
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='AVE')		 	
      {  
        
        #skip first 6m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=3 
        } else if (.isFirstDateOnSemiAnnual(matrixDates[1,]))
        {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])
        } else  {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])+1 
        }
        
        #tmp for ave
        tmpOut=0 
        tmpCnt=1 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if ( .isFirstDateOnSemiAnnual(matrixDates[idx,]))
            {
              tmpOut=x[idx] 
              tmpCnt=1 
              canInsert=TRUE 
            } else {
              tmpOut=x[idx]+tmpOut 
              tmpCnt=1+tmpCnt 
            }
            
            if (.isLastDateOnSemiAnnual(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
          
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else if (fun=='NAVE')		 	
      {  
        #skip first 6m if we dont have all days
        if (is.na(matrixDates[1,1])) 
        {
          outStartP=3 
        } else if (.isFirstDateOnSemiAnnual(matrixDates[1,]))
        {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])
        } else  {
          outStartP=.monthToSemiAnnual(matrixDates[1,2])+1 
        }
        
        #tmp for sum
        tmpOut=NA 
        tmpCnt=0 
        #flag for skip incomplete years
        canInsert=FALSE 
        for (idx in (1:length(x)))
        { 
          
          if (! is.na(matrixDates[idx,1]))
          {
            if (.isFirstDateOnSemiAnnual(matrixDates[idx,]))
            {
              tmpOut=NA 
              if (! is.na(x[idx])) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
              canInsert=TRUE 
            } else {
              
              if ((! is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx]+tmpOut 
                tmpCnt=1+tmpCnt 
              }
              if (( is.na(tmpOut)) && (! is.na(x[idx]))) 
              {
                tmpOut=x[idx] 
                tmpCnt=1 
              }
            }
            
            if (.isLastDateOnSemiAnnual(matrixDates[idx,]))
            {
              if (canInsert) outCD=c(outCD,tmpOut/tmpCnt) 
            }
          }
        }
        
        if (is.null(outCD)) stop('SEMIANNUAL(): input time series does not span a semester. Nothing defined.') 
        if (length(outCD)<2) cat('SEMIANNUAL(): warning, the output time series has only one observation.\n')
        
        outF=ts(outCD,start=c(start(x)[1],outStartP),frequency=2) 
      }
      else stop('SEMIANNUAL(): unknown argument "fun".') 
    }
    
    else {stop('SEMIANNUAL(): unsupported input frequency.') }
    
  }#end is.ts()
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(SEMIANNUAL(fromXTStoTS(x,avoidCompliance=TRUE),fun=fun,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# TABIT code ----------------------------------------

#TABIT print ts in human readable form
TABIT <- function(..., 
                  TSRANGE=NULL, 
                  headers=NULL,
                  digits=getOption('digits'), 
                  avoidCompliance=FALSE)
{
  if ((! is.finite(digits) )|| (digits %% 1 !=0) || digits<=0 || digits > 22) 
    stop('TABIT(): digits must be an integer between 1 and 22.') 
  #an input is null
  tryCatch({inputsL=list(...) },error=function(e){stop('TABIT(): an input argument is NULL.')}) 
  #no args
  if (length(inputsL)==0) stop('TABIT(): at least one argument is required.') 
  if (! is.null(TSRANGE)  && (! is.numeric(TSRANGE) || length(TSRANGE) != 4)) {    
    stop("TABIT(): TSRANGE must be a 4-elements numerical vector.") 
  } 
  
  if (! is.null(headers))
  {
    if (any(! is.character(headers)))
      stop("TABIT(): \"headers\" must be a string array.") 
    
    if (length(headers) != length(inputsL))
      stop("TABIT(): \"headers\" and input time series counts must match.") 
  }					 
  
  #check compliance
  if (! avoidCompliance ) 
  {	
    tryCatch({lapply(inputsL,.isCompliant) },error=function(e){stop('TABIT(): ',e$message) }) 
  }
  
  outFreq=NULL 
  #project if TSRANGE specified
  for (idx in (1:length(inputsL)))
  {
    #convert to ts if xts  
    if (is.xts(inputsL[[idx]])) inputsL[[idx]]=fromXTStoTS(inputsL[[idx]],avoidCompliance=TRUE) 
    if (idx==1) outFreq=frequency(inputsL[[idx]]) 
    if (frequency(inputsL[[idx]])!=outFreq) stop('TABIT(): all time series must have the same frequency.') 
    if (!(is.null(TSRANGE)))
    {
      tryCatch({
        inputsL[[idx]]=TSPROJECT(inputsL[[idx]],TSRANGE=TSRANGE,avoidCompliance=TRUE)
      },error=function(e){stop('TABIT(): cannot project time series: ',e$message)}) 
    }
  }
  
  #output formats
  stdFormat=paste0("% -",digits+8,".",digits,'g') 
  stdFormatS=paste0("% -",digits+8,'s') 
  
  #backup list
  seriesListADSL=inputsL
  
  #contains dates of observations
  arrayOfDates=c() 
  
  #array of names max 10 chars
  if (is.null(headers)) 
  {
    seriesListADSLstr=sprintf(stdFormatS,.getFunArgsNames(...))   
  } else {
    seriesListADSLstr=sprintf(stdFormatS,headers) 
  }	  
  
  for (idx in (1:length(seriesListADSL))){
    
    localStart=start(seriesListADSL[[idx]])
    
    for (idx2 in (1:length(seriesListADSL[[idx]]))){
      
      localYP=normalizeYP(c(localStart[1],localStart[2]+idx2-1),f=outFreq)
      
      arrayOfDates=c(arrayOfDates,
                     1000*localYP[1]+localYP[2]) 
    }
  }
  
  if (is.null(arrayOfDates))  {stop('TABIT(): empty arrayOfDates.') }
  
  #remove duplicates and sort
  arrayOfDates=sort(unique(arrayOfDates)) 
  
  #add missings days
  arrayOfDatesMin=min(arrayOfDates) 
  arrayOfDatesMax=max(arrayOfDates) 
  
  tmpIdx=arrayOfDatesMin 
  arrayOfDates2=c(tmpIdx) 
  
  while (tmpIdx<arrayOfDatesMax)
  {
    if (((tmpIdx %% 1000) %% outFreq) == 0 )
    {
      tmpIdx=(tmpIdx+1000)-(tmpIdx %% 1000)+1 
    } else
    {
      tmpIdx=tmpIdx+1 
    }
    
    arrayOfDates2=c(arrayOfDates2,tmpIdx) 
  }
  
  arrayOfDates=arrayOfDates2 
  outF=arrayOfDates 
  
  seriesListADSLstr=paste(seriesListADSLstr,collapse=', ') 
  
  #init some arrays
  startYint=c() 
  startPint=c() 
  endYint=c() 
  endPint=c() 
  freqint=c() 
  
  #get start, end, freq 
  for (idx in (1:length(seriesListADSL))) {
    
    startYint[idx]=as.integer(start(seriesListADSL[[idx]])[1]) 
    startPint[idx]=as.integer(start(seriesListADSL[[idx]])[2]) 
    endYint[idx]=as.integer(end(seriesListADSL[[idx]])[1]) 
    endPint[idx]=as.integer(end(seriesListADSL[[idx]])[2]) 
    freqint[idx]=as.integer(frequency(seriesListADSL[[1]])) 
    
  }
  
  #print header
  cat('\n      Date, Prd., ',seriesListADSLstr,'\n\n',sep='') 
  
  #main cycle
  for (idx in (1:length(arrayOfDates))){
    
    localYint=trunc(arrayOfDates[idx]/1000) 
    localPint=arrayOfDates[idx] %% 1000 
    #init row str
    tmpOutStr='' 
    #init array of out values
    value=c() 
    #cycle in time series
    for (idx2 in (1:length(seriesListADSL))) 
    { 
      #a time series can have null value in selected date
      value[idx2]= sprintf(stdFormatS,'') 
      #check if actual values exist on ts because R return NA on out of range observation
      if ((localYint>endYint[idx2])  || ( (localYint==endYint[idx2])  && (localPint>endPint[idx2])   ) ) 
      {
        value[idx2]=  sprintf(stdFormatS,'') 
      } else if ((localYint<startYint[idx2])  || ( (localYint==startYint[idx2])  && (localPint<startPint[idx2])   ) ) 
      {
        value[idx2]=  sprintf(stdFormatS,'') 
      } else 
      {
        value[idx2]= try(
          sprintf(stdFormat,as.numeric(seriesListADSL[[idx2]][(localYint-startYint[idx2])* freqint[idx2]+ (1+localPint-startPint[idx2])]))) 
      }
      
      #compose row str      
      tmpOutStr=paste(tmpOutStr,', ',value[idx2],sep='') 
    }  
    
    #print out row
    if (outFreq==1) {cat(paste(sprintf("%10s",GETDATE(ts(1,start=c(localYint,localPint),frequency=outFreq),1,format='%Y',avoidCompliance=TRUE)),', ', sprintf("%-4d",localPint), tmpOutStr, '\n',sep=''),sep='')    }
    else if (outFreq==2) {cat(paste(sprintf("%10s",GETDATE(ts(1,start=c(localYint,localPint),frequency=outFreq),1,format='%Y',avoidCompliance=TRUE)),', ', sprintf("%-4d",localPint), tmpOutStr, '\n',sep=''),sep='') }
    else if (outFreq==4) {cat(paste(sprintf("%10s",GETDATE(ts(1,start=c(localYint,localPint),frequency=outFreq),1,format='%Y Q%q',avoidCompliance=TRUE)),', ', sprintf("%-4d",localPint), tmpOutStr, '\n',sep=''),sep='') }   
    else if (outFreq==12) {cat(paste(sprintf("%10s",GETDATE(ts(1,start=c(localYint,localPint),frequency=outFreq),1,format='%b %Y',avoidCompliance=TRUE)),', ', sprintf("%-4d",localPint), tmpOutStr, '\n',sep=''),sep='')  }  
    else {cat(paste(sprintf("%10s",GETDATE(ts(1,start=c(localYint,localPint),frequency=outFreq),1,avoidCompliance=TRUE)),', ', sprintf("%-4d",localPint), tmpOutStr, '\n',sep=''),sep='')    }
    
  }
  cat('\n') 
  
}

# TSERIES code ----------------------------------------

#TSERIES defines a time series ....
TSERIES <- function(...,START=c(2000,1),FREQ=1,
                    SOURCE=NULL,TITLE=NULL,UNITS=NULL,SCALEFAC=0,class=NULL,avoidCompliance=FALSE)
{
  
  if (is.null(FREQ)) stop('TIMESERIES(): FREQ must be one of the following values: 1, 2, 3, 4, 12, 24, 36, 366, A, Y, S, Q, M or D.') 
  if (FREQ=='A' || FREQ=='Y') FREQ=1 
  if (FREQ=='S') FREQ=2 
  if (FREQ=='Q') FREQ=4 
  if (FREQ=='M') FREQ=12 
  if (FREQ=='W') FREQ=53 
  if (FREQ=='D') FREQ=366 
  #check FREQ
  tryCatch({.isCompliantF(FREQ) },error=function(e){stop('TIMESERIES(): FREQ must be one of the following values: 1, 2, 3, 4, 12, 24, 36, 53, 366, A, Y, S, Q, M, W or D.')}) 
  if (! FREQ %in% c(1,2,3,4,12,24,36,53,366)) stop('TIMESERIES(): FREQ must be 1, 2, 3, 4, 12, 24, 36, 53 or 366.') 
  tryCatch({
    if (inherits(START,'Date')) START=date2yp(START,FREQ) 
    if (inherits(START,'yearmon') && FREQ==12) START=ym2yp(START) 
    if (inherits(START,'yearqtr') && FREQ==4) START=yq2yp(START) 
    .isCompliantYP(START,FREQ) },error=function(e){stop('TIMESERIES(): uncompliant start date.')}) 
  outF=NULL 
  #an input is null
  tryCatch({inputsL=list(...) },error=function(e){stop('TIMESERIES(): an input argument is null.')}) 
  if (! all(as.logical(lapply(inputsL,.A1DCompliantInput)))) stop('TIMESERIES(): all input data must be numeric.')  
  
  #no args
  if (is.null(START) ) stop('TIMESERIES(): start date is required. Please use START=c(y,p).') 
  #no args
  if (!(is.null(inputsL[['end']]))) stop('TIMESERIES(): end date is not allowed in TIMESERIES().') 
  #no data provided
  if (length(inputsL)==0)
  {
    #crete ts
    tryCatch({outF=ts(A1D(NA,avoidCompliance=avoidCompliance),start=START,frequency=FREQ)},error=function(e){stop('TIMESERIES(): ',e$message) }) 
  } else
  {
    #crete ts
    tryCatch({outF=ts(A1D(...,avoidCompliance=avoidCompliance),start=START,frequency=FREQ)},error=function(e){stop('TIMESERIES(): ',e$message) }) 
  }
  
  startTS=start(outF) 
  endTS=end(outF) 
  #check if date in bimets range
  if (startTS[1]<.__bimets__data__static_startYear___ || startTS[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('TIMESERIES(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  if (endTS[1]<.__bimets__data__static_startYear___ || endTS[1]>(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1) ) 
    stop(paste0('TIMESERIES(): dates must be in range ',.__bimets__data__static_startYear___,'-',(.__bimets__data__static_startYear___ + .__bimets__data__static_totalLength___ -1),'.')) 
  #add attributes
  if (!(is.null(SOURCE))) attr(outF,'Source')=SOURCE 
  if (!(is.null(TITLE))) attr(outF,'Title')=TITLE 
  if (!(is.null(UNITS))) attr(outF,'Units')=UNITS 
  if ((!(is.null(SCALEFAC))) && (SCALEFAC!=0))
  {
    if (!(is.numeric(SCALEFAC))) stop('TIMESERIES(): SCALEFAC must be numeric.') 
    if ((is.na(SCALEFAC))) stop('TIMESERIES(): SCALEFAC must be numeric.') 
    if (!(SCALEFAC >=0) ) stop('TIMESERIES(): SCALEFAC must be a positive integer or zero.') 
    if (!(SCALEFAC%%1==0))  stop('TIMESERIES(): SCALEFAC must be a positive integer or zero.') 
    attr(outF,'ScaleFac')=SCALEFAC 
  }
  
  if (! is.null(class))
  {
    if (toupper(.TRIM(class))=='XTS')
    {
      tryCatch({
        outF=fromTStoXTS(outF,avoidCompliance=TRUE)
      },error=function(e){stop('TIMESERIES(): ',e$message) }) 
      return(outF) 
    } 
  } else
  { 
    globalCCT=getBIMETSconf(opt='BIMETS_CONF_CCT') 
    if (! is.null(globalCCT) && (globalCCT=='XTS') )
    {
      tryCatch({
        outF=fromTStoXTS(outF,avoidCompliance=TRUE)
      },error=function(e){stop('TIMESERIES(): ',e$message) }) 
      return(outF) 
    } 
  }   
  
  return(outF) 
}

TIMESERIES <- TSERIES 

# TSDELTA code ----------------------------------------

#TSDELTA computes differences from a time series.
TSDELTA <- function(x=NULL,L=1,O=1,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSDELTA(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(L)) stop('TSDELTA(): NULL lag L.') 
  if (!(is.numeric(L) && L>0) ) stop('TSDELTA(): lag L must be a positive integer.') 
  if (!(L%%1==0))  stop('TSDELTA(): non-integer lag L.') 
  if (is.null(O)) stop('TSDELTA(): null order O.') 
  if (!(is.numeric(O) && O>0) ) stop('TSDELTA(): order O must be a positive integer.') 
  if (!(O%%1==0))  stop('TSDELTA(): non-integer oreder O.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSDELTA(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<=(L*O)) stop('TSDELTA(): Too much lags: attempting to define a NULL object.')
    
    outF=diff(x,lag=L,differences=O) 
  }
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(TSDELTA(fromXTStoTS(x,avoidCompliance=TRUE),L=L,O=O,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

#backward compatibility
DELTA <- TSDELTA 

# TSDELTALOG code ----------------------------------------

#TSDELTALOG computes differences of the log time series
TSDELTALOG <- function(x=NULL,L=1,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSDELTALOG(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(L)) stop('TSDELTALOG(): NULL lag L.') 
  if (!(is.numeric(L) && L>0) ) stop('TSDELTALOG(): lag L must be a positive integer.') 
  if (!(L%%1==0))  stop('TSDELTALOG(): non-integer lag L.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSDELTALOG(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<=(L)) stop('TSDELTALOG(): Too much lags: attempting to define a NULL object.')
    
    outF=TSDELTA(log(x),L=L,avoidCompliance=TRUE) 
  }
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(TSDELTALOG(fromXTStoTS(x,avoidCompliance=TRUE),L=L, avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# TSDELTAP code ----------------------------------------

#TSDELTAP computes the percent changes of a time series.
TSDELTAP <- function(x=NULL,L=1,ANNUALIZE=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSDELTAP(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(L)) stop('TSDELTAP(): NULL lag L.') 
  if (!(is.numeric(L) && L>0) ) stop('TSDELTAP(): lag L must be a positive integer.') 
  if (!(L%%1==0))  stop('TSDELTAP(): non-integer lag L.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSDELTAP(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<=(L)) stop('TSDELTAP(): Too much lags: attempting to define a NULL object.')
    
    outF=100*TSDELTA(x,L=L,avoidCompliance=TRUE)/TSLAG(x,L,avoidCompliance=TRUE) 
    
    if (ANNUALIZE==TRUE)
    {
      if (!(frequency(x) %% L == 0)) stop('TSDELTAP(): ANNUALIZE is incompatible with provided lag L.') 
      #project TSDELTAP on annual
      tempTS=x 
      #apply the same delta% till end of year (i.e. f/L)
      tempTS2=TSLAG(x,avoidCompliance=TRUE)*(1+outF/100)^(frequency(x)/L) 
      #evaluate new TSDELTAP
      tempTS2=100*(tempTS2/TSLAG(x,avoidCompliance=TRUE)-1) 
      outF=tempTS2 
    }
  }
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(TSDELTAP(fromXTStoTS(x,avoidCompliance=TRUE),L=L,ANNUALIZE=ANNUALIZE,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

#backward compatibility
DELTAP <- TSDELTAP 

# TSEXTEND code ----------------------------------------

#TSEXTEND extends time series definition range by a specified criteria
TSEXTEND <- function(x=NULL,BACKTO=NULL,UPTO=NULL,EXTMODE='GROWTH',FACTOR=NA,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSEXTEND(): input needs to be instance of ts() or xts() class.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSEXTEND():',e$message) }) 
  }
  
  if (is.ts(x))
  {
    #BACKTO not null and before  start(x)			
    if (! is.null(BACKTO))
      if (.isMinorPeriodYP(BACKTO,start(x),frequency(x))) 
      {
        #default value to insert in extension
        value2ins=NA 
        value2ins2=NA 
        #fix tsp before window
        outF=.fixTsp(outF)
        
        #TSEXTEND range
        tryCatch({outF=window(outF,start=BACKTO,extend=TRUE) },error=function(e){cat('TSEXTEND():',e$message) }) 
        
        #select value to insert
        if (EXTMODE=='MISSING') 
        {
          value2ins=NA 
          outF[1:(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))]=value2ins 
        }
        
        if (EXTMODE=='ZERO') 
        {
          value2ins=0 
          outF[1:(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))]=value2ins 
        }
        
        if (EXTMODE=='CONSTANT') 
        {
          #select first non.missing value									
          i=1 
          while(i<=length(x) && is.na(value2ins))
          { 
            value2ins=x[i] 
            i=i+1 
          }
          
          outF[1:(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))]=value2ins 
        }
        
        if (EXTMODE=='MYCONST') 
        {
          #as.numeric warns if non numeric input
          suppressWarnings({
            tmpF=	as.numeric(FACTOR) 
          }) 
          outF[1:(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))]=tmpF 
        }
        
        if (EXTMODE=='MEAN4') 
        {
          value2ins=NA 
          if (length(x)>3)
          {
            #mean of first 4 consecutive non.missing value	()								
            i=1 
            while(i<=(length(x)-3))
            { 
              #if internal missing stop...
              if (!(is.na(x[i])) && is.na(x[i+1])) break 
              if (!(is.na(x[i]) || is.na(x[i+1]) || is.na(x[i+2]) || is.na(x[i+3])))
              {
                value2ins=mean(c(x[i],x[i+1],x[i+2],x[i+3])) 
                break 
              }
              i=i+1 
            }
          }
          
          outF[1:(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))]=value2ins 
        }
        
        if (EXTMODE=='GROWTH4') 
        {
          value2ins=NA 
          if (length(x)>7)
          {
            #look code for description :)								
            i=1 
            while(i<=(length(x)-7))
            { 
              #if internal missing then stop...
              if (!(is.na(x[i])) && is.na(x[i+1])) break 
              if (!(is.na(x[i]) || is.na(x[i+1]) || is.na(x[i+2]) || is.na(x[i+3])
                    || is.na(x[i+4])|| is.na(x[i+5])|| is.na(x[i+6])|| is.na(x[i+7])))
              {
                value2ins=((x[i]+x[i+1]+x[i+2]+x[i+3])/(x[i+4]+x[i+5]+x[i+6]+x[i+7]))^0.25 
                break 
              }
              i=i+1 
            }
          }
          for (idx in ((NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x)):1))
            outF[idx]=value2ins*outF[idx+1] 
        }
        
        if (EXTMODE=='GROWTH') 
        {
          #look code for description :)								
          i=1 
          while(i<=(length(x)-1))
          { 
            #if internal missing then stop...
            if (!(is.na(x[i])) && is.na(x[i+1])) break 
            if (!(is.na(x[i]) || is.na(x[i+1]) ))
            {
              value2ins=((x[i])/(x[i+1])) 
              break 
            }
            i=i+1 
          }
          
          for (idx in ((NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x)):1))
            outF[idx]=value2ins*outF[idx+1] 
        }
        
        if (EXTMODE=='MYRATE') 
        {
          suppressWarnings({
            tmpF=as.numeric(FACTOR) 
          }) 
          for (idx in ((NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x)):1))
            outF[idx]=tmpF*outF[idx+1] 
        }
        
        if (EXTMODE=='LINEAR') 
        {
          value2ins=NA 
          if (length(x)>1)
          {
            #look code for description :)								
            i=1 
            while(i<=(length(x)-1))
            { 
              #if internal missing then stop...
              if (!(is.na(x[i])) && is.na(x[i+1])) break 
              if (!(is.na(x[i]) || is.na(x[i+1]) ))
              {
                value2ins=((x[i])-(x[i+1])) 
                break 
              }
              i=i+1 
            }
          }
          for (idx in ((NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x)):1))
            outF[idx]=value2ins+outF[idx+1] 
        }
        
        if (EXTMODE=='QUADRATIC') 
        {
          value2ins2=NA 
          value2ins=NA 
          if (length(x)>2)
          {     
            #look code for description :)								
            i=1 
            #if internal missing then stop...
            if (!(is.na(x[i])) && is.na(x[i+1])) {} else
              while(i<=(length(x)-2))
              { 
                if (!(is.na(x[i]) || is.na(x[i+1]) || is.na(x[i+2]) ))
                {
                  value2ins=((x[i]-2*x[i+1]+x[i+2])/2) 
                  value2ins2=((3*x[i]-4*x[i+1]+x[i+2])/2) 
                  break 
                }
                i=i+1 
              }
          }
          
          tempIdx=(NUMPERIOD(BACKTO,start(x),frequency(x))+.numberOfStartingMissing(x))+1 
          for (idx in ((tempIdx-1):1))
            outF[idx]=outF[tempIdx]+(value2ins2+value2ins*(tempIdx-idx))*(tempIdx-idx) 
        }
      }
    
    #UPTO not null and after  end(x)			
    if (! is.null(UPTO))
      if (.isMinorPeriodYP(end(x), UPTO,frequency(x))) 
      {
        #default value to insert in extension
        value2ins=NA 
        value2ins2=NA 
        #fix tsp before window
        outF=.fixTsp(outF)
        
        #TSEXTEND range
        tryCatch({outF=window(outF,end=UPTO,extend=TRUE) },error=function(e){cat('TSEXTEND():',e$message) }) 
        if (EXTMODE=='MISSING') 
        {
          value2ins=NA 
          outF[length(outF)-(0:(NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)))]=value2ins 
        }
        if (EXTMODE=='ZERO') 
        {
          value2ins=0 
          outF[length(outF)-(0:(NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)))]=value2ins 
        }
        
        if (EXTMODE=='CONSTANT') 
        {
          #select last non.missing value		
          i=length(x) 
          value2ins=x[i] 
          while(i>0 && is.na(value2ins))
          { value2ins=x[i] 
          i=i-1 
          }	
          
          outF[length(outF)-(0:(NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)))]=value2ins 
        }
        
        if (EXTMODE=='MYCONST') 
        {
          #as.numeric warns if non numeric input
          suppressWarnings({
            tmpF=as.numeric(FACTOR) 
          }) 
          outF[length(outF)-(0:(NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)))]=tmpF 
        }
        
        if (EXTMODE=='MEAN4') 
        {
          value2ins=NA 
          if (length(x)>3)
          {
            #mean of last 4 consecutive non.missing value	()								
            i=1 
            #if internal missing then stop...
            if (!(is.na(x[length(x)+1-i])) && is.na(x[length(x)+1-(i+1)])) {} else
              while(i<=(length(x)-3))
              { 
                if (!(is.na(x[length(x)+1-i]) || is.na(x[length(x)+1-(i+1)]) || is.na(x[length(x)+1-(i+2)]) || is.na(x[length(x)+1-(i+3)])))
                {
                  value2ins=mean(c(x[length(x)+1-i],x[length(x)+1-(i+1)],x[length(x)+1-(i+2)],x[length(x)+1-(i+3)])) 
                  break 
                }
                i=i+1 
              }
          }
          
          outF[length(outF)-(0:(NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)))]=value2ins 
        }
        
        if (EXTMODE=='GROWTH4') 
        {
          value2ins=NA 
          if (length(x)>7)
          {
            #look code for description :)							
            i=1 
            #if internal missing then stop...
            if (!(is.na(x[length(x)+1-i])) && is.na(x[length(x)+1-(i+1)])) {} else
              while(i<=(length(x)-7))
              { 
                if (!(is.na(x[length(x)+1-(i)]) || is.na(x[length(x)+1-(i+1)]) || is.na(x[length(x)+1-(i+2)])|| is.na(x[length(x)+1-(i+3)])
                      || is.na(x[length(x)+1-(i+4)])|| is.na(x[length(x)+1-(i+5)])|| is.na(x[length(x)+1-(i+6)])|| is.na(x[length(x)+1-(i+7)])))
                {
                  value2ins=((x[length(x)+1-(i)]+x[length(x)+1-(i+1)]+x[length(x)+1-(i+2)]+x[length(x)+1-(i+3)])/(x[length(x)+1-(i+4)]+x[length(x)+1-(i+5)]+x[length(x)+1-(i+6)]+x[length(x)+1-(i+7)]))^0.25 
                  break 
                }
                i=i+1 
              }
          }
          
          for (idx in (length(outF)-((NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)):0)))
            outF[idx]=value2ins*outF[idx-1] 
        }
        
        if (EXTMODE=='GROWTH') 
        {
          i=1 
          #if internal missing sthen top...
          if (!(is.na(x[length(x)+1-i])) && is.na(x[length(x)+1-(i+1)])) {}
          while(i<=(length(x)-1))
          { 
            if (!(is.na(x[length(x)+1-(i)]) || is.na(x[length(x)+1-(i+1)]) ))
            {
              value2ins=(x[length(x)+1-(i)]/(x[length(x)+1-(i+1)])) 
              break 
            }
            i=i+1 
          }
          
          for (idx in (length(outF)-((NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)):0)))
            outF[idx]=value2ins*outF[idx-1] 
        }
        
        if (EXTMODE=='MYRATE') 
        {
          suppressWarnings({
            tmpF=as.numeric(FACTOR) 
          }) 
          for (idx in (length(outF)-((NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)):0)))
            outF[idx]=tmpF*outF[idx-1] 
        }
        
        if (EXTMODE=='LINEAR') 
        {
          value2ins=NA 
          if (length(x)>1)
          {
            #look code for description :)							
            i=1 
            #if internal missing then stop...
            if (!(is.na(x[length(x)+1-i])) && is.na(x[length(x)+1-(i+1)])) {}
            while(i<=(length(x)-1))
            { 
              if (!(is.na(x[length(x)+1-(i)]) || is.na(x[length(x)+1-(i+1)]) ))
              {
                value2ins=(x[length(x)+1-(i)]-(x[length(x)+1-(i+1)])) 
                break 
              }
              i=i+1 
            }
          }
          for (idx in (length(outF)-((NUMPERIOD(end(x),UPTO,frequency(x))-1+.numberOfEndingMissing(x)):0)))
            outF[idx]=value2ins+outF[idx-1] 
        }
        
        if (EXTMODE=='QUADRATIC') 
        {
          value2ins=NA 
          value2ins2=NA 
          if (length(x)>2)
          {
            i=1 
            #if internal missing then stop...
            if (!(is.na(x[length(x)+1-i])) && is.na(x[length(x)+1-(i+1)])) {}
            while(i<=(length(x)-2))
            { 
              if (!(is.na(x[length(x)+1-(i)]) || is.na(x[length(x)+1-(i+1)]) || is.na(x[length(x)+1-(i+2)]) ))
              {
                value2ins =((x[length(x)+1-(i)]-2*x[length(x)+1-(i+1)]+x[length(x)+1-(i+2)])/2) 
                value2ins2=((3*x[length(x)+1-(i)]-4*x[length(x)+1-(i+1)]+x[length(x)+1-(i+2)])/2) 
                break 
              }
              i=i+1 
            }
          }
          tempIdx=length(outF)-(NUMPERIOD(end(x),UPTO,frequency(x))+.numberOfEndingMissing(x)) 
          for (idx in ((tempIdx+1):length(outF)))
            outF[idx]=outF[tempIdx]+(value2ins2+value2ins*(idx-tempIdx))*(idx-tempIdx) 
        }
      }
  }#end is.ts()
  
  if (is.xts(x))
  {
    return(fromTStoXTS(TSEXTEND(fromXTStoTS(x,avoidCompliance=TRUE),BACKTO=BACKTO,UPTO=UPTO,EXTMODE=EXTMODE,FACTOR=FACTOR,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

#backward compatibility
EXTEND <- TSEXTEND 

# TSINFO code ----------------------------------------

#TSINFO retrieve info on time series.
TSINFO <- function(...,MODE=NULL,avoidCompliance=FALSE)
{
  if (is.null(MODE)) stop('TSINFO(): NULL MODE') 
 
   outF=c() 
  #an input is null
  tryCatch({inputsL=list(...) },error=function(e){stop('TSINFO(): an input argument is NULL.')}) 
  #no ts
  if (length(inputsL)==0)  stop('TSINFO(): an input argument is NULL.') 
  #must return a nx2 array
  if (MODE=='START2')
  {
    outF=cbind(TSINFO(...,MODE='STARTY',avoidCompliance=avoidCompliance),TSINFO(...,MODE='STARTP',avoidCompliance=TRUE)) 
    return(outF) 
  } else if (MODE=='END2')
  {
    outF=cbind(TSINFO(...,MODE='ENDY',avoidCompliance=avoidCompliance),TSINFO(...,MODE='ENDP',avoidCompliance=TRUE)) 
    return(outF) 
  }
  
  #loop list
  for (idx in (1:length(inputsL))) 
  {
    #if inputs is ts/xts check compliance
    if (!(avoidCompliance) )
    {
      tryCatch({.isCompliant(inputsL[[idx]]) },error=function(e){stop('TSINFO(): ',e$message) }) 
    }      
    
    if (MODE=='STARTY')
    {
      outF=c(outF,start(fromXTStoTS(inputsL[[idx]],avoidCompliance=TRUE))[1]) 
    } else if (MODE=='ENDY')
    {
      outF=c(outF,end(fromXTStoTS(inputsL[[idx]]),avoidCompliance=TRUE)[1]) 
    } else if (MODE=='STARTP')
    {
      outF=c(outF,start(fromXTStoTS(inputsL[[idx]],avoidCompliance=TRUE))[2]) 
    } else if (MODE=='ENDP')
    {
      outF=c(outF,end(fromXTStoTS(inputsL[[idx]]),avoidCompliance=TRUE)[2]) 
    } else if (MODE=='START')
    { 
      tmpTS=fromXTStoTS(inputsL[[idx]],avoidCompliance=TRUE) 
      tmpSY=as.numeric(start(tmpTS)[1]) 
      tmpSP=as.numeric(start(tmpTS)[2]) 
      tmpF=as.numeric(frequency(tmpTS)) 
      outF=c(outF,tmpSY+tmpSP/tmpF) 
    } else if (MODE=='END')
    {
      tmpTS=fromXTStoTS(inputsL[[idx]],avoidCompliance=TRUE) 
      tmpEY=as.numeric(end(tmpTS)[1]) 
      tmpEP=as.numeric(end(tmpTS)[2]) 
      tmpF=as.numeric(frequency(tmpTS)) 
      outF=c(outF,tmpEY+tmpEP/tmpF) 
    } else if (MODE=='FREQ')
    { 
      if (is.ts(inputsL[[idx]]))  outF=c(outF,frequency(inputsL[[idx]])) 
      if (is.xts(inputsL[[idx]])) outF=c(outF,frequency(inputsL[[idx]])) 
    } else if (MODE=='FACTOR')
    {
      if (is.null(attr(inputsL[[idx]],'ScaleFac'))) 
      {
        outF=c(outF,0) 
      }
      else
      {
        outF=c(outF,attr(inputsL[[idx]],'ScaleFac')) 
      }
    } else if (MODE=='UNITS')
    {
      if (is.null(attr(inputsL[[idx]],'Units'))) 
      {
        outF=c(outF,'') 
      }
      else
      {
        outF=c(outF,attr(inputsL[[idx]],'Units')) 
      }
    } else if (MODE=='TITLE')
    {
      if (is.null(attr(inputsL[[idx]],'Title'))) 
      {
        outF=c(outF,'') 
      }
      else
      {
        outF=c(outF,attr(inputsL[[idx]],'Title')) 
      }
    } else if (MODE=='SOURCE')
    {
      if (is.null(attr(inputsL[[idx]],'Source'))) 
      {
        outF=c(outF,'') 
      }
      else
      {
        outF=c(outF,attr(inputsL[[idx]],'Source')) 
      }
    } else 
    {
      stop('TSINFO(): unknown MODE.') 
    }
  }
  
  return(outF) 
}

# TSJOIN code ----------------------------------------

#TSJOIN joines two time series.
TSJOIN <- function(x=NULL, y=NULL,JPRD=NULL,ALLOWGAP=FALSE,WARN=FALSE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSJOIN(): input x needs to be instance of ts() or xts() class.') 
  if (is.null(y)) stop('TSJOIN(): input y needs to be instance of ts() or xts() class.') 
  outF=y 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSJOIN(): x - ',e$message) }) 
    tryCatch({.isCompliant(y) },error=function(e){stop('TSJOIN(): y - ',e$message) }) 
  }
  
  if (is.ts(x) && is.ts(y))
  {	
    if (!(frequency(x) == frequency(y))) stop('TSJOIN(): input time series have different frequencies.') 
    if (!(is.null(JPRD)))
    {
      if (!(.isCompliantYP(JPRD,frequency(x)))) stop('TSJOIN(): uncompliant JPRD. Use JPRD=c(y,p).') 
      if (.isMinorPeriodYP(JPRD,start(y),frequency(x)) || .isMinorPeriodYP(end(y),JPRD,frequency(x))) stop('TSJOIN(): joining period out of bounds.') 
    } 
    else {
      JPRD=start(y) 
    }
    
    if (NUMPERIOD(end(x),start(y),frequency(x))>1 )
    {
      if (!(ALLOWGAP==TRUE)) stop('TSJOIN(): There is a gap between the two input time series. Use ALLOWGAP=TRUE in order to fill it with missing value.') 
      if (WARN) cat('TSJOIN(): warning, there is a gap between the two input time series that has been filled with missing values.\n') 
    }
    
    #select out ts start and end
    outFstart=NA 
    
    if (.isMinorPeriodYP(start(x),JPRD,frequency(x)))
    {
      outFstart=start(x) 
    }
    else {
      #outFstart=start(y) 
      outFstart=JPRD 
    }
    
    outFend=end(y) 
    #create out ts with missings
    outF=ts(start=outFstart,end=outFend,frequency=frequency(x)) 
    #project x on outF
    endTemp=NA 
    startTemp=NA 
    rangeTemp=NA 
    if (.isMinorPeriodYP(start(x),JPRD,frequency(x)))
    {
      if (.isMinorPeriodYP(end(x),JPRD,frequency(x)))
      {
        endTemp=length(x)-1 
      }
      else {
        endTemp=NUMPERIOD(start(x),JPRD,frequency(x))-1 
      }
      startTemp=(1+NUMPERIOD(start(outF),start(x),frequency(x)))
      rangeTemp=(startTemp:(startTemp+endTemp)) 
      outF[rangeTemp]=x[(1:(1+endTemp))] 
    }
    else {
      if (WARN) cat('TSJOIN(): warning, nothing got from the first time series. The result will be the second time series, in case plus padding.\n') 
    }
    
    #project y on outF
    startTemp=NA 
    rangeTemp=NA 
    endTemp=NA 
    startTemp=1+NUMPERIOD(start(outF),JPRD,frequency(y)) 
    endTemp=NUMPERIOD(JPRD,end(y),frequency(y)) 
    rangeTemp=(startTemp:(startTemp+endTemp)) 
    
    outF[rangeTemp]=y[((1+NUMPERIOD(start(y),JPRD,frequency(y))):length(y))] 
  }#end is.ts()
  
  else if (is.xts(x) && is.xts(y))
  {
    return(fromTStoXTS(TSJOIN(fromXTStoTS(x,avoidCompliance=TRUE),fromXTStoTS(y,avoidCompliance=TRUE),WARN=WARN,JPRD=JPRD,ALLOWGAP=ALLOWGAP,avoidCompliance=TRUE),avoidCompliance=TRUE)) 
  }
  else
  {
    stop('TSJOIN(): input time series need to be instance of the same class ts() or xts().') 
  }	
  return(outF) 
}

# TSLAG code ----------------------------------------

#TSLAG lags time series data by the specified number of time periods.
TSLAG <- function(x=NULL,L=1,avoidCompliance=FALSE,verbose=FALSE, ...)
{
  if (is.null(x)) stop('TSLAG(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(L)) stop('TSLAG(): NULL lag L.') 
  if (!(is.numeric(L) ) ) stop('TSLAG(): lag L must be an integer.') 
  if (!(L%%1==0))  stop('TSLAG(): non-integer lag L.') 
  if (is.na(verbose) || !is.logical(verbose)) stop('TSLAG(): verbose must be TRUE or FALSE.') 
  																							  
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSLAG(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<=abs(L) && verbose) cat('TSLAG(): warning, lag "L" is greater than time series time span.\n')
    outF=stats::lag(x,k=-L) 	#R stats direction inverse	
  }
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(TSLAG(fromXTStoTS(x,avoidCompliance=TRUE),L=L,avoidCompliance=TRUE,verbose=verbose),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# TSLEAD code ----------------------------------------

TSLEAD <- function(x=NULL,L=1,avoidCompliance=FALSE,verbose=FALSE,...)
{
  if (is.null(x)) stop('TSLEAD(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(L)) stop('TSLEAD(): NULL lag L.') 
  if (!(is.numeric(L) ) ) stop('TSLEAD(): lag L must be an integer.') 
  if (!(L%%1==0))  stop('TSLEAD(): non-integer lag L.') 
  if (is.na(verbose) || !is.logical(verbose)) stop('TSLEAD(): verbose must be TRUE or FALSE.') 
  
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSLEAD(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    if (length(x)<=abs(L) && verbose) cat('TSLEAD(): warning, lag "L" is greater than time series time span.\n')
    outF=stats::lag(x,k=L) 	#R stats direction inverse	
  }
  
  if (is.xts(x) )
  {
    return(fromTStoXTS(TSLEAD(fromXTStoTS(x,avoidCompliance=TRUE),L=L,avoidCompliance=TRUE,verbose=verbose),avoidCompliance=TRUE)) 
  }
  
  return(outF) 
}

# TSLOOK code ----------------------------------------

#TSLOOK retrieve info on time series
TSLOOK <- function(x=NULL,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSLOOK(): input time series needs to be instance of ts() or xts() class.') 
  outF=list() 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSLOOK(): x - ',e$message) }) 
  }
  
  tryCatch({outF[['START']]=TSINFO(x,MODE='STARTY',avoidCompliance=TRUE)},
           error=function(e){stop('TSLOOK(): cannot retrieve info on time series. - ',e$message) }) 
  outF[['STARTY']]=outF[['START']] 
  tryCatch({outF[['PRD']]=TSINFO(x,MODE='STARTP',avoidCompliance=TRUE)},
           error=function(e){stop('TSLOOK(): cannot retrieve info on time series. - ',e$message) }) 
  outF[['STARTP']]=outF[['PRD']] 
  tryCatch({outF[['ENDY']]=TSINFO(x,MODE='ENDY',avoidCompliance=TRUE)},
           error=function(e){stop('TSLOOK(): cannot retrieve info on time series. - ',e$message) }) 
  tryCatch({outF[['ENDP']]=TSINFO(x,MODE='ENDP',avoidCompliance=TRUE)},
           error=function(e){stop('TSLOOK(): cannot retrieve info on time series. - ',e$message) }) 
  tryCatch({outF[['FREQ']]=TSINFO(x,MODE='FREQ',avoidCompliance=TRUE)},
           error=function(e){stop('TSLOOK(): cannot retrieve info on time series. - ',e$message) }) 
  
  return(outF) 
  
}

# TSMERGE code ----------------------------------------

#TSMERGE merges two time series.
TSMERGE <- function(...,fun=NULL,MV=FALSE,avoidCompliance=FALSE)
{
  outF=NULL 
  
  #an input is null
  tryCatch({tsL=list(...) },error=function(e){stop('TSMERGE(): an input argument is NULL.')}) 
  if (length(tsL)==0) stop('TSMERGE(): usage: TSMERGE(ts1,ts2,..,tsN).') 
  if (! avoidCompliance ) 
  {	
    tryCatch({lapply(tsL,.isCompliant) },error=function(e){stop('TSMERGE(): ',e$message) }) 
  }
  
  #all inputs are ts()
  if (all(as.logical(lapply(tsL,is.ts))))
  {	
    if (length(unique(lapply(tsL,frequency)))>1)
    {
      stop('TSMERGE(): different frequencies on input time series.') 
    }
    
    #get frequency
    fOutF=frequency(tsL[[1]]) 
    #get first starting period
    startOutF=c(9999,1) 
    for (idx in (1:length(tsL)))
    {
      if (.isMinorPeriodYP(start(tsL[[idx]]),startOutF,f=fOutF)) startOutF=start(tsL[[idx]]) 
    }
    
    #get last ending period
    endOutF=c(0,1) 
    for (idx in (1:length(tsL)))
    {
      if (.isMinorPeriodYP(endOutF,end(tsL[[idx]]),f=fOutF)) endOutF=end(tsL[[idx]]) 
    }
    
    #create empty out time series
    outF=ts(start=startOutF,end=endOutF,frequency=fOutF) 
    for (idx in (1:length(outF)))
    {
      #...keep # of non missing columns (...used in fun == SUM AVE etc)			
      activeColumns=0 
      #true if observation has been initialized
      initializedValue=FALSE 
      for (idxL in (1:length(tsL)))
      { 
        #periods between start of out time series and start of input time series
        deltaStart=NUMPERIOD(start(outF),start(tsL[[idxL]]),fOutF) 
        deltaEnd=NUMPERIOD(start(outF),end(tsL[[idxL]]),fOutF) 
        #...can project values
        if ((idx-deltaStart>=1) && (1+deltaEnd-idx>=0))
        { 
          #input column value is valid
          if (MV==TRUE || !(is.na(tsL[[idxL]][(idx-deltaStart)]))) 
          {
            activeColumns=activeColumns+1 
            if (is.null(fun))
            {
              outF[idx]=tsL[[idxL]][(idx-deltaStart)] 
              #we get first value then exit cycle
              break 
            }
            
            else if (fun=='AVE')
            {	
              #set temp sum to 0 if first is na
              if (initializedValue==FALSE  ) {tmpS=0 }
              else {tmpS=outF[idx] }
              
              #moving ave
              outF[idx]=((activeColumns-1)*(tmpS)/activeColumns)+tsL[[idxL]][(idx-deltaStart)]/activeColumns 
              initializedValue=TRUE 
            }
            
            else if (fun=='SUM')
            {	
              #set temp sum to 0 if first is na
              if (initializedValue==FALSE  ) {tmpS=0 }
              else {tmpS=outF[idx] }
              
              #moving sum
              outF[idx]=tmpS+tsL[[idxL]][(idx-deltaStart)] 
              initializedValue=TRUE 
            }
            
            else if (fun=='MAX')
            {	
              #set temp sum to 0 if first is na
              if (initializedValue==FALSE  ) 			  			
              {
                outF[idx]=tsL[[idxL]][(idx-deltaStart)] 
                initializedValue=TRUE 
              }
              else 
              {
                outF[idx]=max(outF[idx],tsL[[idxL]][(idx-deltaStart)]) 
              }
            }
            
            else if (fun=='MIN')
            {	
              #set temp sum to 0 if first is na
              if (initializedValue==FALSE  ) 			  			
              {
                outF[idx]=tsL[[idxL]][(idx-deltaStart)] 
                initializedValue=TRUE 
              }
              else 
              {
                outF[idx]=min(outF[idx],tsL[[idxL]][(idx-deltaStart)]) 
              }
            }
            
            else stop('TSMERGE(): unknown merge function (fun) type') 
          }
          #input column value is na
          else
          {
            if (MV==TRUE)
            {
              outF[idx]=NA 
            }
          }
        }
        #missing wont be ignored
        else if (MV==TRUE)
        {
          outF[idx]=NA 
          break 
        }
      }
    }
  }#end is.ts()
  
  #all inputs are xts()
  else if (all(as.logical(lapply(tsL,is.xts))))
  {
    return(fromTStoXTS(do.call(TSMERGE,as.list(c(lapply(tsL,fromXTStoTS,avoidCompliance=TRUE),fun=fun,MV=MV,avoidCompliance=TRUE))),avoidCompliance=TRUE)) 
  }
  else
  {
    stop('TSMERGE(): input time series need to be instance of the same class ts() or xts().') 
  }	
  
  return(outF) 
}

# TSPROJECT code ----------------------------------------

#TSPROJECT projects time series into a time interval.
TSPROJECT <- function(x=NULL,TSRANGE=NULL,ARRAY=FALSE,EXTEND=FALSE,avoidCompliance=FALSE,...)
{ 
  if (is.null(x)) stop('TSPROJECT(): input time series needs to be instance of ts() or xts() class.') 
  if (is.null(ARRAY)) stop('TSPROJECT(): ARRAY must be boolean.') 
  if (is.null(TSRANGE)) stop('TSPROJECT(): NULL TSRANGE.') 
  if (length(TSRANGE)==0 && is.na(TSRANGE)) stop('TSPROJECT(): NULL TSRANGE.') 
  if (!(is.numeric(TSRANGE))) stop('TSPROJECT(): syntax error in TSRANGE.') 
  if (!(length(TSRANGE)==4)) stop('TSPROJECT(): syntax error in TSRANGE.') 
  outF=x 
  if (! avoidCompliance ) 
  {
    tryCatch({.isCompliant(x) },error=function(e){stop('TSPROJECT(): x - ',e$message) }) 
  }
  
  if (is.ts(x) )
  {			
    #get frequency
    localF=frequency(x) 
    #check TSRANGE
    tryCatch({
      normalStart=normalizeYP(c(TSRANGE[1],TSRANGE[2]),localF) 
      normalEnd=normalizeYP(c(TSRANGE[3],TSRANGE[4]),localF) 
    },error=function(e){stop('TSPROJECT(): TSRANGE misformed.') }) 
    #fix tsp before window()
    x=.fixTsp(x)
    
    suppressWarnings({
      tryCatch({
        
        if (ARRAY)
        {
          return(coredata(window(x,start=normalStart,end=normalEnd,extend=EXTEND))) 
        } else
        {
          outF=window(x,start=normalStart,end=normalEnd,extend=EXTEND) 
        }
        
      },error=function(e){stop('TSPROJECT(): TSRANGE and input time series do not overlap.') }) 
    }) 
    return(outF) 
  }
  
  else if (is.xts(x) )
  {
    if (ARRAY)
    {
      return(TSPROJECT(fromXTStoTS(x,avoidCompliance=TRUE), TSRANGE=TSRANGE, ARRAY=ARRAY, EXTEND=EXTEND, avoidCompliance=TRUE)) 
    } else
    {
      return(fromTStoXTS(TSPROJECT(fromXTStoTS(x,avoidCompliance=TRUE), TSRANGE=TSRANGE, ARRAY=ARRAY, EXTEND=EXTEND, avoidCompliance=TRUE), avoidCompliance=TRUE)) 
    }
  }
  
  else stop('TSPROJECT(): input time series needs to be instance of ts() or xts() class.') 
  
  return(outF) 
}

# TSTRIM code ----------------------------------------

#TSTRIM trims trailing or leading selected values
TSTRIM <- function(x=NULL,VALUE=NA,TRAIL=TRUE,LEAD=TRUE,avoidCompliance=FALSE,...)
{
  if (is.null(x)) stop('TSTRIM(): input needs to be instance of c(), ts() or xts() class.') 
  outF=x 
  if (length(outF)==0) return(outF)
  
  #get values
  inData=coredata(outF) 
  #deal with all trimed series
  if (
    (is.na(VALUE)  && all(is.na(inData))) ||
    (!is.na(VALUE) && all(inData==VALUE))
  ) 
  { 
    cat(paste0('TSTRIM(): warning, all values have been trimmed out. Result will be NULL.\n')) 
    return(NULL) 
  }
  
  newStart=1 
  newEnd=length(inData) 
  if (is.na(VALUE))
  {
    #get indexes to be kept
    tmpA=which(! is.na(inData)) 
    if (length(tmpA)>0)
    {
      #change bounds
      if (TRAIL) newStart=tmpA[1] 
      if (LEAD) newEnd=tmpA[length(tmpA)] 
    }
    
  } else {
    #get indexes to be kept
    tmpA=which((! (inData==VALUE)) | is.na(inData)) 
    if (length(tmpA)>0)
    {
      #change bounds
      if (TRAIL) newStart=tmpA[1] 
      if (LEAD) newEnd=tmpA[length(tmpA)] 
    }
  }
  
  if (is.ts(outF) )
  {
    if (! avoidCompliance ) 
    {
      tryCatch({.isCompliant(outF) },error=function(e){stop('TSTRIM():',e$message) }) 
    }
    
    return(TSERIES(outF[newStart:newEnd],
                   START=normalizeYP(
                     c(start(outF)[1],start(outF)[2]-1+newStart),
                     frequency(outF)),
                   FREQ=frequency(outF)))
    
  } else if (is.xts(outF))
  {
    return(fromTStoXTS(
      TSTRIM(
        fromXTStoTS(outF,avoidCompliance=avoidCompliance)
        ,VALUE=VALUE
        ,TRAIL=TRAIL
        ,LEAD=LEAD
        ,avoidCompliance=TRUE)
      ,avoidCompliance=TRUE))
    
  } else
  {
    return(outF[newStart:newEnd])
  }
}

# VERIFY_MAGNITUDE code -------------------------------------------------------------------------

VERIFY_MAGNITUDE <- function(x=list(),magnitude=10e-7,verbose=TRUE,...)
{
  #check args
  if (! is.list(x)) stop('VERIFY_MAGNITUDE(): "x" must be a list of time series.')
  if (! is.logical(verbose) || is.na(verbose)) stop('VERIFY_MAGNITUDE(): "verbose" must be TRUE or FALSE.')
  if (length(x)==0) stop('VERIFY_MAGNITUDE(): "x" is an empty list.')
  
  #check list of time series
  isTimeSeries=unlist(lapply(x,function(x) is.ts(x) || is.xts(x)))
  if (! all(isTimeSeries))
  {
    stop('VERIFY_MAGNITUDE(): "x" must be a time series list of class ts() or xts(). Objects related to the following list indices are not time series: ',
         paste(which(! isTimeSeries),collapse=', '))
  }
  
  if (is.null(magnitude) || ! is.finite(magnitude) || magnitude <0)
    stop('VERIFY_MAGNITUDE(): "magnitude" must be a positive number.')
  
  outF=c()
  
  
  tmpOut=which(unlist(lapply(x,function(x) any(is.na(x)))))
  
  if (length(tmpOut)>0)
    for (idx in 1:length(tmpOut))
    {
      if (verbose) cat(paste0('VERIFY_MAGNITUDE(): warning, the time series in list position #',
                              tmpOut[idx],ifelse(! is.null(names(x)[tmpOut[idx]]),paste0(' with name "',names(x)[tmpOut[idx]],'"'),''),
                              ' has missing values. Missing values will be discarded.\n'))
    }
  
  #output calc
  outF=which(unlist(lapply(x, function(x) sqrt(sum(x^2,na.rm=TRUE))>magnitude)))
  
  if (length(outF) > 0 && verbose)
  {
    for (idx in 1:length(outF))
    {
      cat(paste0('VERIFY_MAGNITUDE(): the time series in list position #',
                 outF[idx],ifelse(! is.null(names(x)[outF[idx]]),paste0(' with name "',names(x)[outF[idx]],'"'),''),
                 ' has significative values.\n'))
    }
  }
  
  return(outF)
  
}

Try the bimets package in your browser

Any scripts or data that you put into this service are public.

bimets documentation built on April 4, 2025, 5:15 a.m.