// values for lazy loading
let lazyInitialScrollY = window.scrollY;
let lazyLoadPxValue = 100; // px
let lazyLoadTriggered = true;
console.log('LAZY LOAD: ',lazyLoadTriggered,'Lazy loading initialized with lazyInitialScrollY:', lazyInitialScrollY, 'and lazyLoadPxValue:', lazyLoadPxValue);




function scrollsequenceMainFunction() {
if (document.getElementsByClassName('scrollsequence-wrap')[0]) {
"use strict";   
/**
* --------------------------------------------------------- PHASE 1 -----------------------------------------------------------------
* ------------------------------------ SELF EXECUTED INIT (RUNS ONLY ONCE IN A DEFINED SEQUENCE) ------------------------------------
*/
/**
* Define Initial Variables
*/ 
  let SHOWMARKERS =ssqInput.debug.includes('markers');   
  let DEBUG = ssqInput.debug.includes('debug');   
  let PRELOADDEBUG = ssqInput.debug.includes('preloaddebug');
  //let SCROLLDEBUG = ssqInput.debug.includes('scrolldebug'); 
  let ssqCalc,ssqImg;  
  let ssqCur={};  
  let ssqInit={};
  let ssqHtml=[];

  //Manual debug override (optional)
    // SHOWMARKERS=true;
    // DEBUG = true; 
    // PRELOADDEBUG = true;
    // SCROLLDEBUG = true;
/**
* SsqInput object length
*/ 
  ssqInput.scLength=ssqInput.sc.length;
  DEBUG && console.log('0.00 ms ssqInput:',ssqInput);
/**
* INIT ssqCur object 
*/
function initSsqCur(){
  ssqCur.lastPImgRenderedOnSc=[];
  ssqCur.logObj={
    renderSuccess:[], 
    renderRestrict:[],
  }
  for (let s = 0; s < ssqInput.scLength; s++) { 
    ssqCur.lastPImgRenderedOnSc[s]=[];
  } 
}initSsqCur();
/** 
* INIT ssqHtml object 
* ssqHtml object serves mainly so we have a way how to easily identify an element in a logical way. 
* It is populated only once at page load and it is not re-loaded if there is any DOM change or reflow. 
*/
function initSsqHtml(){ let t0 = performance.now();
  let allScEl=document.getElementsByClassName('scrollsequence-wrap');
  for (let s = 0; s < ssqInput.scLength; s++) { 
    ssqHtml[s]={
      wrap:allScEl[s],
      sticky:allScEl[s].getElementsByClassName('scrollsequence-sticky')[0],
      canvas:allScEl[s].getElementsByClassName('scrollsequence-canvas')[0],  
      //trigger:allScEl[s].getElementsByClassName('scrollsequence-trigger')[0],  // Delete???????????
      ssqalert:document.getElementById("ssqalert"),
      //pagesWrap:allScEl[s].getElementsByClassName('scrollsequence-pages-wrap')[0],  // Delete???????????
      //spacer:allScEl[s].getElementsByClassName('scrollsequence-spacer')[0],  // removed 1.3.0
    };
    ssqHtml[s].page=[];
    ssqHtml[s].pageLen=allScEl[s].getElementsByClassName('scrollsequence-page').length;
    for (let i = 0; i < ssqHtml[s].pageLen; i++) { 
      ssqHtml[s].page[i]=allScEl[s].getElementsByClassName('scrollsequence-page')[i];
      ssqHtml[s].page[i].curentImageNo=0;
    }// End of i for loop 
  }// End of s for loop  
  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  DEBUG&&console.log(tdelta,'ms ssqHtml: ',ssqHtml);  
}initSsqHtml(); 
/**
* INIT ssqCanvas 
*/ 
function initSsqCanvas(){ let t0 = performance.now();
  for (let s = 0; s < ssqInput.scLength; s++) { 
    ssqHtml[s].canvas.style.zIndex=ssqInput.sc[s].zIndex;   
    ssqHtml[s].canvas.style.opacity=ssqInput.sc[s].imageOpacity;  
    ssqHtml[s].context=ssqHtml[s].canvas.getContext("2d")
    // CanvasDPR
    ssqHtml[s].canvas.aaaDPR = (ssqInput.sc[s].canvasDPR === 'quality') ? window.devicePixelRatio : 1
    //console.log('ssqHtml[s].canvas.aaaDPR:',ssqHtml[s].canvas.aaaDPR,'  (ssqInput.sc[s].canvasDPR:',ssqInput.sc[s].canvasDPR,')')

    // Optional (below is only for pre-draw loading screen): 
        // // Height and Width
        //   var canvasWidth = document.getElementsByClassName('scrollsequence-pages-wrap')[s].offsetWidth*1;
        //   var canvasHeight = document.getElementsByClassName('scrollsequence-pages-wrap')[s].offsetHeight*1;
        //   // CSS - Canvas pixel dimensions on screen (=size)
        //   ssqHtml[s].canvas.style.width = (canvasWidth*1)+"px";       
        //   ssqHtml[s].canvas.style.height =  (canvasHeight*1)+"px"; 
        //   // CANVAS - How many pixels the canvas has (=quality)
        //   ssqHtml[s].context.canvas.width = canvasWidth*1;
        //   ssqHtml[s].context.canvas.height = canvasHeight*1;
        // // Draw Something nice  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //     ssqHtml[s].context.font = "20px Poppins";
        //     ssqHtml[s].context.textAlign = "center";
        //     ssqHtml[s].context.fillText("LOADING", canvasWidth/2, canvasHeight/2-20);
        //     ssqHtml[s].context.fillText("PLEASE WAIT", canvasWidth/2, canvasHeight/2+20);

  }
  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  DEBUG && console.log(tdelta,'ms Canvas Init: ');
}initSsqCanvas(); 
/**
* INIT ssqImg
*/ 
function initSsqImg(){ let t0 = performance.now();
  ssqImg =  {
    objArray:[], 
    absoluteOrder:[], 
    totalImageNo:0,
    priorityImagesPreloadedCount:0,
    nonPriorityImagesPreloadedCount:0,
    priorityLoadingFinished:false,
    nonPriorityLoadingFinished:false, 
    zfirstDrawCalled:false, 
  };
  let absCountImg = 0;    
  for (let s = 0; s < ssqInput.scLength; s++) { 
      ssqImg.objArray[s]=[];
      for (let i = 0; i <  ssqInput.sc[s].pageLength; i++) {  
              ssqImg.totalImageNo=ssqImg.totalImageNo+ssqInput.sc[s].page[i].imagesLength // calculate total image length
              ssqImg.objArray[s][i] = [];  // prepare empty array for each page               
              for (let j = 0; j < ssqInput.sc[s].page[i].imagesLength; j++) { // Loop through images 
                  ssqImg.objArray[s][i][j] = new Image(); // Create a new image  object 
                  ssqImg.absoluteOrder[absCountImg]=[s,i,j]; // Calculate absolute image order
                  absCountImg = absCountImg + 1
              } // End of j loop 
      }  // End of i loop 
  }// End of s loop 
  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  DEBUG && console.log(tdelta,'ms ssqImg: ',ssqImg);
}initSsqImg(); 
/**
* --------------------------------------------------------- PHASE 2 -----------------------------------------------------------------
* ------------------------------------ NOT SELF  EXECUTED   PHASE 2 -------------- FUNCTIONS ----------------------------------------
*/
/**
* SsqCalculate function (sc: begin end, page:absbegin abs end)
*/ 
function ssqCalcCalculate(){let t0 = performance.now();
  ssqCalc={}
  ssqCalc.sc=[]
    for (let s = 0; s < ssqInput.scLength; s++) {   
      ssqCalc.sc[s]={}
      ssqCalc.sc[s].absBegin=document.getElementsByClassName('scrollsequence-wrap')[s].getBoundingClientRect().top+document.documentElement.scrollTop
      ssqCalc.sc[s].absEnd=ssqCalc.sc[s].absBegin+ssqInput.sc[s].scSpacer
      // Distance from the left - for future use 
        ssqCalc.sc[s].leftDistance=document.getElementsByClassName('scrollsequence-wrap')[s].getBoundingClientRect().left+document.documentElement.scrollLeft;      
      ssqCalc.sc[s].page=[]
      for (let i = 0; i <  ssqInput.sc[s].pageLength; i++) { 
        ssqCalc.sc[s].page[i]={}
        ssqCalc.sc[s].page[i].absBegin=ssqCalc.sc[s].absBegin+ssqInput.sc[s].page[i].pageAbsBegin;
        ssqCalc.sc[s].page[i].absEnd=ssqCalc.sc[s].absBegin+ssqInput.sc[s].page[i].pageAbsEnd;
      }
    }
 let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  DEBUG && console.log(tdelta,'ms ssqCalc:',ssqCalc)
} // End of ssqCalcCalculate
/**
* ssqCur Object Calculate
*   - Needs to run in init
*   - ssqCur object is supposed to capture the "curent" state of display of the Scrollsequence(s). 
* When not active isActive = false and all other values are undefined
*/
function ssqCurCalculate(scroll_pos){ let t0 = performance.now();
  // reset isActive value
    ssqCur.isActive=false
  // Check if scroll_pos has active scrollsequence
  for (let s = 0; s < ssqInput.scLength; s++) { 
    if (scroll_pos>= ssqCalc.sc[s].absBegin && scroll_pos<ssqCalc.sc[s].absEnd){
      ssqCur.isActive=true
      ssqCur.sc=s
      for (let i = 0; i <  ssqInput.sc[s].pageLength; i++) {
        if (scroll_pos>= ssqCalc.sc[s].page[i].absBegin && scroll_pos<ssqCalc.sc[s].page[i].absEnd){
            ssqCur.page=i              
            ssqCur.pageProgress= (scroll_pos-ssqCalc.sc[s].page[i].absBegin)/(ssqInput.sc[s].page[i].pageSpacer)
            ssqCur.image=Math.round(ssqCur.pageProgress*(ssqInput.sc[s].page[i].imagesLength-1))
            ssqCur.pixel=scroll_pos;
            //console.log(ssqCur.pixel,' px - ACTIVE ACTIVE ACTIVE  Scrollsequence is active:',ssqCur.isActive,ssqCur.sc,ssqCur.page,ssqCur.image,'prog:',ssqCur.pageProgress, ssqCur.pixel  )
        break
        } // end of IF (i)
      } //end of i loop
    break
    } // End of IF s
  } // end of s loop

  // IF NOT ACTIVE:  
  if (!ssqCur.isActive){ 
    ssqCur.isActive=false;
    ssqCur.sc;
    ssqCur.page;
    ssqCur.pageProgress;      
    ssqCur.image;
    ssqCur.pixel=scroll_pos;
    //console.log(ssqCur.pixel,' px - NOT ACTIVE - NOT NOT NOT:',ssqCur.isActive,ssqCur.sc,ssqCur.page,ssqCur.image,'prog:',ssqCur.pageProgress, ssqCur.pixel  )
  }// end of NOT active  
  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  ( DEBUG && !SHOWMARKERS ) && console.log(tdelta,'ms ssqCur(',scroll_pos,'):', ssqCur); 
} // End of ssqCurCalculate
/**  
* ssqInit - Calculate curent or nearest absolute image 
* Used by: Image Preload Functions 
*/   
function ssqInitCalculate(){let t0 = performance.now();
  // just FYI
  ssqInit.aascr=window.scrollY;
  //Get the latest Cur values and store them separately
    ssqInit.active={}
    ssqInit.active.sc=ssqCur.sc; 
    ssqInit.active.page=ssqCur.page; 
    ssqInit.active.pageProgress=ssqCur.pageProgress;
    ssqInit.active.image=ssqCur.image;
    ssqInit.active.pixel=ssqCur.pixel;
    ssqInit.active.isActive=ssqCur.isActive;    
  // IF ACTIVE  Scrollsequence 
    if (ssqInit.active.isActive){ 
      ssqInit.active.curAbsImg=ssqUtilsConvToAbs(ssqInit.active.sc,ssqInit.active.page, ssqInit.active.image);
    } 
  // Get all NOT ACTIVE Scrollsequence & Look for nearest
    ssqInit.notActive=[];
    for (let s = 0; s < ssqInput.scLength; s++) { 
       // look for nearest begining (aka NEXT)
      if (window.scrollY < ssqCalc.sc[s].absBegin){
        ssqInit.notActive.push({
          type:'next',
          distance:Math.abs(window.scrollY - ssqCalc.sc[s].absBegin),
          sc:s, 
          page:0, 
          image:0, 
          pageProgress:0,
        });
      }
      // look for nearest end (aka PREV sc)
      if (window.scrollY > ssqCalc.sc[s].absEnd){
         ssqInit.notActive.push({
          type: 'prev',
          distance:Math.abs(window.scrollY - ssqCalc.sc[s].absEnd),
          sc:s,
          page:ssqInput.sc[s].pageLength-1, 
          image: ssqInput.sc[s].page[ssqInput.sc[s].pageLength-1].imagesLength-1,
          pageProgress:1,
        });
      }        
    } // end of s loop
  // find the smallest distance in the array and assign it as 
    let notActiveDistanceArray=[];
    for (let x = 0; x < ssqInit.notActive.length; x++) { 
      notActiveDistanceArray[x]=ssqInit.notActive[x].distance
    }
    // sort by absolute value
    notActiveDistanceArray.sort((a,b) => a-b);
  // FINALLY assign out which one is nearest
    for (let x = 0; x < ssqInit.notActive.length; x++) { 
      if (notActiveDistanceArray[0] === ssqInit.notActive[x].distance ){
        ssqInit.notActive.nearAbsImg=ssqUtilsConvToAbs(ssqInit.notActive[x].sc, ssqInit.notActive[x].page, ssqInit.notActive[x].image)
        break
      } // end IF 
    } // end of x for loop
  // OUTPUT - To make a simple answer to "which abs image to use for preload" use variable aaaCurImg below:
    if (ssqInit.active.curAbsImg == undefined){ // if active is not present => use the nearest image
      ssqInit.aaaCurImg=ssqInit.notActive.nearAbsImg
    }else{  // if active - use cur img
      ssqInit.aaaCurImg=ssqInit.active.curAbsImg
    }
  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  DEBUG && console.log(tdelta,'ms ssqInit:',ssqInit)
}// End of ssqInitCalculate
//-------------------- IMAGE PRELOAD FUNCTIONS ----------------------- 
/**
* ssqDumbPreloadArray
*/ 
function ssqDumbPreloadArray(curImg,imageTotalLength){ let t0 = performance.now(); //cur img is absolute
  PRELOADDEBUG && console.log('INITIAL CONDITIONS: curImg:',curImg,' length:',imageTotalLength );
  // Define Variables
    var justOddArray=[];
    for (var i=0; i< (imageTotalLength)/2; i++) { 
        justOddArray[i]=i*2+1;  // red number sequence  
    }
    //PRELOADDEBUG && console.log('justOddArray',justOddArray);
  // POSITIVE SIDE   
    var blueArrayLimit=[]; 
    for (var i=0; i< (imageTotalLength-curImg)/2; i++) { 
        blueArrayLimit[i]=Math.log((imageTotalLength-curImg)/justOddArray[i])/Math.log(2);
    }   
    //PRELOADDEBUG && console.log('blueArrayLimit:',blueArrayLimit);
    var blueArray=[]
    for (var i=0; i< (imageTotalLength-curImg)/2; i++) {  // or equal results in empty array
        blueArray[i]=[] 
        for (var j=0; j< blueArrayLimit[i]; j++) { // or equal results in cur=9 for length=9
            blueArray[i][j] = Math.pow(2,[j])*justOddArray[i]+curImg;
        };
    }
    //PRELOADDEBUG && console.log('blueArray',blueArray);
    var blueArrayLinear = [];
    var blueArrayLength = blueArray.length;
    for (var i=0; i< blueArrayLength; i++) { 
        var blueArrayLengthSub=blueArray[i].length;
        for (var j=0; j< blueArrayLengthSub; j++) { 
            blueArrayLinear.push(blueArray[i][j]);
        }
    }
  // NEGATIVE SIDE 
    var pinkArrayLimit=[];
    for (var i=0; i< (curImg)/2; i++) { 
        pinkArrayLimit[i]=Math.log((curImg)/justOddArray[i])/Math.log(2);
    }   
    //PRELOADDEBUG && console.log('pinkArrayLimit:',pinkArrayLimit);          
    var pinkArray=[]
    for (var i=0; i< (curImg)/2; i++) { // or equal results in empty array
        pinkArray[i]=[] 
        for (var j=0; j<= pinkArrayLimit[i]; j++) { // if or equal is not there, zero does not get counted
            pinkArray[i][j] = -Math.pow(2,[j])*justOddArray[i]+curImg;
        };
    }   
    //PRELOADDEBUG && console.log('pinkArray',pinkArray);
    var pinkArrayLinear = []
    var pinkArrayLength = pinkArray.length;
    for (var i=0; i< pinkArrayLength; i++) { 
        var pinkArrayLengthSub=pinkArray[i].length;
        for (var j=0; j< pinkArrayLengthSub; j++) { 
            pinkArrayLinear.push(pinkArray[i][j]);
        }
    }
  // Combine Positive and negative side
    //PRELOADDEBUG && console.log('COMB:',curImg,'blueArrayLinear:',blueArrayLinear,'pinkArrayLinear:',pinkArrayLinear)
    var combinedArray=[curImg]
    var maxLengthOfBlueAndPink=Math.max(blueArrayLinear.length, pinkArrayLinear.length)
    for (var i=0; i< maxLengthOfBlueAndPink; i++) {
        //console.log('combine runs:',i)
        if (blueArrayLinear[i]!== undefined){ 
        combinedArray.push(blueArrayLinear[i])
        }
        if (pinkArrayLinear[i]!== undefined){ 
        combinedArray.push(pinkArrayLinear[i])
        }
    }
  //WRITE RESULT TO CUR OBJECT
    ssqImg.dumbPreloadOrder=combinedArray; 

  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  PRELOADDEBUG && console.log(tdelta,'ms ssqImg.dumbPreloadOrder:', ssqImg.dumbPreloadOrder) 
}// end of ssqDumbPreloadArray





function preloadPriorityAndNonPriorityImages(){let t0 = performance.now();
  // PRIORITY IMAGE ARRAY PRELOAD
  ssqImg.priorityImageArray=[] // Create array of priority images
    for (let x=0; x< ssqInit.notActive.length; x++) {
      var shc = ssqInit.notActive[x].sc;
      var str = ssqInit.notActive[x].page;
      var obr = ssqInit.notActive[x].image;
      ssqImg.priorityImageArray[x]=ssqUtilsConvToAbs(shc,str,obr);
      ssqImg.objArray[shc][str][obr].aaaaaaIsPriority=true;
      ssqImg.objArray[shc][str][obr].aaaImageInfo={sc:shc,page:str,image:obr,}; 
      ssqImg.objArray[shc][str][obr].onload =preloadImagesCallbackFunction;
      ssqImg.objArray[shc][str][obr].src =ssqInput.sc[shc].page[str].imagesFull[obr];
    } 
  // NON PRIORITY IMAGE ARRAY SUBSTRACT
  const subtractTwoArrays = (arr1, arr2) => arr1.filter( el => !arr2.includes(el) )
  ssqImg.nonPriorityImageArray=subtractTwoArrays(ssqImg.dumbPreloadOrder, ssqImg.priorityImageArray) // create array of non  priority images

  // FIX: Calculate nonPriorityImageCountRequired BEFORE slicing
  ssqImg.nonPriorityImageCountRequired =  Math.round((ssqImg.totalImageNo-ssqImg.priorityImageArray.length)*ssqInput.preloadPercentage);

  // Split non-priority images into "immediate" and "lazy"
  ssqImg.nonPriorityImmediate = ssqImg.nonPriorityImageArray.slice(0, ssqImg.nonPriorityImageCountRequired);
  ssqImg.nonPriorityLazy = ssqImg.nonPriorityImageArray.slice(ssqImg.nonPriorityImageCountRequired);

  // Load only the immediate non-priority images now
  for (var i=0; i< ssqImg.nonPriorityImmediate.length; i++) {
      var shc = ssqImg.absoluteOrder[ssqImg.nonPriorityImmediate[i]][0]
      var str = ssqImg.absoluteOrder[ssqImg.nonPriorityImmediate[i]][1] 
      var obr = ssqImg.absoluteOrder[ssqImg.nonPriorityImmediate[i]][2]  
      ssqImg.objArray[shc][str][obr].aaaaaaIsPriority=false;
      ssqImg.objArray[shc][str][obr].aaaImageInfo={sc:shc,page:str,image:obr}; 
      ssqImg.objArray[shc][str][obr].onload =preloadImagesCallbackFunction;
      ssqImg.objArray[shc][str][obr].src =ssqInput.sc[shc].page[str].imagesFull[obr];
  }

  // NEW: Set up lazy loading for the rest
  if (ssqImg.nonPriorityLazy.length > 0) {
    lazyInitialScrollY = window.scrollY;
    lazyLoadTriggered = false;
    window.addEventListener('scroll', lazyLoadNonPriorityImages, {passive: true});
  }

  let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2);  PRELOADDEBUG && console.log(tdelta,'ms preloadPriorityAndNonPriorityImages','PRIORITY:',ssqImg.priorityImageArray, 'NON-PRIORITY:',ssqImg.nonPriorityImageArray, 'NON PRIORITY REQD: ',ssqImg.nonPriorityImageCountRequired ) 
} // end of preloadPriorityAndNonPriorityImages

function preloadImagesCallbackFunction(){
  this.aaaLoaded=true;
  imageWasLoaded(this.aaaImageInfo, this.aaaaaaIsPriority)  
} // end of preloadImagesCallbackFunction


// Add this new function near the other preload functions:
function lazyLoadNonPriorityImages() {
  if (lazyLoadTriggered) return;
  if (Math.abs(window.scrollY - lazyInitialScrollY) >= lazyLoadPxValue) {
    lazyLoadTriggered = true;
    window.removeEventListener('scroll', lazyLoadNonPriorityImages, {passive: true});
    // Load the remaining non-priority images
    for (var i=0; i< ssqImg.nonPriorityLazy.length; i++) {
      var shc = ssqImg.absoluteOrder[ssqImg.nonPriorityLazy[i]][0]
      var str = ssqImg.absoluteOrder[ssqImg.nonPriorityLazy[i]][1] 
      var obr = ssqImg.absoluteOrder[ssqImg.nonPriorityLazy[i]][2]  
      ssqImg.objArray[shc][str][obr].aaaaaaIsPriority=false;
      ssqImg.objArray[shc][str][obr].aaaImageInfo={sc:shc,page:str,image:obr}; 
      ssqImg.objArray[shc][str][obr].onload =preloadImagesCallbackFunction;
      ssqImg.objArray[shc][str][obr].src =ssqInput.sc[shc].page[str].imagesFull[obr];
    }
    PRELOADDEBUG && console.log(`Lazy loaded remaining non-priority images after ${lazyLoadPxValue}px scroll`);
  }
}











/**  
* imageWasLoaded
*/ 


function imageWasLoaded(imageInfo, isPriority){
  // Count priority and non priority images
    if (isPriority){ // Count Priority Images 
      ssqImg.priorityImagesPreloadedCount = ssqImg.priorityImagesPreloadedCount+1;    
    } else {// Count non-priority Images
      ssqImg.nonPriorityImagesPreloadedCount=ssqImg.nonPriorityImagesPreloadedCount+1;
    }
  // run if all priority images are loaded 
    if (ssqImg.priorityImagesPreloadedCount >= ssqImg.priorityImageArray.length ){ PRELOADDEBUG && console.log('All priority images have been loaded. Loading non-priority now. ssqImg.nonPriorityImagesPreloadedCount:',ssqImg.nonPriorityImagesPreloadedCount,'/',ssqImg.nonPriorityImageCountRequired  )
      ssqImg.priorityLoadingFinished=true;

    } // end if priority images 
    if ( ssqImg.nonPriorityImagesPreloadedCount >= ssqImg.nonPriorityImageCountRequired ){ //console.log('IMAGE PRELOAD PERCENTAGE WAS MET ')
      ssqImg.nonPriorityLoadingFinished=true;
    } // end of preload count

    if (ssqImg.priorityLoadingFinished && ssqImg.nonPriorityLoadingFinished ){
      if(!ssqImg.zfirstDrawCalled) {
        ssqImg.zfirstDrawCalled=true;  
        PRELOADDEBUG &&  console.log('PRIORITY AND ENOUGH OF NON PRIORITY IMAGES ARE LOADED ------------- >>> RENDER SCROLLSEQUENCE ------------------------------')
        ssqFirstDraw()
        // Create and dispatch event that says that preloadPercentage has been met
          const event = document.createEvent('Event'); // Create the event.
          event.initEvent('ssqPreloadPercentage', true, true); // Define that the event name is 'ssqPreloadPercentage'.
          document.dispatchEvent(event);// target can be any Element or other EventTarget. In this case, the target is document object
      }
    }

} // end of imageWasLoaded
//-------------------- RENDER FUNCTIONS ----------------------- ARE CALLED ON SCROLL
/**
*           THIS IS USED MOSTLY IN PRO VERSION, AS FREE DEALS WITH IT DIFFERENTLY
* renderRequest(requestor) function  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Who can call this? (sorted by frequency likely to be called)
* OK  - Update of tween (sc,page,image) => check if sc/page/image has changed since last + render)
*     - Resize                          => limit to reasonable ammount (2fps?) - on mobile 
*     - Recalc                          => just run, no questions asked (not likely to fire a lot)
*     - Init                            => just run, called only few times
*     - Orientation change              => just run, no questions asked (not likely to fire a lot)
*
*   There should be a counter of requests vs renders completed with their respective requestors
*     ssqCur.logObj={
*       lastPImgRenderedOnSc:[#,#], [#,#], [#,#],                   [page,image]
*       renderSuccess:[[#,#,#],[#,#,#],[#,#,#],[#,#,#],[#,#,#]]     [sc,page,image]
*       renderRestrict:[[#,#,#],[#,#,#],[#,#,#],[#,#,#],[#,#,#]]    [sc,page,image]
*  
*      }
*
*
*/ 
function renderRequest(sc,page,image,requestor, info){
  //console.log('RENDER REQUEST:',requestor,'" [sc,page,image]:',sc,page, image );
    switch(requestor) {
      case 'tween':
        // Check if last page/image combination on SC is the same if yes = no need to re-render. Else Render.
        if(ssqCur.lastPImgRenderedOnSc[sc][0] === page && ssqCur.lastPImgRenderedOnSc[sc][1] === image){
          // OPTIONAL: save to log 
            // ssqCur.logObj.renderRestrict.push([sc,page,image,requestor]);
        } else {
          renderCanvas(sc,page,image,requestor, info)
          // OPTIONAL: save to log 
            // ssqCur.logObj.renderSuccess.push([sc,page,image,requestor]);
        }
        break;
      case 'resize':
        /**
        *
        *
        */
        //console.log('requested by resize event') 
        renderCanvas(sc,page,image,requestor, info); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
        // OPTIONAL: save to log 
          // ssqCur.logObj.renderSuccess.push([sc,page,image,requestor]);         
        break;        
      case 'initActive':
        renderCanvas(sc,page,image,requestor, info)
        // OPTIONAL: save to log 
          ssqCur.logObj.renderSuccess.push([sc,page,image,requestor]);
        break;
      case 'initNotActive':
        renderCanvas(sc,page,image,requestor, info)
        // OPTIONAL: save to log 
          ssqCur.logObj.renderSuccess.push([sc,page,image,requestor]);
        break;   
      case 'orientationChange':
        renderCanvas(sc,page,image,requestor, info)
        // OPTIONAL: save to log 
          ssqCur.logObj.renderSuccess.push([sc,page,image,requestor]);
        break;

      default:
        console.log('warning: no render requestor') // code block
    } // end of switch 
}
/**
* renderCanvas() function
*/ 
function renderCanvas(sc,page,image, requestor,info) {   // Check screen size, update canvas size (css + canvas) and render with scale and align
  DEBUG && console.log('RenderCanvas:',sc,page,image, requestor,info);
  if (ssqImg.objArray[sc][page][image].aaaLoaded){

    let canvasWidth,canvasHeight,canvasAspectRatio;

    // CanvasDPR
    let canvasDPR = ssqHtml[sc].canvas.aaaDPR

    if (ssqInput.sc[sc].forceFullWidth){
      canvasWidth =  document.documentElement.clientWidth;
      ssqHtml[sc].canvas.style.left = -document.getElementsByClassName('scrollsequence-wrap')[sc].getBoundingClientRect().left-document.documentElement.scrollLeft+"px"; 
    } else {
      canvasWidth = document.getElementsByClassName('scrollsequence-pages-wrap')[sc].offsetWidth*1;
    }
    canvasHeight = document.getElementsByClassName('scrollsequence-pages-wrap')[sc].offsetHeight*1;
    //document.getElementsByClassName("ssqalert")[0].innerHTML = 'offheight:'+canvasHeight;
    canvasAspectRatio =  canvasWidth / canvasHeight
    // CSS - Canvas pixel dimensions on screen (=size)
    ssqHtml[sc].canvas.style.width = (canvasWidth*1)+"px";       
    ssqHtml[sc].canvas.style.height =  (canvasHeight*1)+"px"; 
    // CANVAS - How many pixels the canvas has (=quality)
    ssqHtml[sc].context.canvas.width = canvasWidth*canvasDPR;
    ssqHtml[sc].context.canvas.height = canvasHeight*canvasDPR;
    //SCROLLDEBUG && console.log('renderCanvas - canvasAspectRatio:',canvasAspectRatio);  
    if (canvasAspectRatio>=1){ // Panorama aka desktop monitor
        renderScaled(sc,page,ssqImg.objArray[sc][page][image], ssqInput.sc[sc].page[page].scaleTo.desktop, ssqInput.sc[sc].page[page].alignX.desktop, ssqInput.sc[sc].page[page].alignY.desktop);
        //SCROLLDEBUG && console.log('renderScaled LANDSCAPE (DESKTOP) :', ssqInput.sc[sc].page[page].scaleTo.desktop);
    } else {  // Portrait aka mobile screen
        renderScaled(sc,page,ssqImg.objArray[sc][page][image], ssqInput.sc[sc].page[page].scaleTo.mobile, ssqInput.sc[sc].page[page].alignX.mobile, ssqInput.sc[sc].page[page].alignY.mobile);        
        //SCROLLDEBUG && console.log('renderScaled PORTRAIT (MOBILE) :', ssqInput.sc[sc].page[page].scaleTo.mobile);
    }
  } else { PRELOADDEBUG && console.log('Image [',sc,',',page,',',image,'] was not loaded in time ')}; // updated 1.3.8 so it only shows when preloaddebug
}
/**
* renderScaled(img, fitOrFill, alignX, alignY) function 
*/  
function renderScaled(sc,page,image, fitOrFill, alignX, alignY){
  var scale, x,y;
  switch (fitOrFill) {
      case "fill": //FILL
          scale = Math.max(ssqHtml[sc].canvas.width / image.width, ssqHtml[sc].canvas.height / image.height);
          break;
      case "fit": // fit 100 %
          scale = Math.min(ssqHtml[sc].canvas.width / image.width, ssqHtml[sc].canvas.height / image.height);
          break;
      default:  // fit (fitOrFill) %
          scale = Math.min(ssqHtml[sc].canvas.width / image.width, ssqHtml[sc].canvas.height / image.height)*fitOrFill;
  }
  switch (alignX) {
      case "left": // Legacy 0.9.93
          x = 0;
          break;
      case "right": // Legacy 0.9.93
          x = (ssqHtml[sc].canvas.width ) - (image.width ) * scale; 
          break;
      case "center": // Legacy 0.9.93
          x = (ssqHtml[sc].canvas.width / 2) - (image.width / 2) * scale;
          break;                  
      default:
          x = (ssqHtml[sc].canvas.width * alignX) - (image.width * alignX) * scale;
  }
  switch (alignY) {
      case "top": // Legacy 0.9.93
          y = 0;
          break;
      case "bottom": // Legacy 0.9.93
          y = (ssqHtml[sc].canvas.height ) - (image.height ) * scale;
          break;
      case "center": // Legacy 0.9.93
          y = (ssqHtml[sc].canvas.height / 2) - (image.height / 2) * scale;
          break;
      default:
          y = (ssqHtml[sc].canvas.height * alignY) - (image.height * alignY) * scale;
  }
  ssqHtml[sc].context.drawImage(image, Math.round(x), Math.round(y), Math.ceil(image.width * scale),Math.ceil(image.height * scale)); // math ceil added to avoid sub-pixel rendering
  ssqCur.lastPImgRenderedOnSc[sc]=[page,image.aaaImageInfo.image];//save last rendered values
  //SCROLLDEBUG && console.log('Rendered scale:',scale,' x:',x,' alignX:',alignX,' y:',y,' alignY:',alignY);
}
//-------------------- UTILITY FUNCTIONS -----------------------
/**
* Utility function that converts (sc,page,image) to absolute image number required by image preload function
*/ 
function ssqUtilsConvToAbs(sc,page,image){
  for (let x = 0; x < ssqImg.totalImageNo; x++) { 
    if (ssqImg.absoluteOrder[x][0] === sc && ssqImg.absoluteOrder[x][1] === page &&ssqImg.absoluteOrder[x][2] === image ){
      return x;
      break
    }
  } 
}












/**
* --------------------------------------- ROADM START ----------------------------------------------- 
* --------------------------------------- ROADM START -----------------------------------------------
* --------------------------------------- ROADM START  ----------------------------------------------- 
*/

if (SHOWMARKERS) {ssqHtml[0].ssqalert.style.display = "block"; console.log('showing markers') } // Pro only

function ssqUpdateAlert(sc,page, image){
  if (SHOWMARKERS){
    let alertText =`<b>Scrollsequence <br> ID: <a href="${ssqInput.siteUrl}/wp-admin/post.php?post=${ssqInput.sc[sc].ssqId}&action=edit" >${ssqInput.sc[sc].ssqId}</a> <br> Index: ${sc}<br> Scene: ${page}<br> Image: ${image}<br> ScrollY: ${window.scrollY}px</b>`;
    alertText += `<br>Start: ${ssqCalc.sc[sc].absBegin}px <br> End: ${ssqCalc.sc[sc].absEnd} px`
    ssqHtml[0].ssqalert.innerHTML = alertText  
  }
}




  let ticking = false;
  let timelineSc=[]; // ROADM
  let timelineScPin=[];//ROADM 1.3.0
  let timelineEl=[]; // ROADM
  
// ScrollTrigger.addEventListener("refreshInit", function() {
//     // this code will run BEFORE the refresh
//     console.log('BEFORE REFRESH');
// });
ScrollTrigger.addEventListener("refresh", function() {
    // this code will run AFTER all ScrollTriggers refreshed.
    //console.log('AFTER REFRESH');
    for (let s = 0; s < ssqInput.scLength; s++) { 
        if(timelineSc[s]){
            //console.log('timelineSc[',s,'].progress():',timelineSc[s].progress())
            if (timelineSc[s].progress()===0){
                timelineSc[s].progress(0.001)
            }
            if (timelineSc[s].progress()===1){
                timelineSc[s].progress(0.999)
            }             
        }
    }
    
});

//-------------------- TIMELINES -----------------------  
/**
*
*
*
*
*
*/
function ssqTimelines7(){let t0 = performance.now();
  gsap.registerPlugin(ScrollTrigger);
  // STEP 1 - TIMELINE DEFINITIONS 
    for (let s = 0; s < ssqInput.scLength; s++) { 
      // TimelineSc Definition
      timelineSc[s] = gsap.timeline({
        onUpdate:() => {
          if(timelineSc[s].progress()===0){
            timelineSc[s].progress(0.001);
          };
          if(timelineSc[s].progress()===1){
            timelineSc[s].progress(0.999);
          };   
          //console.log('timelineSc[',s,'] Progress:',timelineSc[s].progress());       
        },
        scrollTrigger:{ // TimelineSC Trigger
          trigger: ssqHtml[s].wrap,
          start: "top "+(1-ssqInput.sc[s].triggerStart)*100+"%", // 'element viewport' // update 1.3.0
          end:"bottom "+(1-ssqInput.sc[s].triggerEnd)*100+"%" , // 'element viewport' // update 1.3.0                 
          scrub:ssqInput.sc[s].scrub,
          markers:SHOWMARKERS,
          pin:false ,  

          preventOverlaps: true, // since 1.3.0
          fastScrollEnd: true, // since 1.3.0
          
        },
      }); 
      // TimelineScPin Definition  PIN PIN PIN PIN PIN PIN PIN since 1.3.0
      if (ssqInput.sc[s].position == 'sticky-js'){
        timelineScPin[s] = gsap.timeline({
          scrollTrigger:{ 
            trigger: ssqHtml[s].wrap,
            start: "top top", // 'element viewport' // update 1.3.0
            end:"+="+ssqInput.sc[s].scSpacer, // update late 1.3.0
            scrub:ssqInput.sc[s].scrub,
            markers:false, //SHOWMARKERS, // Markers turned off, because they are different than main ones
            pin:  ssqHtml[s].sticky ,  //true, // update 1.3.0
            pinSpacing: false,
            anticipatePin:0.5, // added 1.2.0 - trying to avoid flashing during pinning // updated 1.3.0 to 0.5

            //pinReparent:true, // This was used only in one case. 99% of themes do not need reparenting. Only used in one "trillion" websites
            //preventOverlaps: true, // since 1.3.0 - turned this off, because fast scroll messed with pinning
            //fastScrollEnd: true, // since 1.3.0 - turned this off, because fast scroll messed with pinning
            
          },
        });         
      }

      // TimelineEl Definition
      timelineEl[s]=[];
      for (let i = 0; i <  ssqInput.sc[s].pageLength; i++) {     
          timelineEl[s][i]=gsap.timeline();
          timelineSc[s].add(timelineEl[s][i], ssqInput.sc[s].page[i].pageAbsBegin);   
      }// end of i loop
    }// end of s loop

  // STEP 2 - Tweeeeeeen! 
    for (let s = 0; s < ssqInput.scLength; s++) { 
      for (let i = 0; i <  ssqInput.sc[s].pageLength; i++) {  
      if(!ssqCur.image){ssqCur.image=0;};  // since 1.0.078 - to prevent gsap error. This line was added to prevent GSAP warning message https://wordpress.org/support/topic/gsap-invalid-property-error/#post-14328432
      timelineSc[s].set(ssqHtml[s].page[i], {display: "block"},ssqInput.sc[s].page[i].pageAbsBegin ) // Turn pages ON 
      timelineSc[s].fromTo(ssqCur,
        {image:0}, 
        {
           ease: "steps("+(ssqInput.sc[s].page[i].imagesLength-1)+")",
           image: ssqInput.sc[s].page[i].imagesLength-1, // ssqCur.image tween ***
           duration:ssqInput.sc[s].page[i].pageSpacer, // px units 
          onUpdate: function () {
            renderRequest(s, i, ssqCur.image,'tween', 'TWEEN timelineSc sc:'+s+'page:'+i+'img:'+ssqCur.image+' onUpdate ________________________________');
            ssqUpdateAlert(s, i, ssqCur.image ) // since 1.3.8
          },           
        },ssqInput.sc[s].page[i].pageAbsBegin);
      timelineSc[s].set(ssqHtml[s].page[i], {display: "none"},ssqInput.sc[s].page[i].pageAbsEnd ) // Turn pages OFF 
      }// end of i loop
    }// end of s loop
  // STEP 3 - TWEEN AnimEl 
    for (let s = 0; s < ssqInput.scLength; s++) { 
      for (var i=0; i<ssqInput.sc[s].page.length; i++) {
        timelineEl[s][i].set({}, {}, ssqInput.sc[s].page[i].imagesFull.length*ssqInput.sc[s].page[i].imgDur);// Set timeline length
        gsap.set(`.ssq-wrap-${s} .scrollsequence-canvas`, {autoAlpha: 1}); //console.log(i,'setting: ', `.ssq-wrap-${s} .scrollsequence-canvas`, ) // Set .scrollsequence-canvas visibility for each sc since 1.4.2

        for (var j=0; j<ssqInput.sc[s].page[i].animEl.length; j++) {
          if (ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id !== '' && ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_start !== '' && ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_end !== ''){
            // AnimElAnimElAnimElAnimElAnimElAnimElAnimElAnimEl START 
            // IN IN IN IN IN IN IN IN IN IN IN IN IN IN IN IN  START 
              /* Differences between In and Out Blocks of code 
              *   - Replace every "in" for "out" in variable name and description
              *   - GSAP Delay is different (in: start,  out: end-duration)
              *   - If animation list is not defined (in: auto alpha 1 out: auto alpha 0)
              *   - Immediate render is only for IN. It is not present in OUT. It causes problems when reverse scroll 
              */   
            // Pre CHECKS: 
              if( ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_duration === ''){
                ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_duration = 0;
                //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,' - no IN duration - APPLY DEFAULT DURATION ');
              }
              if( ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list.length === 0){
                  ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[0] = {};
                  ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[0].ssqnce_anim_io_value = 0; // ??????????????????? WAS 1 in previous thing
                  ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[0]._type ='ssqnce_anim_io_fade';
                  //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,' - no anim IN list - APPLY DEFAULT FADE');
              }            
            // Create animaceObjekt and rename type
              var animaceObjekt={};  
            // Loop through animation list
              for(var k=0; k<ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list.length  ; k++) { // Loop PAGE[i] ELEMENT [j] Anim LIST [k]
                switch(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type) {
                  case 'ssqnce_anim_io_fade':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type='autoAlpha';
                    break;                          
                  case 'ssqnce_anim_io_x':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type='xPercent';
                    break;
                  case 'ssqnce_anim_io_y':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type='yPercent';
                    break;
                  case 'ssqnce_anim_io_scale':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type='scale';
                    break;
                  default:
                    // code block
                } // end of switch
                // Assign key value pairs
                animaceObjekt[ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k]._type]=ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_list[k].ssqnce_anim_io_value;
              } // end of "k" loop (Animation list items)
              // Assign duration
              animaceObjekt['duration']=parseInt(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_in_duration)*ssqInput.sc[s].page[i].imgDur+0.001; 
              animaceObjekt['delay']=(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_start)*ssqInput.sc[s].page[i].imgDur; 
              // CREATE TWEEN FOR EACH ELEMENT
              timelineEl[s][i].from(
                  //ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id, // SELECT AND MATCHING SELECTOR ANYWHERE IN DOCUMENT
                  ".ssq-wrap-"+s+" "+ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id, // SELECT MATCHING ID ON A PAGE - DOES NOT WORK
                  animaceObjekt, // Animation Object
                  0 //position
                  );
              //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,'animaceObjekt IN:',animaceObjekt);
              // OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT START 
              // Pre checks
                if( ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_duration === ''){
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_duration = 0 // default fade out duration
                    //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,' - no OUT duration - APPLY DEFAULT DURATION ');
                }              
                if( ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list.length === 0){
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[0] = {};
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[0].ssqnce_anim_io_value = 0; // !!!!! default fade value
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[0]._type ='ssqnce_anim_io_fade';
                    //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,' - no anim OUT list - APPLY DEFAULT FADE');
                }
              // Create animaceObjekt and rename type
              var animaceObjekt={};   
              for(var k=0; k<ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list.length  ; k++) { // Loop PAGE[i] ELEMENT [j] Anim LIST [k]
                switch(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type) {
                  case 'ssqnce_anim_io_fade':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type='autoAlpha';
                    break;                          
                  case 'ssqnce_anim_io_x':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type='xPercent'; // changed 1.1.9.
                    break;
                  case 'ssqnce_anim_io_y':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type='yPercent'; // changed 1.1.9.
                    break;
                  case 'ssqnce_anim_io_scale':
                    ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type='scale';
                    break;
                  default:
                    // code block
                } // end of switch
                // Assign key value pairs
                animaceObjekt[ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k]._type]=ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_list[k].ssqnce_anim_io_value;
              } // end of "k" loop (Animation list items)
              // Assign duration
              animaceObjekt['duration']=parseInt(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_duration)*ssqInput.sc[s].page[i].imgDur+0.001; 
                                                                                                                    // +1 is to leave it visible on the number specified (< vs <=)
              animaceObjekt['delay']= (ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_end-ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_out_duration+1)*ssqInput.sc[s].page[i].imgDur;
              // CREATE TWEEN FOR EACH ELEMENT
              timelineEl[s][i].to(
                  //ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id, // SELECT AND MATCHING SELECTOR ANYWHERE IN DOCUMENT
                  ".ssq-wrap-"+s+" "+ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id, // SELECT MATCHING ID ON A PAGE - DOES NOT WORK
                  animaceObjekt, // Animation Object
                  0   // GSAP Delay !!!!! Different for IN/OUT 
                  );  
              //console.log(ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,'animaceObjekt Out:',animaceObjekt);
            // AnimElAnimElAnimElAnimElAnimElAnimElAnimElAnimEl END
          } else { // end of if id&&start&&end 
            console.log('Scrollsequence ERROR: element ',ssqInput.sc[s].page[i].animEl[j].ssqnce_anim_io_id,' is NOT defined properly')
          } 
        }// end of j loop
      } // end of i loop
    }// end of s loop

    gsap.to('.scrollsequence-wrap', {autoAlpha:0,duration:0}); // Added 1.0.074 // Removed 1.6.0 // Added back 1.6.1


    // BELOW IS FOR INFORMATION ONLY:
    // for (let s = 0; s < ssqInput.scLength; s++) { 
    //   console.log('ssqTimelines7 timelineSc[',s,']',timelineSc[s])
    //   for (var i=0; i<ssqInput.sc[s].page.length; i++) {
    //     console.log('ssqTimelines7 timelineEl[',s,'][',i,']',timelineEl[s][i])
    //   }
    // }


 let t1 = performance.now(); let tdelta =(t1 - t0).toFixed(2); DEBUG && console.log(tdelta,'ms timelineEl:',timelineEl);    
} // end of ssqTimelines7

/**
* RESIZE EVENT
*
*
*/
let lastWindowWidth; // required for resize event checking
let lastWindowHeight; // required for resize event checking


function ssqEventReqAnimFrameFire(scroll_pos, requestor){
  //countRafFire=countRafFire+1; console.log('RAF:',countRafFire, requestor);
  switch(requestor) {
    case "resize":
        if(document.documentElement.clientWidth!==lastWindowWidth){ //console.log('WIDTH IS CHANGING ');
          lastWindowWidth=document.documentElement.clientWidth
          ssqCalcCalculate()
          ssqCurCalculate(scroll_pos) 
          ScrollTrigger.refresh()
          for (let s = 0; s < ssqInput.scLength; s++) {
            renderCanvas(s,ssqCur.lastPImgRenderedOnSc[s][0], ssqCur.lastPImgRenderedOnSc[s][1])
          }
        } else if(document.documentElement.clientHeight!==lastWindowHeight){ //console.log('HEIGHT IS CHANGING ');
          lastWindowHeight=document.documentElement.clientHeight
          //renderCanvas(0,ssqCur.page,ssqCur.image)
        }  // end of changing height
      break;
    case "orientationchange": // console.log('orientation changed')

          ssqCalcCalculate()
          ssqCurCalculate(scroll_pos) 
          ScrollTrigger.refresh()
          for (let s = 0; s < ssqInput.scLength; s++) {
            renderCanvas(s,ssqCur.lastPImgRenderedOnSc[s][0], ssqCur.lastPImgRenderedOnSc[s][1])
          }

      break;    
    default:
      console.log('ERROR REQUESTOR NOT DEFINED!')
  }  

} // end of ssqEventReqAnimFrameFire

/**
* Called by scroll, resize orientationchange
*/

function ssqEventFastFire(scroll_pos, requestor){
  //countFastFire=countFastFire+1; console.log('FAST:',countFastFire, requestor);
    if (!ticking) {
      window.requestAnimationFrame(function() {
        ssqEventReqAnimFrameFire(scroll_pos, requestor);
        ticking = false;
      });
      ticking = true;
    }
} // end of ssqEventFastFire




/**
* Initial Animation States (WORK IN PROGRESS)
*/
function ssqFirstDraw(){
  //console.log('ssqFirstDraw - START');
  ssqCalcCalculate(); // run this because it's cheap and get fresh values of  absBegin, absEnd, left etc
  ssqCurCalculate(window.scrollY); // run this because it's cheap and get fresh values of  ssqCur  

  //console.log(' BEFORE TIMELINES  BEFORE TIMELINES  BEFORE TIMELINES  BEFORE TIMELINES  BEFORE TIMELINES ')
  ssqTimelines7(); // MOVED FROM SOMEWHERE ELSE? 
  //console.log(' AFTER TIMELINES  AFTER TIMELINES  AFTER TIMELINES  AFTER TIMELINES  AFTER TIMELINES  AFTER TIMELINES ')
  // ScrollTrigger.refresh()
  




//calls myFunction() after 1 second and passes 2 parameters:
  gsap.delayedCall(.25, myDelFunction, ["param1", "param2"]);
  function myDelFunction(param1, param2) {
        gsap.to('.scrollsequence-wrap', {autoAlpha:1,duration:1.25}); // With this are two lines associated in -admin.php (script and noscript) // removed 1.0.074
        ScrollTrigger.refresh()
        // ACTIVE SC: 
          if (ssqInit.active.isActive){
            // Initial Render Canvas
            renderRequest(ssqInit.active.sc,ssqInit.active.page,ssqInit.active.image,'initActive','Initial render - Active page')
            // Initial Render Elements
            timelineSc[ssqInit.active.sc].progress(ssqInit.active.pageProgress+0.00001);
            //console.log('ssqFirstDraw - FIRST DRAW INIT ACTIVE timeline sc:',ssqInit.active.sc,'progress:',ssqInit.active.pageProgress+0.00001)
          }
        // NOT ACTIVE SC
          for (let x = 0; x < ssqInit.notActive.length; x++) { 
            // Initial Render Canvas
            renderRequest(ssqInit.notActive[x].sc,ssqInit.notActive[x].page,ssqInit.notActive[x].image, 'initNotActive', 'Initial render - Not Active page(s)')
            // Initial Render Elements
              if(ssqInit.notActive[x].type == "next" ){
                timelineSc[ssqInit.notActive[x].sc].progress(0.001);
                //console.log('ssqFirstDraw - FIRST DRAW INIT NOT ACTIVE timeline sc:',ssqInit.notActive[x].sc, 'progress: 0.002')
              } else { // prev
                timelineSc[ssqInit.notActive[x].sc].progress(0.999);
                //console.log('ssqFirstDraw - FIRST DRAW INIT NOT ACTIVE timeline sc:',ssqInit.notActive[x].sc, 'progress: 0.998')
              } // end of else
            } // end of x loop

        // Add Listeners
          // DELETE THIS IS DONE WITH TWEEN window.addEventListener("scroll", function() {ssqEventFastFire(window.scrollY,'scroll')});
          window.addEventListener("resize", function() {ssqEventFastFire(window.scrollY,'resize')});  // AKTODO 
          window.addEventListener("orientationchange", function() {ssqEventFastFire(window.scrollY,'orientationchange')});  // AKTODO 
          
        // This is for the alert to have correct values - since 1.3.8
          ssqCurCalculate(window.scrollY) 
          //console.log('alert init values: ',  ssqCur.sc ?ssqCur.sc : 0, ssqCur.page ? ssqCur.page : 0, ssqCur.image ? ssqCur.image : 0 )
          ssqUpdateAlert(           ssqCur.sc ?ssqCur.sc : 0, ssqCur.page ? ssqCur.page : 0, ssqCur.image ? ssqCur.image : 0 )        
  }

  // Few more delayed calls to refresh the scrollTrigger - @since 1.1.1
    gsap.delayedCall(1, refreshFunctionSsq);
    gsap.delayedCall(5, refreshFunctionSsq);
    gsap.delayedCall(10, refreshFunctionSsq);
    function refreshFunctionSsq(){
      const startTimeLog = Date.now()
      if ( !ScrollTrigger.isScrolling() ){ // Since 1.3.0 Only refresh if there is no scrolling or no scrub 
        ScrollTrigger.refresh();
        DEBUG && console.log('refresh :',Date.now(),'elapsed: ', Date.now()-startTimeLog,' ms' );
     
      } else {
        DEBUG && console.log('refresh delayed by 1s :',Date.now(),'elapsed: ', Date.now()-startTimeLog,' ms' );
        gsap.delayedCall(1, refreshFunctionSsq);
      }
    }


}; // End of ssqFirstDraw


// -------------------- PHASE X - FUNCTION CALL DEFINITIONS  -----------------------  
/**
* SAME AS FREE/PRO
*/
function delayedInitialExecution(){
  ssqCalcCalculate();
  ssqCurCalculate(window.scrollY)
  ssqInitCalculate();
  ssqDumbPreloadArray(ssqInit.aaaCurImg,ssqImg.totalImageNo);
  
  preloadPriorityAndNonPriorityImages() // this used to be -> dumberPreloadArray();  
  // preloadImages();  // removed 
                    /** ==> imageWasLoaded() 
                    *     => once 25%  
                    *        ==> ssqTimelines7 => multiple times randomly
                    *           ==> renderRequest 
                    *           ==> renderCanvas 
                    *           ==> renderScaled
                    *        ==> ssqFirstDraw
                    */
} delayedInitialExecution()

//window.addEventListener("load", function(){ setTimeout(delayedInitialExecution, 50); }); 






// Closing the re-run function so that it can re-run if scrollsequence-wrap is not ready yet
} else {
  setTimeout(scrollsequenceMainFunction, 100);
  console.log('"scrollsequence-wrap" container not found in DOM - trying again in 100ms')
}
}scrollsequenceMainFunction();

