library.js

// Library Scripts


//back_to_start_10_js

j.timeout = setTimeout(j.reset,10000);
j.query("body").on("click",()=>j.cancelTimeout());


//back_to_start_5_js

j.timeout = setTimeout(j.reset,5000);
j.query("body").on("click",()=>j.cancelTimeout());


//base_site_ext_fullscreen.js

/*@AFTER*/
if (screenfull.isEnabled)
{
    await j.addHeaderHtml(`<i class="fas fa-expand" style="color: #3c3c3b;font-size: xx-large;"></i>`,'fullScreenBtn',true);
    j.query("#fullScreenBtn").on('click',() =>
    {
        if(screenfull.isFullscreen)
            screenfull.exit();
        else screenfull.request();
    });
}


//base_site_js

if(j.query("#backButton")) j.query("#backButton").on('click', () =>
{
	// if temp_data exists (running process) and the current page is not one of the listed ones
  	if(Object.keys(j.app.temp_data).length>0 && !(["main_menu","error_page","contact_search","youre_in_page","youre_in_logistics_page","youre_out_page","youre_in_group_page","access_denied_page"].includes(j.app.state.current_page)))
    {
		j.confirmationModal("{$are_you_sure}",() => j.app.next("main_menu",{},"home_button_clicked"));
    }
  	else j.app.next("main_menu",{},"home_button_clicked");
});
j.queryAll("#headerLogoWrapper,#headerTitle").forEach((elem)=>elem.on('click',()=>
{
  	// if temp_data exists (running process) and the current page is not one of the listed ones
  	if(Object.keys(j.app.temp_data).length>0 && !(["error_page","contact_search","youre_in_page","youre_in_logistics_page","youre_out_page"].includes(j.app.state.current_page)))
    {
		j.confirmationModal("{$are_you_sure}",j.reset);
    }
  	else j.reset();
}));
if(j.query("footer")) j.query("footer").on('dblclick',() =>
{
  	if(j.app.state.current_page==="debug_pin_page" || j.app.state.current_page==="debug_page")
    {
    	j.reload(); 
    }
  	else j.app.next("debug_pin_page");
});
if(j.query("#languageButton")) j.query("#languageButton").on("click",() =>
{
    /*
	if(Object.keys(j.app.temp_data).length>0 && j.app.state.current_page!=="error_page")
    {
		j.confirmationModal("{$are_you_sure}",() => j.app.next("lang_selector"));
    }
  	else j.app.next("lang_selector");
    */
    j.app.languageModal();
});
if(j.query("#current_date"))
{
    j.clockElement = j.query("#current_date")
    if(j.clockInterval) clearInterval(j.clockInterval);

    let dateFunc = async () =>
    {
      let format = await j.translate("datetime_format"); // get the date format for the current language
      if(format.startsWith("fixme")) return;
      let date_str = phpdate(format); // format the date with the date-format-string
      j.clockElement.innerHTML=date_str; // replace the element content with the new date string
    }

    j.clockInterval = setInterval(dateFunc,15000);
    dateFunc();
}

j.app.config.slideshow="";
if(j.app.config.di && j.app.config.di.di_id)
{
	let slider = await API.GET("/display/"+j.app.config.di.di_id+"/slider",false,true,true);
  	if(slider)
    {
   		let slides = [];
      	slider.forEach((slide) =>
        {
            if(slide.parts)
            {
                slide.parts.forEach((part) =>
                                    {
                  	slides.push(part);
                });
            }
            else if(slide.download)
            {
              	slides.push(slide.download);
            }
        });
      	j.app.config.di.slides = slides;
      	let slideshow = `{if $config.di.slides.length>0}
			<div class="slideshow-container">
				{foreach $config.di.slides as $slide}
					<div class="mySlides fade">
						<img src="{$slide}" />
					</div>
				{/foreach}
				<a class="prev" onclick="slideshow.plusSlides(-1)" id="slideshow_next">&#10094;</a>
				<a class="next" onclick="slideshow.plusSlides(1)"  id="slideshow_prev">&#10095;</a>
			</div>
			<style> .scrollMask { height:100%; } </style>
		{/if}`;
      	j.app.config.slideshow=slideshow;
    }
}


//checklist_app_qr_js

/*
j.query("#hw_qr_code").on('blur', (ev) =>
{
    ev.preventDefault();
    if(j.query("#hw_qr_code"))
    {
      	j.query("#hw_qr_code").focus();
    }
});
*/
j.qrscan_handler = async (qrcode) =>
{
	if(j.query("#qr_error")) j.query("#qr_error").html("");
  	if(typeof qrcode==="undefined")
    {
        if(j.query("#hw_qr_code")) qrcode = j.query("#hw_qr_code").value;
        else if(j.query("#qr_error"))
        {
            j.query("#qr_error").html(await j.translate("qrcode_invalid"));
            j.HideLoadingOverlay();
            return;
        }
      	else
        {
            j.app.next("error_page",{error_code:"AE_018"});
            return;
        }
    }
    if(j.query("#hw_qr_code")) j.query("#hw_qr_code").value="";

    let json = await API.GET("/logistic/process/?qrcode="+qrcode+"&checklists");
    if(!json.ok)
    {
      if(j.query("#qr_error"))
      {
        j.query("#qr_error").html(await j.translate("qrcode_invalid"));
        j.HideLoadingOverlay();
        return;
      }
      j.app.next("error_page",{error_code:"AE_018"});
      return;
    }
    let data = await json.json();
    if(!data)
    {
      if(j.query("#qr_error"))
      {
        j.query("#qr_error").html(await j.translate("an_unknown_error_occured"));
        j.HideLoadingOverlay();
        return;
      }
      j.app.next("error_page",{error_code:"AE_019"});
      return;
    }
    if(data.message==="nok")
    {
      if(j.query("#qr_error"))
      {
        j.query("#qr_error").html(await j.translate("qrcode_invalid"));
        j.HideLoadingOverlay();
        return;
      }
      j.app.next("error_page",{error_code:"AE_020"});
      return;
    }
  	if(!data.lpi)
    {
    	if(j.query("#qr_error"))
      {
        j.query("#qr_error").html(await j.translate("qrcode_invalid"));
        j.HideLoadingOverlay();
        return;
      }
      j.app.next("error_page",{error_code:"AE_020"});
      return;
    }
  	
  	if(!data.checklists)
    {
      	j.infoModal("{$no_checklist_available}", () => j.reset());
      	j.HideLoadingOverlay();
    }
  	
  
  	if(data.ap.ap_checklist)
    {
        data.checklist=data.ap.ap_checklist;
    }
  	else
    {
      j.infoModal("{$no_checklist_available}", () => j.reset());
      j.HideLoadingOverlay();
    }
    j.app.temp_data.ltdata = data;

    j.app.next("checklists_overview_page");
}
j.query("#hw_qr_code").on("keyup", async (ev) =>
{
  	if(ev.keyCode === 13)
    {
        ev.preventDefault();
      	j.qrscan_handler();
    }
});
// j.query("#hw_qr_code").focus();
if(j.app.config.di && j.app.config.di.di_qr_engine==="js")
{
  	if(j.query("#mainbody"))
    {
      	window.qr_read_callback = (result) =>
        {
         	j.query("#hw_qr_code").value=result;
            j.qrscan_handler(); 
          	return false;
        }
		qr_initialize();
    }
}


//contact_search_js

j.queryAll("a.contactLink").forEach((link) =>
{
	link.on("click",async(ev) =>
    {
    	ev.preventDefault();
      	const pid = ev.target.dataset.id;
      	const P = j.app.temp_data.people[pid];
       	console.log(P);
      	let htmlstr = '';
      	const fields = {
          	"pe_name":"lastname",
          	"pe_vorname":"firstname",
        	"pe_building":"building",
        	"pe_building_part":"building_part",
          	"pe_department":"department",
          	"pe_floor":"floor",
          	"pe_room_nr":"room"
        };
      	await Renderer.smartify(Object.entries(fields).map((k)=>'{$'+k[1]+'}').join(),{});
      	for (let field in fields)
        {
        	if(P[field].length>0)
            {
            	htmlstr+='<div class="tableKey">'+(await j.translate(fields[field]))+'</div><div class="tableValue">'+P[field]+'</div>'
            }
        }
      	if(j.query(".profilePic")) j.query(".profilePic").remove();
      	if(j.query("#callButton")) j.query("#callButton").remove();
      	j.query("div.mainContactInfoPanel").insertAdjacentHTML('afterbegin','<img src="/app/img/user-pic.png" class="profilePic">');
      	j.query("div.contactInfoPanelGrid").html(htmlstr);
      	if(P["pe_tel_1"]!=null && P["pe_tel_1"].length>0)
        {
            if(j.phone && j.phone.active && await j.phone.checkOnlineStatus(false))
            {
        	  j.query(".contactPhonePanel").html('<button id="callButton" data-number="'+P['pe_tel_1']+'" data-name="'+P['pe_vorname']+' '+P['pe_name']+'" class="button btn green"><i class="fas fa-phone fa-fw"></i>&nbsp;&nbsp;Anrufen</button>');
          	  j.query("#callButton").on('click',(ev) =>
              {
            	if(typeof ev !== "undefined") ev.preventDefault();
              	let number = ev.currentTarget.dataset.number;
              	j.phone.call(number);
              });
            }
        }
       	j.query("div.contactInfoPanel").style.setProperty("opacity",1);
    });
});
j.query("a.contactInfoClose").on("click",(e)=>
{
    e.preventDefault();
    j.query("div.contactInfoPanel").style.setProperty("opacity",0);
});


//da_base_site_js

j.query("#backButton").on('click', () =>
{
	j.app.next("main_menu");
});
j.queryAll("#headerLogoWrapper,#headerTitle").forEach((elem)=>elem.on('click',()=>
{
  	j.app.next("main_menu");
}));
j.query("footer").on('dblclick',() =>
{
  	if(j.app.state.current_page==="debug_pin_page" || j.app.state.current_page==="debug_page")
    {
    	j.reload(); 
    }
  	else j.app.next("debug_pin_page");
});
j.query("#languageButton").on("click",() =>
{
	if(Object.keys(j.app.temp_data).length>0 && j.app.state.current_page!=="error_page")
    {
		j.confirmationModal("{$are_you_sure}",() => j.app.next("lang_selector"));
    }
  	else j.app.next("lang_selector");
});

j.app.config.slideshow="";
if(j.app.config.di && j.app.config.di.di_id)
{
	let slider = await API.GET("/display/"+j.app.config.di.di_id+"/slider",false,true,true);
  	if(slider)
    {
   		let slides = [];
      	slider.forEach((slide) =>
        {
            if(slide.parts)
            {
                slide.parts.forEach((part) =>
                                    {
                  	slides.push(part);
                });
            }
            else if(slide.download)
            {
              	slides.push(slide.download);
            }
        });
      	j.app.config.di.slides = slides;
      	let slideshow = '{if $config.di.slides.length>0}<div class="slideshow-container">{foreach $config.di.slides as $slide}<div class="mySlides fade"><img src="{$slide}" /></div>{/foreach}<a class="prev" onclick="slideshow.plusSlides(-1)">&#10094;</a><a class="next"onclick="slideshow.plusSlides(1)">&#10095;</a></div><style> .scrollMask { height:100%; } </style>{/if}';
      	j.app.config.slideshow=slideshow;
    }
}


//gdpr_late_submit_js

(async function(){
if(j.app.temp_data.checkin_data)
{
  let jID;
  if(j.app.temp_data.checkin_data.AU) jID = j.app.temp_data.checkin_data.AU.au_jau_id;
  else if(j.app.temp_data.checkin_data.JAU) jID = j.app.temp_data.checkin_data.JAU.jau_id;
  else if(j.app.temp_data.checkin_data.au) jID = j.app.temp_data.checkin_data.au.au_jau_id;
  else if(j.app.temp_data.checkin_data.jau) jID = j.app.temp_data.checkin_data.jau.jau_id;
  else return;
  
  if(j.app.temp_data.gdpr_data && j.app.temp_data.gdpr_accepted)
  {
      let gdpr_data = j.app.temp_data.gdpr_data;
      let post_data = {
          accepted:true
      };
      if(gdpr_data.signature_required)
      {
          if(j.app.temp_data.gdpr_signature)
          {
              post_data.signature = j.app.temp_data.gdpr_signature;
          }
          else
          {
          	  j.app.next("gdpr_page",{target_page:j.app.state.current_page});
              return;
          }
      }
      
      let json = await API.POST("/gdpr/"+jID, post_data);
      console.log(await json.text());
      return;
  }
}
})();


//guidance_history_js

j.guidanceHistory = async (ev) =>
{
    let jau_id = false;
  	if(ev.currentTarget.dataset.jauid) jau_id=ev.currentTarget.dataset.jauid;
	else if(j.app.temp_data.checkin_data.JAU && j.app.temp_data.checkin_data.JAU.jau_id) jau_id=j.app.temp_data.checkin_data.JAU.jau_id;
	else if(j.app.temp_data.checkin_data.jau && j.app.temp_data.checkin_data.jau.jau_id) jau_id=j.app.temp_data.checkin_data.jau.jau_id;
	else if(j.app.temp_data.checkin_data.AU && j.app.temp_data.checkin_data.AU.au_jau_id) jau_id=j.app.temp_data.checkin_data.AU.au_jau_id;
	else if(j.app.temp_data.checkin_data.au && j.app.temp_data.checkin_data.au.au_jau_id) jau_id=j.app.temp_data.checkin_data.au.au_jau_id;
  
    if(jau_id!=false)
    {
     	let guidances_done = await API.GET("/visitor/guidance/log/"+jau_id,true,true,true);
      	if(guidances_done)
        {
         	j.app.temp_data.checkin_data.guidances_done = guidances_done;
            if(guidances_done.length>0)
            {
          	    await j.modal(
                  "{$guidance_history}",
                  `<div class="buttonList">
                    {foreach $checkin_data.guidances_done as $guide}
                      <div class="guidanceButton old" data-id="{$guide.gui_id}">
                        <img src="/app/img/icons/icon_unterweisung.svg" class="guidButtImg">
                        <div class="historyListEntry">
                          <div>{$guide.gui_name}</div>
                          <kdone>{$done_at}:</kdone>
                          <vdone>{$guide.gul_time|toDate}</vdone>
                          <kvalid>{$valid_until}:</kvalid>
                          <vvalid>{$guide.gul_valid_until|toDate}</vvalid>
                        </div>
                        <button class="guidStartButt">{$refresh_guidance}</button>
                      </div>
                    {/foreach}
                  </div>` );
          	    j.queryAll(".guidanceButton.old").on("click", async (ev) =>
                {
                    ev.preventDefault();
                    let gid = ev.currentTarget.dataset.id;
                    console.log(gid);
                    let json = await API.GET("/guidance/"+gid);
                    if(!json.ok)
                    {
                        j.app.next("error_page",{error_code:"AE_018"});
                        return;
                    }
                    let data = await json.json();
                    let guide = j.app.temp_data.checkin_data.guidances_done.find(g => g.gui_id==gid);
                    if(data)
                    {
                        let points=[];
                        for(let index in data.points)
                            points.push(data.points[index]);
                        data.points=points;
                        Object.assign(guide, data);
                        if(guide.points.length==0)
                        {
                            guide.points.push({
                                guip_id:0,
                                guip_gui_id:gid,
                                guip_name:"{$empty_guidance}",
                                guip_type:"text",
                                guip_body:"<p>{$guidance_is_empty}</p>",
                                guip_ttl:0,
                                guip_pos:1
                            });
                        }
                        j.app.temp_data.current_guide = guide;
                    }
                    j.app.next("guidance_single_start_page",{page:0});
                });
            }
            else
            {
                j.infoModal("{$no_guidance_history_available}");
            }
        }
        else
        {
        	j.infoModal("{$no_guidance_history_available}");
        }
    }
    else
    {
        j.infoModal("{$no_guidance_history_available}");
    }
}
if(j.query("#gui_log_btn")) j.query("#gui_log_btn").on('click', (ev) => j.guidanceHistory(ev));


//high_contrast_mode.js

if(j.app.config.high_contrast_enable=="yes")
{
    await j.addHeaderHtml(`<i class="fas fa-adjust" style="color: #000f;
        font-size: xx-large;"></i>`,'hcm_button',true);
    j.query("#hcm_button").on('click',() =>
    {
        let style_elem = j.query(`link[rel="stylesheet"][href="/portals/download.php?mode=app_fragment&ali_name=high_contrast.css"]`);
        if(style_elem)
        {
            style_elem.remove();
            setTimeout(()=>j.keyboard.autoShow(),500);
        }
        else
        {
            j.query('body').insertAdjacentHTML('beforeend',`<link rel="stylesheet" href="/portals/download.php?mode=app_fragment&ali_name=high_contrast.css">`);
            setTimeout(()=>j.keyboard.autoShow(),500);
        }
    });
}


//j_auth

/**
 * Class for handling the login
 * @class
 * @name auth
 * @memberof j
 * @static
 */
if(!j.auth) j.auth = (function(o){
  	if(typeof j.store === "undefined")
    {
      j.errorModal("AE_031","j_auth requires j_store. j_store must be loaded BEFORE j_auth.");
      return o;
    }
    /**
     * @var {string|null} token the access token for the api
     * @memberof j.auth
     */
    o.token=null;
    /**
     * @var {object|null} user the user array
     * @memberof j.auth
     */
  	o.user=null;
  
    /**
     * @var {Callable} loginCallback a callback that gets executed, when a login succeeds
     * @memberof j.auth
     */
  	o.loginCallback = () => {};

    /**
     * Function for logging in
     * @function login
     * @memberof j.auth
     * @param {string} username the username
     * @param {string} password the password
     * @param {boolean} remember wether to save the login for later use
     * @returns {Promise<boolean>} true on success
     * @example
     * if(await j.auth.login("user","pass",true))
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     */
	o.login = async (username,password,remember,callback) =>
    {
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
    	return j.auth._login({
        	name:username,
            pass:password
        },remember)
    }

    /**
     * Function for logging in internally
     * @function _login
     * @memberof j.auth
     * @param {object} loginData contains username, password and gets directly send to the login endpoint
     * @param {boolean} remember wether to save the login for later use
     * @returns {Promise<boolean>} true on success
     * @example
     * if(await j.auth._login(userData,true))
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     * @ignore
     */
    o._login = async (loginData,remember,callback) =>
    {
      	if(typeof remember === "undefined") remember=false;
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
        let response = await API.POST("/login/",loginData,false,true,true);
        if(response)
        {
            j.auth.token=response.SID;
          	j.auth.user=response;
            API.apikey = j.auth.token;
          	if(remember)
            {
            	j.store.set("auth",loginData);
            }
          	
          	console.log(j.auth.user);
          	j.auth.loginCallback(j.auth.user);
          	j.auth.loginCallback = () => {};
          	j.closeModal(true);
            return true;
        }
        return false;
    };

    /**
     * Function for automatically logging in (e.g. on page reload)
     * @function autoLogin
     * @memberof j.auth
     * @returns {Promise<boolean>} true on success and logged in
     * @example
     * if(await j.auth.autoLogin())
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     */
  	o.autoLogin = async (callback) =>
    {
      if(typeof callback !== "undefined") j.auth.loginCallback = callback;
      let data = j.store.get("auth");
      if(data)
      {
        return j.auth._login(data,true);
      }
      else return false;
    }
    
    /**
     * Checks if there is stored data to try the autologin
     * @function canTryAutoLogin
     * @memberof j.auth
     * @returns {boolean}
     */
    o.canTryAutoLogin = () =>
    {
    	let data = j.store.get("auth");
      	if(data)
        {
        	return true;
        }
      	else return false;
    }

    /**
     * Function for logging out (and removing saved login data)
     * @function logout
     * @memberof j.auth
     * @returns {Promise}
     * @example j.auth.logout().then(() => console.log("logged out"));
     */
    o.logout = async () =>
    {
        j.auth.token = null;
        j.auth.user = null;
        API.apikey = null;
      	j.store.delete("auth");
      	await j.infoModal("{$you_have_been_logged_out}");
    };

    /**
     * Function for checking if logged in
     * @function isLoggedIn
     * @memberof j.auth
     * @returns {boolean} true if logged in
     * @example
     * if (!j.auth.isLoggedIn())
     * {
     *     // not logged in
     * }
     */
  	o.isLoggedIn = () => j.auth.token!==null;
  
  	o.modalDismissable = true;

    /**
     * Function opening a modal with a login form
     * @function modal
     * @memberof j.auth
     * @param {Callable?} callback a callback to execute when login succeeds
     * @param {boolean?} dismissable when false, the modal cannot be closed until the user logs in.
     * @returns {Promise}
     * @example
     * j.query("#loginButton").on('click', () => j.auth.modal());
     */
  	o.modal = async (callback,dismissable) =>
    {
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
      	if(typeof dismissable == "undefined") dismissable = true;
      	j.auth.modalDismissable=dismissable;
      	if(j.auth.isLoggedIn())
        {
          	j.confirmationModal("Sie sind bereits angemeldet. Möchten Sie sich abmelden?",async () => { await j.auth.logout(); j.reset(); })
          	return;
        }
      	let modalButtons = [
              	{
                    icon:   "check",
                    text:   "{$login}",
                    bgcolor:"#458B00",
                    color:  "#fff",
                    onclick:() =>
                    {
                        j.auth.submitModal();
                    }
                }
            ];
        if(j.auth.modalDismissable)
        {
        	modalButtons.unshift(
            	{
                    icon:   "times",
                    text:   "{$cancel}",
                    bgcolor:"#B71427",
                    color:  "#fff",
                    onclick:() => j.closeModal()
                });
        }
    	await j.questionModal(
            "{$login}",
            modalButtons,
            j.auth.modalDismissable,
            '<form id="login_modal_form" method="post" action="/api/v1/self_checkin" class="form scrollto">'
    		+ '<div class="form-group"><label class="label">Username</label><input type="text" placeholder="Username" name="name" id="username" value="" class="input" required></div>'
    		+'<div class="form-group"><label class="label">Password</label><input type="password" placeholder="Password" name="pass" id="password" value="" class="input" required></div>'
          	+'<div class="checkbox"><input type="checkbox" class="checkToggle" id="remember" name="remember" value="1"><label for="remember">{$remember_login}</label></div>'
          	+'<p class="error red" id="login_error"></p>'
			+'</form>'
        );
    };

    /**
     * Function for submitting the login form (gets hooked on the submit button in the login form modal)
     * @function submitModal
     * @memberof j.auth
     * @returns {Promise}
     * @ignore
     */
    o.submitModal = async () =>
    {
      	j.query("#login_error").html("");
		if(!j.query("#login_modal_form").checkValidity())
        {
            j.query("#login_modal_form").reportValidity();
            return false;
        }
      	let data = API.SerializeForm("#login_modal_form");
      	if(await j.auth._login(data,data.remember=="1"))
        {
          	j.closeModal(true);
        }
      	else
        {
      		j.query("#login_error").jhtml("{$wrong_username_or_password}");
        }
    }
	
	o.requireLogin = () => new Promise(async (resolve,error) =>
    {
        let al = await j.auth.autoLogin();
        if(al === true)
        {
            resolve(j.auth.user);
            return;
        }
        await j.auth.modal(u => resolve(u),false);
    });
    return o;
})({});
await j.auth.autoLogin();


//j_logistics

if(!j.logistics) j.logistics = (function(o){
	o._currentProcess=null;
	o.current = () => j.logistics._currentProcess;
	
	o.loadAll = () =>
	{
		let stored = j.store.get("processes");
		if(!stored) stored=[];
		return stored;
	}
	
	o.getByQR = async qrcode =>
	{
		let stored = j.logistics.loadAll();
		let localIndex;
		let foundLocal = false;
		for(let i in stored)
		{
			if(qrcode===stored[i].lpi.lpi_qrcode)
			{
				localIndex=i;
				foundLocal=true;
				break;
			}
		}
		
		let foundRemote=false;
		let remotedata = await API.GET("/logistic/process/?qrcode="+qrcode+"&checklists&resolve",false,true,true);
		if(remotedata || remotedata.message!=="nok")
		{
			foundRemote=true;
		}
		
		if(foundRemote)
		{
			if(foundLocal)
			{
				stored[localIndex]=remotedata;
			}
			else
			{
				stored.unshift(remotedata);
			}
			j.store.set("processes",stored);
			return remotedata;
		}
		else if (foundRemote) return stored[localIndex];
		else return null;
	}
	
	o.getByProcessId = async pid =>
	{
		let stored = j.logistics.loadAll();
		let localIndex;
		let foundLocal = false;
		for(let i in stored)
		{
			if(pid===stored[i].ap.ap_title)
			{
				localIndex=i;
				foundLocal=true;
				break;
			}
		}
		
		let foundRemote=false;
		let remotedata = await API.GET("/logistic/process/?process_id="+pid+"&checklists&resolve",false,true,true);
		if(remotedata || remotedata.message!=="nok")
		{
			foundRemote=true;
		}
		
		if(foundRemote)
		{
			if(foundLocal)
			{
				stored[localIndex]=remotedata;
			}
			else
			{
				stored.unshift(remotedata);
			}
			j.store.set("processes",stored);
			return remotedata;
		}
		else if (foundRemote) return stored[localIndex];
		else return null;
	}
	
	o.removeByQR = qrcode =>
	{
		let stored = j.logistics.loadAll();
		for(let i in stored)
		{
			if(qrcode===stored[i].lpi_qrcode)
			{
				stored.splice(i,1);
				j.store.set("processes",stored);
				return;
			}
		}
	}
	return o;
})({});


//j_phone

/**
 * Class handling phone calls
 * @class
 * @name phone
 * @memberof j
 * @static
 */
if(!j.phone) j.phone = await (async function(p)
{
    /**
     * @var {boolean} active if phone calls are configurated on the current kiosk
     */
	p.active=false;

    /**
     * @var {number} pollingInterval the intervall time in which the status of a call gets updated (default: 3000 [3 seconds])
     */
  	p.pollingInterval=3000;
    if(j.app.config.di && j.app.config.di.di_id)
    {
		p.channelID = j.app.config.di.di_id;
    }
    if(j.app.config.di && j.app.config.di.di_sip_data)
    {
    	p.src = j.app.config.di.di_sip_data;
    }
    if(p.channelID && p.src)
    {
        p.active=true;
    }
  
    /**
     * Function for checking the online status of the sip client
     * @function call
     * @memberof j.phone
     * @param {string} number the phone number to call
     * @param {string} modalText Text to show on the status modal (gets smartified)
     * @param {string} jamesMode a mode to set for the pbx handler
     * @param {string|number} jamesID a relevant unique id to set the context for the current mode
     * @returns {Promise}
     * @example j.phone.call("0123789","Calling an awesome dude");
     */
    p.checkOnlineStatus = async (showModal) =>
    {
        if(typeof showModal === "undefined") showModal=true;
    	if(!j.phone.active)
        {
        	if(showModal) j.infoModal("Die Telefonie für dieses Gerät wurde noch nicht (vollständig) konfiguriert.");
            return false;
        }
        let onlinecheck = await API.GET(`/pbx/endpoint/${j.phone.src}`,false,true,true);
      	if(onlinecheck && onlinecheck.status==="success" && onlinecheck.data.state==="online")
        {
          	j.phone.online=true;
            return true;
        }
        else
        {
        	if(showModal) j.infoModal("Der Telefonie-Client auf diesem Gerät ist leider nicht aktiv.");
            return false;
        }
        return j.phone.online;
    }
  
    /**
     * Function for starting a call
     * @function call
     * @memberof j.phone
     * @param {string} number the phone number to call
     * @param {string} modalText Text to show on the status modal (gets smartified)
     * @param {string} jamesMode a mode to set for the pbx handler
     * @param {string|number} jamesID a relevant unique id to set the context for the current mode
     * @returns {Promise}
     * @example j.phone.call("0123789","Calling an awesome dude");
     */
	p.call = async (number,modalText,jamesMode,jamesID) =>
    {
      	if(typeof modalText ==="undefined") modalText="{$calling}...";
      	if(typeof jamesMode ==="undefined") jamesMode="call";
      	if(typeof jamesID ==="undefined") jamesID=j.app.config.di.di_id;
      
    	if(!j.phone.active)
        {
        	j.infoModal("Die Telefonie für dieses Gerät wurde noch nicht (vollständig) konfiguriert.");
            return;
        }
        if(!j.phone.checkOnlineStatus())
        {
        	return;
        }
        let call = await API.POST("/pbx/"+j.phone.channelID,{
        	src:j.phone.src,
            dst:number,
          	james_mode: jamesMode,
          	james_id: jamesID
        },true,true,true);
        if(call.status!=="success")
        {
        	console.error(call);
        	j.errorModal("AE_018");
            return;
        }
        await j.questionModal(
            modalText,
            [
                {
                    icon:   "phone",
                    text:   "{$hangup}",
                    bgcolor:"#B71427",
                    color:  "#fff",
                    onclick:async () =>
                    {
                        await j.phone.hangUp()
                    }
                }
            ],
            false
        );
      	j.phone.watchState();
    };

    /**
     * Function to fetch the state of the current call
     * @function getState
     * @memberof j.phone
     * @returns {Promise<string>} a lowercase status
     * @example let state = await j.phone.getState();
     */
  	p.getState = async () =>
    {
    	if(!j.phone.active)
        {
        	j.infoModal("Die Telefonie für dieses Gerät wurde noch nicht (vollständig) konfiguriert.");
            return;
        }
        if(!j.phone.checkOnlineStatus())
        {
        	return;
        }
      	let result = await API.GET("/pbx/"+j.phone.channelID,false,true,true);
      	if(result!==null)
        {
          	if(result.data && result.data.message)
            {
              	if(result.data.message.match(/not found/))
                {
                  	return "down";
                }
            }
          	if(result.data && result.data.state)
            {
            	return result.data.state.toLowerCase();
            }
        }
      	return "unknown";
    }
    
    /**
     * @var {Callable} callEndCallback a callback to execute when a call ends
     * @memberof j.phone
     */
    p.callEndCallback = ()=>{};

    /**
     * Function for periodically fetching the call state and handle the end call back when the call has ended
     * @function watchState
     * @memberof j.phone
     * @returns Promise
     * @ignore
     * @example await j.phone.watchState();
     */
    p.watchState = async () =>
    {
    	let state = await j.phone.getState();
      	j.log("current call state: ",state);
      	if(state==="down")
        {
          j.phone.callEndCallback();
          p.callEndCallback = () => {};
          return j.phone.hangUp(false);
        }
      	else
        {
        	setTimeout(j.phone.watchState,j.phone.pollingInterval);
        }
    }

    /**
     * Function for ending a phone call
     * @function hangUp
     * @memberof j.phone
     * @param {boolean} sendHangupRequest if true, sends an api request to end the call (default: true)
     * @returns {Promise}
     * @example j.phone.hangup();
     */
    p.hangUp = async (sendHangupRequest) =>
    {
    	if(!j.phone.active)
        {
        	j.infoModal("Die Telefonie für dieses Gerät wurde noch nicht (vollständig) konfiguriert.");
            return;
        }
      	if(typeof sendHangupRequest === "undefined") sendHangupRequest=true;
    	API.DELETE("/pbx/"+j.phone.channelID,{},false,true,false);
		j.closeModal(true);
    }
    
    /**
     * Function to start an emergency call
     * @function emergencyCall
     * @memberof j.phone
     * @param {string} text Text to show on the modal (default: "{$calling_emergency}...")
     * @returns Promise
     * @example await j.phone.emergencyCall()
     */
    p.emergencyCall = async (text="{$calling_emergency}...") =>
    {
    	if(!j.phone.active)
        {
        	j.infoModal("Die Telefonie für dieses Gerät wurde noch nicht (vollständig) konfiguriert.");
            return;
        }
        if(!j.phone.checkOnlineStatus())
        {
        	return;
        }
      	if(j.app.config.di && j.app.config.di.di_ext_call)
        {
            let dst = j.app.config.di.di_ext_call;
          	await j.phone.call(dst,text);
        }
      	else
        {
        	j.infoModal("Für dieses Gerät wurde keine Durchwahlnummer konfiguriert.");
            return;
        }
    }
    
    JEventLib.overrideSingletonEvent("hangup",() =>
	{
    	if(typeof j.phone!=="undefined")
        {
        	j.phone.hangUp();
        }
    });

	return p;
})({});


//j_store

/**
 * Class for mapping accessing the local storage
 * @class
 * @name store
 * @memberof j
 * @static
 */
if(!j.store) j.store = (function(o)
{
  	/**
     * @var {string} prefix The prefix for cache keys (default is meta_)
     * @memberof j.store
     */
    o.prefix = "meta_";

    /**
     * Fetch a value from the local storage
     * @param {string} k the key to fetch
     * @returns {any|null} the fetched value deserialized or null if not found
     * @memberof j.store
     * @function get
     * @example let some_var = j.store.get("some_var");
     */
    o.get = k =>
    {
        let str = localStorage.getItem(j.store.prefix+k);
        if(!str) return null;
        return JSON.parse(str);
    };
    /**
     * Find out, if a key exists in the local storage
     * @param {string} k the key to lookup
     * @returns {boolean} wether or not the key exists
     * @memberof j.store
     * @function has
     * @example if(j.store.has("some_var") { ... }
     */
    o.has = k => j.store.get(k)!=null;

    /**
     * Set a value in the local storage (overrides existing)
     * @param {string} k the key where to save the object
     * @param {any} v the value to save
     * @memberof j.store
     * @function set
     * @example j.store.set("some_var","Hello there!");
     */
    o.set = (k,v) => localStorage.setItem(j.store.prefix+k,JSON.stringify(v));
    /**
     * Add a key in the local storage (will fail, if key already exsits. for overriding use set())
     * @param {string} k the key where to save the object
     * @param {any} v the value to save
     * @returns {boolean} true on success
     * @memberof j.store
     * @function add
     * @example
     * if(j.store.add("some_var","Hello there!"))
     * {
     *     // key has been added
     * }
     * else
     * {
     *     // key has NOT been added
     * }
     */
    o.add = (k,v) =>
    {
        if(j.store.get(k)!=null) return false;
        j.store.set(k,v);
        return true;
    };
    /**
     * Remove a key from the local storage
     * @param {string} k the key where the object is saved
     * @memberof j.store
     * @function delete
     * @example j.store.delete("some_var");
     */
    o.delete = k => localStorage.removeItem(j.store.prefix+k);
    /**
     * Remove a key from the local storage
     * @param {string} k the key where the object is saved
     * @memberof j.store
     * @function remove
     * @example j.store.remove("some_var");
     */
    o.remove = k => localStorage.removeItem(j.store.prefix+k);

    /**
     * Get all keys from the localstorage matching the prefix
     * @return {string[]} all the keys, that are currently saved in the local storage
     * @memberof j.store
     * @function keys
     * @example j.store.keys().forEach(k => console.log(k));
     */
  	o.keys = () =>
    {
      	let filter = new RegExp("^"+j.store.prefix);
      	return Object.keys(localStorage).filter((e) => e.match(filter)).map((e) => e.replace(filter,""));
    }
    /**
     * Remove all keys from the localstorage matching the prefix
     * @memberof j.store
     * @function clear
     * @example j.store.clear();
     */
    o.clear = () => j.store.keys().forEach(key => j.store.delete(key));

    return o;
})({});


//j_visit

if(!j.visit) j.visit = (function(o)
{
  	o.error = async (code) =>
    {
      	if(typeof(code)==="undefined") code = "AE_000";
        if(j.query("#qr_error"))
        {
          j.query("#qr_error").html(await j.translate("qrcode_invalid"));
          j.HideLoadingOverlay()
        }
        else
        {
          j.app.next("error_page",{error_code:code});
        }
        return;
    }
	o.checkinQR = async (id,simulate,guidance_target_page) =>
    {
        if(j.app.temp_data.checkin_data) j.app.temp_data.checkin_data.guidance=false;
      	if(typeof simulate==="undefined") simulate=false;
      	if(typeof guidance_target_page === "undefined") guidance_target_page="checkin_confirmation";

        let autoCheckin = j.app.config.auto_checkin_qr==="yes";
        if(autoCheckin) simulate=false;
      	let welcomePage = "youre_in_page";
        if(j.app.config.qr_welcome_target!="" && j.app.config.qr_welcome_target!=null)
        {
          welcomePage=j.app.config.qr_welcome_target;
        }
        if(j.app.temp_data.employee_data && j.app.temp_data.employee_data.emp_id>0)
        {
          welcomePage="youre_in_page_employee";
          if(j.app.config.employee_welcome_target!="" && j.app.config.employee_welcome_target!=null)
          {
            welcomePage=j.app.config.employee_welcome_target;
          }
        }


    	let json = await API.GET("/visitor/"+id+"/checkin"+(simulate?"?simulate":""),true,true,false);
      	let data = await json.json();
      	if(data && typeof data.success !== "undefined")
        {
          	if(data.success==true)
            {
              	if(j.app.temp_data.checkin_is_group)
                {
                    j.app.temp_data.checkin_data.guidance=false;
                  	for(let i in j.app.temp_data.group_ap_real.ap_contacts)
                    {
                    	if(j.app.temp_data.group_ap_real.ap_contacts[i].au_id==id)
                        {
                          	j.app.temp_data.group_ap_real.ap_contacts[i].checked_in=true;
                          	break;
                        }
                    }
                	j.app.next(simulate?"checkin_confirmation":"group_checkin_overview", { checkin_type:"qr", checkin_data:data });
                }
              	else
                {
        			j.app.next(simulate?"checkin_confirmation":welcomePage, { checkin_type:"qr", checkin_data:data });
                }
            }
            else if (data.time==="early")
            {
                    let msg = await j.translate("youre_early");
                j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_frueh.svg"}});
            }
                else if (data.time==="late")
            {
                    let msg = await j.translate("youre_late");
                j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_spaet.svg"}});
            }
          	else if (data.guidance!==false)
            {
            	j.app.next(guidance_target_page, { checkin_type:"qr", checkin_data:data });
            }
          	else if (typeof(data.gdpr)!=="undefined" && data.gdpr!==false)
            {
            	j.app.next("gdpr_page", { checkin_type:"qr", checkin_data:data, gdpr_state:data.gdpr });
            }
          	else if (typeof(data.checklist)!=="undefined" && data.checklist!==false)
            {
            	j.app.next("checkin_confirmation", { checkin_type:"qr", checkin_data:data });
            }
            else if (data.immunity_required===true)
            {
                j.app.next("checkin_confirmation", { checkin_type:"qr", checkin_data:data });
            }
      		else
            {
              let msg = await j.translate("an_unknown_error_occured");
              j.app.next("error_page",{error_message:msg});
            }
        }
      	else
        {
            j.visit.error("AE_020");
        }
    };

  	o.checkinSpontan = async (checkin_data,simulate,guidance_target_page) =>
    {
      	if(typeof simulate==="undefined") simulate=false;
      	if(typeof guidance_target_page === "undefined") guidance_target_page="checkin_confirmation_spontan";

        let autoCheckin = j.app.config.auto_checkin_spontan==="yes";
        if(autoCheckin) simulate=false;
      	let welcomePage = "youre_in_page";
        if(j.app.config.spontan_welcome_target!="" && j.app.config.spontan_welcome_target!=null)
        {
          welcomePage=j.app.config.spontan_welcome_target;
        }
      	/*
		// parse form data
		console.log(form);
		if(form!=null)
		{
			if(form instanceof HTMLFormElement)
			{
				j.app.temp_data.spont_checkin_form = API.ParseRequestData(form,false,false);
			}
			else j.app.temp_data.spont_checkin_form = form;
		}
		else if (typeof j.app.temp_data.spont_checkin_form === "undefined")
		{
			return false;
		}
		*/
      	if(typeof(checkin_data)==="undefined" && typeof(j.app.temp_data.checkin_data)!=="undefined")
        {
        	checkin_data = j.app.temp_data.checkin_data;
        }
    	let json = await API.GET("/spontan_visitor/"+checkin_data.aps_uuid+"/checkin"+(simulate?"?simulate":""),true,true,false);
      	j.log("response",json);
		if(json.status===401)
		{
			let data = await json.json();
          	Object.assign(checkin_data,data);
			j.log(checkin_data);
			if (checkin_data.guidance!==false)
            {
            	j.app.next(guidance_target_page, { checkin_type:"spontan", checkin_data:checkin_data });
            }
          	else if (typeof(checkin_data.gdpr)!=="undefined" && checkin_data.gdpr!==false)
            {
            	j.app.next("gdpr_page", { checkin_type:"spontan", checkin_data:checkin_data, gdpr_state:data.gdpr });
            }
          	else if (typeof(checkin_data.checklist)!=="undefined" && checkin_data.checklist!==false)
            {
            	j.app.next("checkin_confirmation_spontan", { checkin_type:"spontan", checkin_data:checkin_data });
            }
          	else if (checkin_data.time==="early")
            {
              	let msg = await j.translate("youre_early");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_frueh.svg"}});
            }
          	else if (checkin_data.time==="late")
            {
              	let msg = await j.translate("youre_late");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_spaet.svg"}});
            }
            else if (checkin_data.immunity_required===true)
            {
                j.app.next("checkin_confirmation_spontan", { checkin_type:"spontan", checkin_data:data });
            }
          	else if(checkin_data.reasons && checkin_data.reasons.length>0)
            {
            	if(checkin_data.reasons.includes("ALREADY_CHECKED_IN"))
                {
                    j.visit.error("AE_054");
                }
            }
      		else
            {
            	j.visit.error("AE_020");
            }
        }
		else if (!json.ok)
		{
            j.visit.error("AE_018");
		}
      	else
        {
			let data = await json.json();
			j.log("data",data);
          	Object.assign(checkin_data,data);
        	j.app.next(simulate?"checkin_confirmation_spontan":welcomePage, { checkin_type:"spontan", checkin_data:checkin_data });
        }
    };

	o.checkinLogistics = async (log_data,simulate,guidance_target_page) =>
    {
      	if(typeof simulate==="undefined") simulate=false;
        let autoCheckin = j.app.config.log.logistic_kiosk_auto_checkin==="yes";
        if(autoCheckin) simulate=false;
      	let welcomePage = "youre_in_logistics_page";
        if(j.app.config.log.logistic_kiosk_welcome_target!="" && j.app.config.log.logistic_kiosk_welcome_target!=null)
        {
          welcomePage=j.app.config.log.logistic_kiosk_welcome_target;
        }
      	if(typeof guidance_target_page === "undefined") guidance_target_page="checkin_confirmation_logistic";
      	if(typeof(log_data)==="undefined" && typeof(j.app.temp_data.logistics_data)!=="undefined")
        {
        	log_data = j.app.temp_data.logistics_data;
        }

      	let pjson = await API.POST("/logistic/process",{
            log_data:log_data
        });
        if(!pjson.ok)
        {
          let msg = await j.translate("an_unknown_error_occured");
          j.app.next("error_page",{error_message:msg});
        }
        let presponse = await pjson.json();
        j.log(presponse);
        Object.assign(j.app.temp_data.logistics_data,presponse,presponse.lpi);
        Object.assign(log_data,presponse);

    	let json = await API.GET("/logistic/process/"+log_data.ap.ap_id+"/driver/checkin"+(simulate?"?simulate":""),true,true,false);
		if(json.status===401)
		{
			let data = await json.json();
			j.log(data);
			if (data.guidance!==false)
            {
            	j.app.next(guidance_target_page, { checkin_type:"logistic", checkin_data:data, logistics_data:Object.assign(j.app.temp_data.logistics_data,log_data) });
            }
          	else if (typeof(data.gdpr)!=="undefined" && data.gdpr!==false)
            {
            	j.app.next("gdpr_page", { checkin_type:"logistic", checkin_data:data, logistics_data:Object.assign(j.app.temp_data.logistics_data,log_data), gdpr_state:data.gdpr });
            }
          	else if (typeof(data.checklist)!=="undefined" && data.checklist!==false)
            {
            	j.app.next("checkin_confirmation_logistic", { checkin_type:"logistic", checkin_data:data, logistics_data:Object.assign(j.app.temp_data.logistics_data,log_data) });
            }
          	else if (data.time==="early")
            {
              	let msg = await j.translate("youre_early");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_frueh.svg"}});
            }
          	else if (data.time==="late")
            {
              	let msg = await j.translate("youre_late");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_spaet.svg"}});
            }
            else if (data.immunity_required===true)
            {
                j.app.next("checkin_confirmation_logistic", { checkin_type:"logistic", checkin_data:data });
            }
      		else
            {
            	j.visit.error("AE_020");
            }
        }
		else if (!json.ok)
		{
            j.visit.error("AE_018");
		}
      	else
        {
			let data = await json.json();
			j.log("data",data);
          	let route_id = null;
          	if(data.ap && data.ap.ap_lsl_id)
            {
             	if(data.ap.ap_lsl.lsl_me_id)
                {
                	route_id=data.ap.ap_lsl.lsl_me_id;
                }
            }
          	if(data.ap && data.ap.ap_ls_id)
            {
             	if(data.ap.ap_ls.ls_me_id)
                {
                	route_id=data.ap.ap_ls.ls_me_id;
                }
            }
          	if(route_id)
            {
            	j.app.next(simulate?"checkin_confirmation_logistic":welcomePage, { checkin_type:"logistic", logistics_data:Object.assign(j.app.temp_data.logistics_data,log_data), checkin_data:data, logistics_route:route_id });
            }
        	else j.app.next(simulate?"checkin_confirmation_logistic":welcomePage, { checkin_type:"logistic", logistics_data:Object.assign(j.app.temp_data.logistics_data,log_data), checkin_data:data, logistics_route:"none" });
        }
    };


	o.checkin = async (data,simulate,guidance_target_page,visit_type) =>
	{
      	if(typeof visit_type === "undefined")
        {
        	if(typeof(j.app.temp_data.visit_type) === "undefined")
            {
            	visit_type="qr";
            }
          	else visit_type=j.app.temp_data.visit_type;
        }
      	else
        {
        	j.app.temp_data.visit_type=visit_type;
        }
		switch(visit_type)
		{
			case "qr":
				return j.visit.checkinQR(data,simulate,guidance_target_page);
				break;
			case "spontan":
				return j.visit.checkinSpontan(data,simulate,guidance_target_page);
				break;
			case "logistic":
				return j.visit.checkinLogistics(j.app.temp_data.logistics_data,simulate,guidance_target_page);
				break;
			case "group_qr":
				return j.visit.checkinGroupQR(simulate,guidance_target_page);
				break;
			default:
            	j.visit.error("AE_021");
				break;
		}
	}

    o.retryCheckin = async (back) =>
    {
      if(typeof back === "undefined") back = false;
      switch(j.app.temp_data.checkin_type)
      {
        case "qr":
          let id;
          if(j.app.temp_data.checkin_data.au && j.app.temp_data.checkin_data.au.au_id)
            id = j.app.temp_data.checkin_data.au.au_id;
          else if(j.app.temp_data.checkin_data.AU && j.app.temp_data.checkin_data.AU.au_id)
            id = j.app.temp_data.checkin_data.AU.au_id;
          else {console.error("Missing ID!"); return};
          j.visit.checkin(id,true,back==true?undefined:"guidance_page","qr");
          break;
        case "spontan":
          j.visit.checkin(j.app.temp_data.spont_checkin_form,true,back==true?undefined:"guidance_page","spontan");
          break;
        case "logistic":
          j.visit.checkin(j.app.temp_data.spont_checkin_form,true,back==true?undefined:"guidance_page","logistic");
          break;
        case "group_qr":
          j.visit.checkin(j.app.temp_data.checkin_data,true,"guidance_page","group_qr");
          break;
        default:
  		  j.app.next("error_page",{error_code:"AE_016"});
          break;
      }
    };

  	o.checkout = async (id) =>
    {
    	let json = await API.GET("/visitor/"+id+"/checkout",true,true,false);
      	if(!json.ok)
        {
  			j.app.next("error_page",{error_code:"AE_018"});
          	return;
        }
      	let data = await json.json();
      	if(data && data.success && data.success==true)
        {
        	j.app.next("youre_out_page");
        }
      	else
        {
  			j.app.next("error_page",{error_code:"AE_020"});
        }
    };

  	o.getCurrentGroupUser = () =>
    {
    	if(!j.app.temp_data.groupQR_checkin_idx)
          	j.app.temp_data.groupQR_checkin_idx=0;
      	if(j.app.temp_data.groupQR_checkin_idx>=j.app.temp_data.checkin_data.selected_aus.length)
        {
        	return null;
        }
      	j.app.temp_data.groupQR_checkin_au_id=j.app.temp_data.checkin_data.selected_aus[j.app.temp_data.groupQR_checkin_idx];
      	j.app.temp_data.groupQR_checkin_au = j.app.temp_data.checkin_data.AUS[j.app.temp_data.groupQR_checkin_au_id];
      	return j.app.temp_data.groupQR_checkin_au;
    }
	o.checkinGroupQR = async (simulate,guidance_target_page) =>
    {
      	if(typeof simulate==="undefined") simulate=false;
      	if(typeof guidance_target_page === "undefined") guidance_target_page="checkin_confirmation_group_qr";

      	j.visit.getCurrentGroupUser();

    	let json = await API.GET("/visitor/"+j.app.temp_data.groupQR_checkin_au_id+"/checkin"+(simulate?"?simulate":""),true,true,false);
      	let data = await json.json();
      	if(data && typeof data.success !== "undefined")
        {
          	j.app.temp_data.checkin_response = data;
          	if(data.success==true)
            {
              	if(!simulate)
                {
                	// j.app.temp_data.checkin_data.selected_aus.splice(j.app.temp_data.checkin_data.selected_aus.indexOf(j.app.temp_data.groupQR_checkin_au_id),1);
                  	j.app.temp_data.groupQR_checkin_idx++;
                }
              	j.app.next(simulate?"checkin_confirmation_group_qr":"group_qr_youre_in_page", { checkin_type:"group_qr" });
            }
          	else if (data.guidance!==false)
            {
            	j.app.next(guidance_target_page, { checkin_type:"group_qr" });
            }
          	else if (typeof(data.gdpr)!=="undefined" && data.gdpr!==false)
            {
            	j.app.next("gdpr_page", { checkin_type:"group_qr", gdpr_state:data.gdpr });
            }
          	else if (typeof(data.checklist)!=="undefined" && data.checklist!==false)
            {
            	j.app.next("checkin_confirmation_group_qr", { checkin_type:"group_qr" });
            }
          	else if (data.time==="early")
            {
              	let msg = await j.translate("youre_early");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_frueh.svg"}});
            }
          	else if (data.time==="late")
            {
              	let msg = await j.translate("youre_late");
            	j.app.next("error_page",{error_message:msg,error_image:{url:"/app/img/icons/icon_spaet.svg"}});
            }
            else if (data.immunity_required===true)
            {
                j.app.next("checkin_confirmation", { checkin_type:"group_qr", checkin_data:data });
            }
      		else
            {
              let msg = await j.translate("an_unknown_error_occured");
              j.app.next("error_page",{error_message:msg});
            }
        }
      	else
        {
            j.visit.error("AE_020");
        }
    };

  	o.multiguide = async () =>
  	{
    	let response = await API.GET("/visitor/multiguide/"+j.app.temp_data.checkin_data.AP.ap_id+"?aus="+j.app.temp_data.checkin_data.selected_aus.join(","),true,true,true);
        if(response===null || response===false)
        {
            j.HideLoadingOverlay();
            j.errorModal("AE_020");
        }
        if(response.guidances_required)
        {
            j.app.temp_data.checkin_data.guidance=response.guidances;
            j.app.next("guidance_page");
        }
        else
        {
            j.visit.retryCheckin();
        }
    }
  	return o;
})({});


//j_visitor_auth

/**
 * Class for handling the login
 * @class
 * @name auth
 * @memberof j
 * @static
 */
if(!j.auth) j.auth = (function(o){
  	if(typeof j.store === "undefined")
    {
      j.errorModal("AE_031","j_auth requires j_store. j_store must be loaded BEFORE j_auth.");
      return o;
    }
    /**
     * @var {string|null} token the access token for the api
     * @memberof j.auth
     */
    o.token=null;
    /**
     * @var {object|null} user the user array
     * @memberof j.auth
     */
  	o.user=null;
  
    /**
     * @var {Callable} loginCallback a callback that gets executed, when a login succeeds
     * @memberof j.auth
     */
  	o.loginCallback = () => {};

    /**
     * Function for logging in
     * @function login
     * @memberof j.auth
     * @param {string} username the username
     * @param {string} password the password
     * @param {boolean} remember wether to save the login for later use
     * @returns {Promise<boolean>} true on success
     * @example
     * if(await j.auth.login("user","pass",true))
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     */
	o.login = async (username,password,remember,callback) =>
    {
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
    	return j.auth._login({
        	email:username,
            pass:password
        },remember)
    }

    /**
     * Function for logging in internally
     * @function _login
     * @memberof j.auth
     * @param {object} loginData contains username, password and gets directly send to the login endpoint
     * @param {boolean} remember wether to save the login for later use
     * @returns {Promise<boolean>} true on success
     * @example
     * if(await j.auth._login(userData,true))
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     * @ignore
     */
    o._login = async (loginData,remember,callback) =>
    {
      	if(typeof remember === "undefined") remember=false;
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
        let response = await API.POST("/user/login",loginData,false,true,true);
        if(response)
        {
            j.auth.token=response.SID;
          	j.auth.user=response;
            API.apikey = j.auth.token;
          	if(remember)
            {
            	j.store.set("vauth",loginData);
            }
          	
          	console.log(j.auth.user);
          	j.auth.loginCallback(j.auth.user);
          	j.auth.loginCallback = () => {};
          	j.closeModal(true);
            return true;
        }
        return false;
    };

    /**
     * Function for automatically logging in (e.g. on page reload)
     * @function autoLogin
     * @memberof j.auth
     * @returns {Promise<boolean>} true on success and logged in
     * @example
     * if(await j.auth.autoLogin())
     * {
     *     console.log("logged in");
     * }
     * else
     * {
     *     console.log("not logged in");
     * }
     */
  	o.autoLogin = async (callback) =>
    {
      if(typeof callback !== "undefined") j.auth.loginCallback = callback;
      let data = j.store.get("vauth");
      if(data)
      {
        return j.auth._login(data,true);
      }
      else return false;
    }
    
    /**
     * Checks if there is stored data to try the autologin
     * @function canTryAutoLogin
     * @memberof j.auth
     * @returns {boolean}
     */
    o.canTryAutoLogin = () =>
    {
    	let data = j.store.get("vauth");
      	if(data)
        {
        	return true;
        }
      	else return false;
    }

    /**
     * Function for logging out (and removing saved login data)
     * @function logout
     * @memberof j.auth
     * @returns {Promise}
     * @example j.auth.logout().then(() => console.log("logged out"));
     */
    o.logout = async () =>
    {
        j.auth.token = null;
        j.auth.user = null;
        API.apikey = null;
      	j.store.delete("vauth");
      	await j.infoModal("{$you_have_been_logged_out}");
    };

    /**
     * Function for checking if logged in
     * @function isLoggedIn
     * @memberof j.auth
     * @returns {boolean} true if logged in
     * @example
     * if (!j.auth.isLoggedIn())
     * {
     *     // not logged in
     * }
     */
  	o.isLoggedIn = () => j.auth.token!==null;
  
  	o.modalDismissable = true;

    /**
     * Function opening a modal with a login form
     * @function modal
     * @memberof j.auth
     * @param {Callable?} callback a callback to execute when login succeeds
     * @param {boolean?} dismissable when false, the modal cannot be closed until the user logs in.
     * @returns {Promise}
     * @example
     * j.query("#loginButton").on('click', () => j.auth.modal());
     */
  	o.modal = async (callback,dismissable) =>
    {
      	if(typeof callback !== "undefined") j.auth.loginCallback = callback;
      	if(typeof dismissable == "undefined") dismissable = true;
      	j.auth.modalDismissable=dismissable;
      	if(j.auth.isLoggedIn())
        {
          	j.confirmationModal("Sie sind bereits angemeldet. Möchten Sie sich abmelden?",async () => { await j.auth.logout(); j.reset(); })
          	return;
        }
      	let modalButtons = [
              	{
                    icon:   "check",
                    text:   "{$login}",
                    bgcolor:"#458B00",
                    color:  "#fff",
                    onclick:() =>
                    {
                        j.auth.submitModal();
                    }
                }
            ];
        if(j.auth.modalDismissable)
        {
        	modalButtons.unshift(
            	{
                    icon:   "times",
                    text:   "{$cancel}",
                    bgcolor:"#B71427",
                    color:  "#fff",
                    onclick:() => j.closeModal()
                });
        }
    	await j.questionModal(
            "{$login}",
            modalButtons,
            j.auth.modalDismissable,
            '<form id="login_modal_form" method="post" action="/api/v1/self_checkin" class="form scrollto">'
    		+ '<div class="form-group"><label class="label">Username or E-Mail</label><input type="text" placeholder="Username or E-Mail" name="email" id="username" value="" class="input" required></div>'
    		+'<div class="form-group"><label class="label">Password</label><input type="password" placeholder="Password" name="pass" id="password" value="" class="input" required></div>'
          	+'<div class="checkbox"><input type="checkbox" class="checkToggle" id="remember" name="remember" value="1"><label for="remember">{$remember_login}</label></div>'
          	+'<p class="error red" id="login_error"></p>'
			+'</form>'
        );
    };

    /**
     * Function for submitting the login form (gets hooked on the submit button in the login form modal)
     * @function submitModal
     * @memberof j.auth
     * @returns {Promise}
     * @ignore
     */
    o.submitModal = async () =>
    {
      	j.query("#login_error").html("");
		if(!j.query("#login_modal_form").checkValidity())
        {
            j.query("#login_modal_form").reportValidity();
            return false;
        }
      	let data = API.SerializeForm("#login_modal_form");
      	if(await j.auth._login(data,data.remember=="1"))
        {
          	j.closeModal(true);
        }
      	else
        {
      		j.query("#login_error").jhtml("{$wrong_username_or_password}");
        }
    }
	
	o.requireLogin = () => new Promise(async (resolve,error) =>
    {
        let al = await j.auth.autoLogin();
        if(al === true)
        {
            resolve(j.auth.user);
            return;
        }
        await j.auth.modal(u => resolve(u),false);
    });
    return o;
})({});
await j.auth.autoLogin();


//language_selector_js

j.queryAll('.langCard').on('click',async (ev) =>
{
  	j.ShowLoadingOverlay();
    let lang = ev.currentTarget.dataset.lang;
    console.log(lang);
    await j.app.setLanguage(lang,true,true);
    await j.app.next('main_menu',{},'lang_selected');
});

API.GET(`/languagepack/de?cache=${jDefaults.cache.translations}`,false,true,true).then(de =>
{
  if(de.status && de.status.success)
  {
    if(typeof(Renderer.cached_data)==="undefined") Renderer.cached_data={};
    if(typeof(Renderer.cached_data["de"])==="undefined") Renderer.cached_data["de"]={};
    Renderer.cached_data["de"] = Object.assign(Renderer.cached_data["de"], de.data);
  }
});

API.GET(`/languagepack/en?cache=${jDefaults.cache.translations}`,false,true,true).then(en =>
{
  if(en.status && en.status.success)
  {
    if(typeof(Renderer.cached_data)==="undefined") Renderer.cached_data={};
    if(typeof(Renderer.cached_data["en"])==="undefined") Renderer.cached_data["en"]={};
    Renderer.cached_data["en"] = Object.assign(Renderer.cached_data["en"], en.data);
  }
});


//main_menu_js

j.queryAll('.menuCard:not(.custom)').on('click',async (ev) =>
{
    let data = ev.currentTarget.dataset;
  	if(data.businesshours==="true" && !await j.inService()) return;
    if(data.process) j.loadProgress(data.process);
    let next = data.next;
    console.log(ev);
    console.log(next);
    j.app.next(next);
});
if(j.query("#emergency_call")) j.query("#emergency_call").on('click',async (ev) =>
{
  	if(ev.currentTarget.dataset.businesshours==="true" && !await j.inService()) return;
	if(j.phone && j.phone.active)
    {
    	j.phone.emergencyCall();
    }
});
if(j.query('#logistics')) j.query('#logistics').on('click',async (ev) =>
{
    let data = ev.currentTarget.dataset;
    j.loadProgress("logistic")
  	if(data.businesshours==="true" && !await j.inService()) return;
  	let log_json = await API.GET("/logistic/settings/?cache="+jDefaults.cache.log_settings);
    if(log_json.ok)
    {
        let log = await log_json.json();
        j.app.config.log = log;
    }
    else
    {
        j.app.next("error_page",{error_code:"AE_018", error_message:"Konnte Logistik-Konfiguration nicht laden."});
      	return;
    }
  	let target_page="logistics_1";
    if(j.app.config.log.logistic_kiosk_psa_check==="yes")
    {
     	 target_page="logistics_0";
    }
  	if(j.app.config.log.logistic_kiosk_gdpr_check==="yes")
    {
      	j.app.next("gdpr_page",{target_page:target_page});
    }
  	else
    {
     	 j.app.next(target_page);
    }
});
if(j.query("#group_checkin")) j.query("#group_checkin").on('click', async (ev) =>
{
    let data = ev.currentTarget.dataset;
    j.loadProgress("group_spontan");
  	if(data.businesshours==="true" && !await j.inService()) return;
    j.app.next("group_checkin_ap");
});


//main_menu_service_checker

if(typeof j.mainMenuService==="undefined") j.mainMenuService = await (async (o) =>
{
    o.timeout = null;
    
    o.checkService = async () =>
    {
        j.mainMenuService.timeout=null;
    	if(j.app.state.current_page!=="main_menu") return;
    	if(j.mainMenuService.inService !== await j.inService(false))
        {
          	j.log("service hours changed");
        	j.app.next(j.app.state.current_page);
        }
        else j.log("service hours not changed");
        j.mainMenuService.timeout=setTimeout(() => j.mainMenuService.checkService(), 1000*120);
    };
  
  	o.init = async () =>
    {
    	j.mainMenuService.inService = await j.inService(false);
        if(j.mainMenuService.timeout===null) j.mainMenuService.timeout=setTimeout(async () => await j.mainMenuService.checkService(), 1000*120);
    };
    return o;
})({});
setTimeout(() => j.mainMenuService.init(), 1000*120);


//pickerjs.min.js


/*!
 * Picker.js v1.2.1
 * https://fengyuanchen.github.io/pickerjs
 *
 * Copyright 2016-present Chen Fengyuan
 * Released under the MIT license
 *
 * Date: 2019-02-18T13:08:12.801Z
 */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Picker=t()}(this,function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function r(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function n(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t<e.length;t++)n[t]=e[t];return n}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var a={container:null,controls:!1,date:null,format:"YYYY-MM-DD HH:mm",headers:!1,increment:1,inline:!1,language:"",months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],rows:5,text:{title:"Pick a date and time",cancel:"Cancel",confirm:"OK",year:"Year",month:"Month",day:"Day",hour:"Hour",minute:"Minute",second:"Second",millisecond:"Millisecond"},translate:function(e,t){return t},show:null,shown:null,hide:null,hidden:null,pick:null},v='<div class="picker" data-picker-action="hide" touch-action="none" tabindex="-1" role="dialog"><div class="picker-dialog" role="document"><div class="picker-header"><h4 class="picker-title">{{ title }}</h4><button type="button" class="picker-close" data-picker-action="hide" aria-label="Close">&times;</button></div><div class="picker-body"><div class="picker-grid"></div></div><div class="picker-footer"><button type="button" class="picker-cancel" data-picker-action="hide">{{ cancel }}</button><button type="button" class="picker-confirm" data-picker-action="pick">{{ confirm }}</button></div></div></div>',s="undefined"!=typeof window,g=s?window:{},e=!!s&&"ontouchstart"in g.document.documentElement,i=!!s&&"PointerEvent"in g,b="picker",o={},y="next",k="prev",w="".concat(b,"-open"),M="".concat(b,"-opened"),d="".concat(b,"-picked"),E="".concat(b,"Action"),Y="type",m="value",c="click",l="focus",h="hidden",u="hide",f="keydown",p="pick",x=i?"pointerdown":e?"touchstart":"mousedown",D=i?"pointermove":e?"touchmove":"mousemove",S=i?"pointerup pointercancel":e?"touchend touchcancel":"mouseup",C="show",N="shown",A="wheel mousewheel DOMMouseScroll",O=Object.prototype,H=O.hasOwnProperty,P=O.toString;function F(e){return"string"==typeof e}var L=Number.isFinite||g.isFinite,j=Number.isNaN||g.isNaN;function T(e){return"number"==typeof e&&!j(e)}function _(e){return"object"===t(e)&&null!==e}function B(e){if(!_(e))return!1;try{var t=e.constructor,n=t.prototype;return t&&n&&H.call(n,"isPrototypeOf")}catch(e){return!1}}function V(e){return"function"==typeof e}function I(e){return"date"===(t=e,P.call(t).slice(8,-1).toLowerCase());var t}function R(t,n){if(t&&V(n))if(Array.isArray(t)||T(t.length)){var e,i=t.length;for(e=0;e<i&&!1!==n.call(t,t[e],e,t);e+=1);}else _(t)&&Object.keys(t).forEach(function(e){n.call(t,t[e],e,t)});return t}function W(n){for(var e=arguments.length,t=new Array(1<e?e-1:0),i=1;i<e;i++)t[i-1]=arguments[i];return _(n)&&0<t.length&&t.forEach(function(t){_(t)&&Object.keys(t).forEach(function(e){B(n[e])&&B(t[e])?n[e]=W({},n[e],t[e]):n[e]=t[e]})}),n}function J(e,t){if(t)if(T(e.length))R(e,function(e){J(e,t)});else if(e.classList)e.classList.add(t);else{var n=e.className.trim();n?n.indexOf(t)<0&&(e.className="".concat(n," ").concat(t)):e.className=t}}function q(e,t){t&&(T(e.length)?R(e,function(e){q(e,t)}):e.classList?e.classList.remove(t):0<=e.className.indexOf(t)&&(e.className=e.className.replace(t,"")))}var K=/([a-z\d])([A-Z])/g;function U(e){return e.replace(K,"$1-$2").toLowerCase()}function $(e,t){return _(e[t])?e[t]:e.dataset?e.dataset[t]:e.getAttribute("data-".concat(U(t)))}function z(e,t,n){_(n)?e[t]=n:e.dataset?e.dataset[t]=n:e.setAttribute("data-".concat(U(t)),n)}var Z=/\s\s*/,G=function(){var e=!1;if(s){var t=!1,n=function(){},i=Object.defineProperty({},"once",{get:function(){return e=!0,t},set:function(e){t=e}});g.addEventListener("test",n,i),g.removeEventListener("test",n,i)}return e}();function Q(n,e,i){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:{},a=i;e.trim().split(Z).forEach(function(e){if(!G){var t=n.listeners;t&&t[e]&&t[e][i]&&(a=t[e][i],delete t[e][i],0===Object.keys(t[e]).length&&delete t[e],0===Object.keys(t).length&&delete n.listeners)}n.removeEventListener(e,a,r)})}function X(a,e,s){var o=3<arguments.length&&void 0!==arguments[3]?arguments[3]:{},c=s;e.trim().split(Z).forEach(function(i){if(o.once&&!G){var e=a.listeners,r=void 0===e?{}:e;c=function(){delete r[i][s],a.removeEventListener(i,c,o);for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];s.apply(a,t)},r[i]||(r[i]={}),r[i][s]&&a.removeEventListener(i,r[i][s],o),r[i][s]=c,a.listeners=r}a.addEventListener(i,c,o)})}function ee(e,t,n){var i;return V(Event)&&V(CustomEvent)?i=new CustomEvent(t,{detail:n,bubbles:!0,cancelable:!0}):(i=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,n),e.dispatchEvent(i)}function te(e,t){return[31,(n=e,n%4==0&&n%100!=0||n%400==0?29:28),31,30,31,30,31,31,30,31,30,31][t];var n}function ne(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:1,n=String(Math.abs(e)),i=n.length,r="";for(e<0&&(r+="-");i<t;)i+=1,r+="0";return r+n}function ie(e){return{Y:"year",M:"month",D:"day",H:"hour",m:"minute",s:"second",S:"millisecond"}[e.charAt(0)]}var re=/(Y|M|D|H|m|s|S)\1*/g;var ae={bind:function(){var e=this.element,t=this.options,n=this.grid;V(t.show)&&X(e,C,t.show),V(t.shown)&&X(e,N,t.shown),V(t.hide)&&X(e,u,t.hide),V(t.hidden)&&X(e,h,t.hidden),V(t.pick)&&X(e,p,t.pick),X(e,l,this.onFocus=this.focus.bind(this)),X(e,c,this.onFocus),X(this.picker,c,this.onClick=this.click.bind(this)),X(n,A,this.onWheel=this.wheel.bind(this)),X(n,x,this.onPointerDown=this.pointerdown.bind(this)),X(document,D,this.onPointerMove=this.pointermove.bind(this)),X(document,S,this.onPointerUp=this.pointerup.bind(this)),X(document,f,this.onKeyDown=this.keydown.bind(this))},unbind:function(){var e=this.element,t=this.options,n=this.grid;V(t.show)&&Q(e,C,t.show),V(t.shown)&&Q(e,N,t.shown),V(t.hide)&&Q(e,u,t.hide),V(t.hidden)&&Q(e,h,t.hidden),V(t.pick)&&Q(e,p,t.pick),Q(e,l,this.onFocus),Q(e,c,this.onFocus),Q(this.picker,c,this.onClick),Q(n,A,this.onWheel),Q(n,x,this.onPointerDown),Q(document,D,this.onPointerMove),Q(document,S,this.onPointerUp),Q(document,f,this.onKeyDown)}},se={focus:function(e){e.target.blur(),this.show()},click:function(e){var t=e.target,n=$(t,E);switch(n){case"hide":this.hide();break;case"pick":this.pick();break;case k:case y:this[n]($(t.parentElement,Y))}},wheel:function(e){var t=e.target;if(t!==this.grid){for(e.preventDefault();t.parentElement&&t.parentElement!==this.grid;)t=t.parentElement;var n=$(t,Y);e.deltaY<0?this.prev(n):this.next(n)}},pointerdown:function(e){var t=e.target;if(t!==this.grid&&!$(t,E)){for(e.preventDefault();t.parentElement&&t.parentElement!==this.grid;)t=t.parentElement;var n=t.querySelector(".".concat(b,"-list")),i=n.firstElementChild.offsetHeight;this.cell={elem:t,list:n,moveY:0,maxMoveY:i,minMoveY:i/2,startY:e.changedTouches?e.changedTouches[0].pageY:e.pageY,type:$(t,Y)}}},pointermove:function(e){var t=this.cell;if(t){e.preventDefault();var n=e.changedTouches?e.changedTouches[0].pageY:e.pageY,i=t.moveY+(n-t.startY);t.startY=n,t.moveY=i,Math.abs(i)<t.maxMoveY?t.list.style.top="".concat(i,"px"):(t.list.style.top=0,t.moveY=0,i>=t.maxMoveY?this.prev(t.type):i<=-t.maxMoveY&&this.next(t.type))}},pointerup:function(e){var t=this.cell;t&&(e.preventDefault(),t.list.style.top=0,t.moveY>=t.minMoveY?this.prev(t.type):t.moveY<=-t.minMoveY&&this.next(t.type),this.cell=null)},keydown:function(e){!this.shown||"Escape"!==e.key&&27!==e.keyCode||this.hide()}},oe={render:function(e){var t=this;if(e){var n=this.options,i=this.data[e],r=this.current(e),a=V(i.max)?i.max():i.max,s=V(i.min)?i.min():i.min,o=0;L(a)&&(o=0<s?a:a+1),i.list.innerHTML="",i.current=r;for(var c=0;c<n.rows+2;c+=1){var l=document.createElement("li"),h=c-i.index,u=r+h*i.increment;o&&(u%=o)<s&&(u+=o),l.textContent=n.translate(e,i.aliases?i.aliases[u]:ne(u+i.offset,i.digit)),z(l,"name",e),z(l,m,u),J(l,"".concat(b,"-item")),0===h&&(J(l,d),i.item=l),i.list.appendChild(l)}}else this.format.tokens.forEach(function(e){return t.render(ie(e))})},current:function(e,t){var n=this.date,i=this.format,r=i[e];switch(r.charAt(0)){case"Y":return T(t)&&(n.setFullYear(2===r.length?2e3+t:t),i.month&&this.render(ie(i.month)),i.day&&this.render(ie(i.day))),n.getFullYear();case"M":return T(t)&&(n.setMonth(t,Math.min(n.getDate(),te(n.getFullYear(),t))),i.day&&this.render(ie(i.day))),n.getMonth();case"D":return T(t)&&n.setDate(t),n.getDate();case"H":return T(t)&&n.setHours(t),n.getHours();case"m":return T(t)&&n.setMinutes(t),n.getMinutes();case"s":return T(t)&&n.setSeconds(t),n.getSeconds();case"S":return T(t)&&n.setMilliseconds(t),n.getMilliseconds()}return n},getValue:function(){var e=this.element;return this.isInput?e.value:e.textContent},setValue:function(e){var t=this.element;this.isInput?t.value=e:this.options.container&&(t.textContent=e)},open:function(){var e=this.body;e.style.overflow="hidden",e.style.paddingRight="".concat(this.scrollBarWidth+(parseFloat(this.initialBodyPaddingRight)||0),"px")},close:function(){var e=this.body;e.style.overflow="",e.style.paddingRight=this.initialBodyPaddingRight}},ce={show:function(){var e=0<arguments.length&&void 0!==arguments[0]&&arguments[0],t=this.element,n=this.picker;if(this.inline||this.shown)return this;if(!1===ee(t,C))return this;this.shown=!0,this.open(),J(n,w);var i=function(){ee(t,N)};return e||n.offsetWidth,J(n,M),e?i():setTimeout(i,300),this},hide:function(){var e=this,t=0<arguments.length&&void 0!==arguments[0]&&arguments[0],n=this.element,i=this.picker;if(this.inline||!this.shown)return this;if(!1===ee(n,u))return this;this.shown=!1,q(i,M);var r=function(){e.close(),q(i,w),ee(n,h)};return t?r():setTimeout(r,300),this},prev:function(e){var t=this.options,n=this.format[e],i=this.data[e],r=i.list,a=r.lastElementChild,s=V(i.max)?i.max():i.max,o=V(i.min)?i.min():i.min,c=i.item.previousElementSibling,l=Number($(r.firstElementChild,m))-i.increment;return l<o&&(l+=s-o+1),a.textContent=t.translate(e,i.aliases?i.aliases[l]:ne(l+i.offset,n.length)),z(a,m,l),c&&(q(i.item,d),J(c,d),i.item=c),r.insertBefore(a,r.firstElementChild),i.current=Number($(i.item,m)),this.current(e,i.current),this.inline&&t.container&&this.pick(),this},next:function(e){var t=this.options,n=this.format[e],i=this.data[e],r=i.list,a=r.firstElementChild,s=V(i.max)?i.max():i.max,o=V(i.min)?i.min():i.min,c=i.item.nextElementSibling,l=Number($(r.lastElementChild,m))+i.increment;return s<l&&(l-=s-o+1),a.textContent=t.translate(e,i.aliases?i.aliases[l]:ne(l+i.offset,n.length)),z(a,m,l),r.appendChild(a),c&&(q(i.item,d),J(c,d),i.item=c),i.current=Number($(i.item,m)),this.current(e,i.current),this.inline&&t.container&&this.pick(),this},pick:function(){var e=this.element;if(!1===ee(e,p))return this;var t=this.formatDate(this.date);return this.setValue(t),this.isInput&&!1===ee(e,"change")&&this.reset(),this.hide(),this},getDate:function(){var e=0<arguments.length&&void 0!==arguments[0]&&arguments[0],t=this.date;return e?this.formatDate(t):new Date(t)},setDate:function(e){return e&&(this.date=this.parseDate(e),this.render()),this},update:function(){return this.date=this.parseDate(this.getValue()),this.render(),this},reset:function(){return this.setValue(this.initialValue),this.date=new Date(this.initialDate),this.render(),this},parseDate:function(o){var c=this.options,l=this.format,e=[];if(I(o))return new Date(o);if(F(o)){var t=[].concat(n(c.months),n(c.monthsShort),["\\d+"]);if((e=o.match(new RegExp("(".concat(t.join("|"),")"),"g")))&&o.length===c.format.length&&e.length!==l.tokens.length&&(e=l.tokens.map(function(e){return o.substr(c.format.indexOf(e),e.length)})),!e||e.length!==l.tokens.length)return new Date}var h=new Date;return e.forEach(function(e,t){var n=l.tokens[t],i=Number(e);switch(n){case"YYYY":case"YYY":case"Y":var r=o.indexOf(e),a="-"===o.substr(r-1,1),s=1<r&&a&&/\S/.test(o.substr(r-2,1))||1===r&&a;h.setFullYear(s?-i:i);break;case"YY":h.setFullYear(2e3+i);break;case"MMMM":h.setMonth(c.months.indexOf(e));break;case"MMM":h.setMonth(c.monthsShort.indexOf(e));break;case"MM":case"M":h.setMonth(i-1);break;case"DD":case"D":h.setDate(i);break;case"HH":case"H":h.setHours(i);break;case"mm":case"m":h.setMinutes(i);break;case"ss":case"s":h.setSeconds(i);break;case"SSS":case"SS":case"S":h.setMilliseconds(i)}}),h},formatDate:function(e){var t,n=this.options,i=this.format,r="";if(I(t=e)&&"Invalid Date"!==t.toString()){var a=e.getFullYear(),s=e.getMonth(),o=e.getDate(),c=e.getHours(),l=e.getMinutes(),h=e.getSeconds(),u=e.getMilliseconds();r=n.format,i.tokens.forEach(function(e){var t="";switch(e){case"YYYY":case"YYY":case"Y":t=ne(a,e.length);break;case"YY":t=ne(a%100,2);break;case"MMMM":t=n.months[s];break;case"MMM":t=n.monthsShort[s];break;case"MM":case"M":t=ne(s+1,e.length);break;case"DD":case"D":t=ne(o,e.length);break;case"HH":case"H":t=ne(c,e.length);break;case"mm":case"m":t=ne(l,e.length);break;case"ss":case"s":t=ne(h,e.length);break;case"SSS":case"SS":case"S":t=ne(u,e.length)}r=r.replace(e,t)})}return r},destroy:function(){var e=this.element,t=this.picker;return $(e,b)&&(this.hide(!0),this.unbind(),function(t,n){if(_(t[n]))try{delete t[n]}catch(e){t[n]=void 0}else if(t.dataset)try{delete t.dataset[n]}catch(e){t.dataset[n]=void 0}else t.removeAttribute("data-".concat(U(n)))}(e,b),t.parentNode.removeChild(t)),this}},le=/\{\{\s*(\w+)\s*\}\}/g,he=/input|textarea/i,ue=g.Picker,de=function(){function n(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),!e||1!==e.nodeType)throw new Error("The first argument is required and must be an element.");this.element=e,this.options=W({},a,o[t.language],B(t)&&t),this.shown=!1,this.init()}var e,t,i;return e=n,i=[{key:"noConflict",value:function(){return g.Picker=ue,n}},{key:"setDefaults",value:function(e){W(a,o[e.language],B(e)&&e)}}],(t=[{key:"init",value:function(){var l=this,e=this.element;if(!$(e,b)){z(e,b,this);var h=this.options,t=he.test(e.tagName),n=h.inline&&(h.container||!t),i=document.createElement("div");i.insertAdjacentHTML("afterbegin",v.replace(le,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return h.text[t[1]]}));var r=i.getElementsByClassName(b)[0],u=r.getElementsByClassName("".concat(b,"-grid"))[0],a=h.container;if(F(a)&&(a=document.querySelector(a)),n)J(r,w),J(r,M),a||(a=e);else{var s=e.ownerDocument,o=s.body||s.documentElement;this.body=o,this.scrollBarWidth=g.innerWidth-s.documentElement.clientWidth,this.initialBodyPaddingRight=g.getComputedStyle(o).paddingRight,J(r,"".concat(b,"-fixed")),a||(a=document.body)}this.isInput=t,this.inline=n,this.container=a,this.picker=r,this.grid=u,this.cell=null,this.format=function(e){var n=e.match(re);if(!n)throw new Error("Invalid format.");var t={tokens:n=n.filter(function(e,t){return n.indexOf(e)===t})};return n.forEach(function(e){t[ie(e)]=e}),t}(h.format);var c=this.getValue(),d=this.parseDate(h.date||c);this.date=d,this.initialDate=new Date(d),this.initialValue=c,this.data={};var m=Number(h.rows);m%2||(m+=1),h.rows=m||5,J(u,"".concat(b,"-").concat(1<h.rows?"multiple":"single")),h.controls&&J(u,"".concat(b,"-controls"));var f=h.headers,p=h.increment;f&&(J(u,"".concat(b,"-headers")),f=B(f)?f:h.text),B(p)||(p={year:p,month:p,day:p,hour:p,minute:p,second:p,millisecond:p}),this.format.tokens.forEach(function(e){var t=ie(e),n=document.createElement("div"),i=document.createElement("div"),r=document.createElement("ul"),a={digit:e.length,increment:Math.abs(Number(p[t]))||1,list:r,max:1/0,min:-1/0,index:Math.floor((h.rows+2)/2),offset:0};switch(e.charAt(0)){case"Y":2===a.digit&&(a.max=99,a.min=0);break;case"M":a.max=11,a.min=0,a.offset=1,3===a.digit?a.aliases=h.monthsShort:4===a.digit&&(a.aliases=h.months);break;case"D":a.max=function(){return te(l.date.getFullYear(),l.date.getMonth())},a.min=1;break;case"H":a.max=23,a.min=0;break;case"m":case"s":a.max=59,a.min=0;break;case"S":a.max=999,a.min=0}if(z(n,Y,t),z(n,"token",e),f){var s=document.createElement("div");J(s,"".concat(b,"-cell__header")),s.textContent=f[t]||t[0].toUpperCase()+t.substr(1),n.appendChild(s)}if(h.controls){var o=document.createElement("div");J(o,"".concat(b,"-cell__control")),J(o,"".concat(b,"-cell__control--prev")),z(o,E,k),n.appendChild(o)}if(J(r,"".concat(b,"-list")),J(i,"".concat(b,"-cell__body")),J(n,"".concat(b,"-cell")),J(n,"".concat(b,"-").concat(t,"s")),i.appendChild(r),n.appendChild(i),h.controls){var c=document.createElement("div");J(c,"".concat(b,"-cell__control")),J(c,"".concat(b,"-cell__control--next")),z(c,E,y),n.appendChild(c)}u.appendChild(n),l.data[t]=a,l.render(t)}),n&&(a.innerHTML=""),a.appendChild(r),this.bind()}}}])&&r(e.prototype,t),i&&r(e,i),n}();return W(de.prototype,ae,se,oe,ce),de.languages=o,de});


//qr_scanner_js

if(j.app.config.di && j.app.config.di.di_qr_engine!=="none")
{
  	if(j.app.config.keyboard!=="hardware")
    {
        j.query("#hw_qr_code").on("blur",(ev) =>
        {
            ev.preventDefault();
            if(j.query("#hw_qr_code"))
            {
                j.query("#hw_qr_code").focus();
            }
        });
    };
  	j.handle_qr_appoint = async (qrcode) =>
    {
        let data = await API.GET("/visitors/?qrcode="+qrcode,true,true,true);
        if(data===null || data===false)
        {
            j.visit.error("AE_024");
            return;
        }
        j.app.temp_data.checkin_data = data;

        // if page is lang_selector, that means, no language has been chosen.
        // so we try to get the language of the user and fall back to the default language.
        if(j.app.state.current_page==="lang_selector" && data.JAU && data.JAU.jau_lang)
        {
          j.log("Language found for User:",data.JAU.jau_lang.toLowerCase());
          await j.app.setLanguage(data.JAU.jau_lang.toLowerCase(),true,true);
        }

        switch(data.AU.au_state)
        {
          case "onside":
            j.app.next("checkout_confirmation", { checkin_data:data });
            break;
          default:
          case "gone":
            if(data.AP.ap_grp_appoint=="1")
            {
              	j.app.temp_data.checkin_type="group_qr";
            	j.app.next("group_qr_user_select",{checkin_data:data});
            }
            else if(j.app.link_map.get("qr_code_scanned"))
            {
                j.app.temp_data.checkin_type="qr";
                j.app.next(j.app.link_map.get("qr_code_scanned"),{checkin_data:data});
            }
            else if(j.app.config.qr_scan_target && j.app.hasPage(j.app.config.qr_scan_target))
            {
                j.app.temp_data.checkin_type="qr";
            	j.app.next(j.app.config.qr_scan_target,{checkin_data:data});
            }
            else
            {
            	j.visit.checkin(data.AU.au_id,true,"checkin_confirmation","qr");
            }
            break;
        }
    };
  	j.handle_qr_logistic = async (qrcode) =>
    {
    	let json = await API.GET("/logistic/process/?qrcode="+qrcode);
        if(!json.ok)
        {
          	j.visit.error();
          	return;
        }
        let data = await json.json();
        if(!data || data.message==="nok")
        {
            j.visit.error("AE_024");
            return;
        }
        j.app.temp_data.logistics_data = data;

        let log_data = data.ap;
        Object.assign(log_data,data.lpi);
        log_data.jau_lang = j.app.state.current_language.id;

        j.app.next("logistics_2",{logistics_data:log_data});
    };
    j.handle_qr_spontan = async (qrcode) =>
    {
        let response = await API.GET("/spontan_visitor_by_qr/"+qrcode,false,true,false);
        let data = await response.json();
        j.app.temp_data.checkin_data = data;
        j.app.temp_data.checkin_type = "spontan";
        j.visit.checkin(j.app.temp_data.spont_checkin_form,true,"checkin_confirmation_spontan","spontan");
    };
    j.qrscan_handler = async () =>
    {
      	await j.ShowLoadingOverlay();
        let qrcode = j.query("#hw_qr_code").value;
      	if(!qrcode.match(/^[A-Za-z0-9]+$/))
        {
            await j.visit.error("AE_024");
            return;
        }
      	let json = await API.GET("/qr/"+qrcode,true,true);
      	if(json.status===404)
        {
            j.visit.error("AE_024");
            return;
        }
      	let data = await json.json();
      	
      	switch(data.data.type)
        {
          	case "user":
        		j.handle_qr_appoint(qrcode);
            	break;
          	case "spontan":
                j.handle_qr_spontan(qrcode);
                break;
            case "logistic":
                j.handle_qr_logistic(qrcode);
                break;
            default:
                j.visit.error("AE_024");
                return;
                break;
        }
    }
    j.query("#hw_qr_code").on("keyup", async (ev) =>
    {
        if(ev.keyCode === 13)
        {
            ev.preventDefault();
            j.qrscan_handler();
        }
    });
    j.query("#hw_qr_code").focus();
    if(j.app.config.di && j.app.config.di.di_qr_engine==="js")
    {
        if(j.query("#mainbody"))
        {
            window.qr_read_callback = (result) =>
            {
              	qr_stop();
                j.query("#hw_qr_code").value=result;
                j.qrscan_handler(); 
                return false;
            }
            qr_initialize();
        }
    }
}


//qr_scanner_js_new

if(j.app.config.di && j.app.config.di.di_qr_engine!=="none")
{
  	if(j.app.config.keyboard!=="hardware")
    {
        j.query("#hw_qr_code").on("blur",(ev) =>
        {
            ev.preventDefault();
            if(j.query("#hw_qr_code"))
            {
                j.query("#hw_qr_code").focus();
            }
        });
    };
  	j.handle_qr_appoint = async (qrcode) =>
    {
        let data = await API.GET("/visitors/?qrcode="+qrcode,true,true,true);
        if(data===null || data===false)
        {
            j.visit.error("AE_024");
            return;
        }
        j.app.temp_data.checkin_data = data;

        // if page is lang_selector, that means, no language has been chosen.
        // so we try to get the language of the user and fall back to the default language.
        if(j.app.state.current_page==="lang_selector" && data.JAU && data.JAU.jau_lang)
        {
          j.log("Language found for User:",data.JAU.jau_lang.toLowerCase());
          await j.app.setLanguage(data.JAU.jau_lang.toLowerCase(),true,true);
        }

        switch(data.AU.au_state)
        {
          case "onside":
            j.app.next("checkout_confirmation", { checkin_data:data });
            break;
          default:
          case "gone":
            if(data.AP.ap_grp_appoint=="1")
            {
                j.loadProgress("group_appointment")
              	j.app.temp_data.checkin_type="group_qr";
            	j.app.next("group_qr_user_select",{checkin_data:data});
            }
            else if(j.app.config.qr_scan_target && j.app.hasPage(j.app.config.qr_scan_target))
            {
                j.loadProgress("appointment");
                j.app.temp_data.checkin_type="qr";
            	j.app.next(j.app.config.qr_scan_target,{checkin_data:data},"qr_code_scanned");
            }
            else if(j.app.link_map.get("qr_code_scanned"))
            {
                j.loadProgress("appointment");
                j.app.temp_data.checkin_type="qr";
                j.app.next(j.app.link_map.get("qr_code_scanned"),{checkin_data:data});
            }
            else if(j.app.config.qr_scan_target && j.app.hasPage(j.app.config.qr_scan_target))
            {
                j.loadProgress("appointment");
                j.app.temp_data.checkin_type="qr";
            	j.app.next(j.app.config.qr_scan_target,{checkin_data:data});
            } /*
            else if(j.app.config.vacc_check==="yes")
            {
                j.loadProgress("appointment");
                j.app.temp_data.checkin_type="qr";
                j.app.next("vacc_question",{checkin_data:data});
            } */
            else
            {
                j.loadProgress("appointment");
            	j.visit.checkin(data.AU.au_id,true,"checkin_confirmation","qr");
            }
            break;
        }
    };
  	j.handle_qr_logistic = async (qrcode) =>
    {
    	let json = await API.GET("/logistic/process/?qrcode="+qrcode);
        if(!json.ok)
        {
          	j.visit.error();
          	return;
        }
        let data = await json.json();
        if(!data || data.message==="nok")
        {
            j.visit.error("AE_024");
            return;
        }
        j.app.temp_data.logistics_data = data;

        let log_data = data.ap;
        Object.assign(log_data,data.lpi);
        log_data.jau_lang = j.app.state.current_language.id;
		
        j.loadProgress("logistic");
        if(j.app.config.vacc_check==="yes")
        {
          j.app.temp_data.checkin_type="logistic";
          j.app.next("vacc_question",{logistics_data:log_data});
        }
        else
        {
            j.app.next("logistics_2",{logistics_data:log_data});
        }
    };
    j.handle_qr_spontan = async (qrcode) =>
    {
        let data = await API.GET("/spontan_visitor_by_qr/"+qrcode,false,true,true);
        j.app.temp_data.checkin_data = data;
        j.app.temp_data.checkin_type = "spontan";
        j.visit.checkin(j.app.temp_data.spont_checkin_form,true,"checkin_confirmation_spontan","spontan");
    };
    j.qrscan_handler = async () =>
    {
        let qrcode = j.query("#hw_qr_code").value;
      	let json = await API.GET("/qr/"+qrcode,true,true);
      	if(json.status===404)
        {
            j.visit.error("AE_024");
            return;
        }
      	let data = await json.json();
      	
      	switch(data.data.type)
        {
          	case "user":
        		j.handle_qr_appoint(qrcode);
            	break;
          	case "spontan":
                j.handle_qr_spontan(qrcode);
                break;
            case "logistic":
                j.handle_qr_logistic(qrcode);
                break;
            default:
                j.visit.error("AE_024");
                return;
                break;
        }
    }
    j.qrscanBlocker=false;
    j.query("#hw_qr_code").on("keyup", async (ev) =>
    {
        if(j.qrscanBlocker===true)
        {
          ev.preventDefault();
          return false;
        }
        if(ev.keyCode === 13)
        {
            ev.preventDefault();
            j.qrscanBlocker=true;
            await j.qrscan_handler();
            j.qrscanBlocker=true;
        }
    });
    j.query("#hw_qr_code").focus();
    if(j.app.config.di && j.app.config.di.di_qr_engine==="js")
    {
        if(j.query("#mainbody"))
        {
            window.qr_read_callback = (result) =>
            {
              	qr_stop();
                j.query("#hw_qr_code").value=result;
                j.qrscan_handler(); 
                return false;
            }
            qr_initialize();
        }
    }
}


//qr_scanner_logistic_js

if(j.app.config.di && j.app.config.di.di_qr_engine!=="none")
{
    j.query("#hw_qr_code").on("blur",(ev) =>
    {
        ev.preventDefault();
        if(j.query("#hw_qr_code"))
        {
            j.query("#hw_qr_code").focus();
        }
    });
    j.query("#hw_qr_code").on("keyup", async (ev) =>
    {
        if(ev.keyCode === 13)
        {
            ev.preventDefault();
            let qrcode = j.query("#hw_qr_code").value;
            let json = await API.GET("/logistic/process/?qrcode="+qrcode);
            if(!json.ok)
            {
                j.visit.error();
            }
            let data = await json.json();
            if(!data || data.message==="nok")
            {
                j.visit.error("qrcode_invalid");
                return;
            }
            j.app.temp_data.logistics_data = data;

            let log_data = data.ap;
            Object.assign(log_data,data.lpi);
            log_data.jau_lang = j.app.state.current_language.id;

            j.app.next("logistics_2",{logistics_data:log_data});
        }
    });
    j.query("#hw_qr_code").focus();
}


//reset_data

delete j.app.serialized_data;
j.app.serialized_data={};
delete j.app.temp_data;
j.app.temp_data={};

if(typeof metaPDF !== "undefined" && typeof metaPDF.cleanup==="function") metaPDF.cleanup();


//scaling_terminal_qr_js

j.query("#hw_qr_code").on('blur', (ev) =>
{
    ev.preventDefault();
    if(j.query("#hw_qr_code"))
    {
      	j.query("#hw_qr_code").focus();
    }
});
j.query("#hw_qr_code").on("keyup", async (ev) =>
{
  	if(j.query("#qr_error"))
    {
      j.query("#qr_error").html("");
    }
  	if(ev.keyCode === 13)
    {
        ev.preventDefault();
        let qrcode = j.query("#hw_qr_code").value;
      	j.query("#hw_qr_code").value="";

        let json = await API.GET("/logistic/process/?qrcode="+qrcode);
      	if(!json.ok)
        {
          	if(j.query("#qr_error"))
            {
              	j.query("#qr_error").html(await j.translate("qrcode_invalid"));
              	j.HideLoadingOverlay();
              	return;
            }
  			j.app.next("error_page",{error_code:"AE_018"});
          	return;
        }
        let data = await json.json();
		if(!data)
        {
          	if(j.query("#qr_error"))
            {
              	j.query("#qr_error").html(await j.translate("an_unknown_error_occured"));
              	j.HideLoadingOverlay();
              	return;
            }
  			j.app.next("error_page",{error_code:"AE_019"});
          	return;
        }
      	if(data.message==="nok")
        {
          	if(j.query("#qr_error"))
            {
              	j.query("#qr_error").html(await j.translate("qrcode_invalid"));
              	j.HideLoadingOverlay();
              	return;
            }
  			j.app.next("error_page",{error_code:"AE_020"});
          	return;
        }
      	j.app.temp_data.ltdata = data;
      	
      	j.app.next("logisticterminal_weighing");
    }
});
j.query("#hw_qr_code").focus();


//screenfull.min.js

/*!
* screenfull
* v5.1.0 - 2020-12-24
* (c) Sindre Sorhus; MIT License
*/

!function(){"use strict";var c="undefined"!=typeof window&&void 0!==window.document?window.document:{},e="undefined"!=typeof module&&module.exports,s=function(){for(var e,n=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],l=0,r=n.length,t={};l<r;l++)if((e=n[l])&&e[1]in c){for(l=0;l<e.length;l++)t[n[0][l]]=e[l];return t}return!1}(),l={change:s.fullscreenchange,error:s.fullscreenerror},n={request:function(t,u){return new Promise(function(e,n){var l=function(){this.off("change",l),e()}.bind(this);this.on("change",l);var r=(t=t||c.documentElement)[s.requestFullscreen](u);r instanceof Promise&&r.then(l).catch(n)}.bind(this))},exit:function(){return new Promise(function(e,n){var l,r;this.isFullscreen?(l=function(){this.off("change",l),e()}.bind(this),this.on("change",l),(r=c[s.exitFullscreen]())instanceof Promise&&r.then(l).catch(n)):e()}.bind(this))},toggle:function(e,n){return this.isFullscreen?this.exit():this.request(e,n)},onchange:function(e){this.on("change",e)},onerror:function(e){this.on("error",e)},on:function(e,n){e=l[e];e&&c.addEventListener(e,n,!1)},off:function(e,n){e=l[e];e&&c.removeEventListener(e,n,!1)},raw:s};s?(Object.defineProperties(n,{isFullscreen:{get:function(){return Boolean(c[s.fullscreenElement])}},element:{enumerable:!0,get:function(){return c[s.fullscreenElement]}},isEnabled:{enumerable:!0,get:function(){return Boolean(c[s.fullscreenEnabled])}}}),e?module.exports=n:window.screenfull=n):e?module.exports={isEnabled:!1}:window.screenfull={isEnabled:!1}}();


//self_checkin1_js

j.leftButton().on('click',()=>window.history.back());
j.rightButton().on('click',async (ev) =>
{
    j.log(ev);
    ev.preventDefault();
  	
  	// extended validation
  	if(j.query("#aps_host_autocomplete_id").value.length==0)
    {
      	if(j.query("button#hostChooseButton"))
        {
        	j.query("button#hostChooseButton").click();
          	return false;
        }
    	j.query("#aps_host_autocomplete").value="";
    }
  	if(!j.query("#self_checkin_form").checkValidity())
    {
      	j.reportValidity("#self_checkin_form");
        // j.query("#self_checkin_form").reportValidity();
      	return false;
    }
	/*
    // j.app.next("main_menu")
    */
    let json = await API.POST("/spontan_visitor/",
		j.query("#self_checkin_form")
    );
  	console.log("response_obj",json);
  	if(json.ok)
    {
      	try
        {
          	let checkin_data = await json.json();
            if(j.app.config.vacc_check==="yes")
            {
                j.app.next("vacc_question",{checkin_data:checkin_data, checkin_type:"spontan"});
            }
          	else j.app.next("spont_apt_request",{checkin_data:checkin_data, checkin_type:"spontan"});
  			// else j.visit.checkin(checkin_data,true,"checkin_confirmation_spontan","spontan");
        }
      	catch(exc)
        {
            let msg = await j.translate("couldnt_create_appointment");
            j.app.next("error_page",{error_code:"AE_019",error_message:msg});
        }
    }
    else
    {
      let msg = await j.translate("couldnt_create_appointment");
      j.app.next("error_page",{error_code:"AE_018",error_message:msg});
    }
    /*
  	j.visit.checkin(j.query("#self_checkin_form"),true,"checkin_confirmation_spontan","spontan");
    */
});
if(j.query('#aps_host_autocomplete'))
{
    const aps_host_autocomplete_field = j.query("#aps_host_autocomplete");
    const aps_host_autocomplete_id_field = j.query("#aps_host_autocomplete_id");
    const aps_host_autocomplete = new Awesomplete(aps_host_autocomplete_field,{
        filter: () => { return true; },
        sort: false,
        list: [],
        replace: (suggestion) =>
        {
            aps_host_autocomplete_field.value=suggestion.label;
            aps_host_autocomplete_id_field.value=suggestion.value;
        }
    });
    aps_host_autocomplete_field.addEventListener("input", async (event) => {
        const input = event.target.value;
        let data = await API.GET("/ajax/autocomplete_search.php?src=host_add_spontan_host_full"+(j.app.config.di.kiosk_approval_spont==="phone_dtmf"?"&dtmf=true":"")+"&cache="+jDefaults.cache.hosts+"&term="+input,false,false,true);
        let result=[];
        console.log(data);
        for(let key in data)
        {
          j.log(data[key]);
          result.push({
            label: data[key].Label,
            value: data[key].pe_id
          });
        }
        aps_host_autocomplete.list = result;
        aps_host_autocomplete.evaluate();
    });
}
if(j.query("button#hostChooseButton")) j.query("#hostChooseButton").on('click', async (ev) =>
{
	if(typeof ev !== "undefined") ev.preventDefault();
  	if(typeof j.app.temp_data.avail_hosts==="undefined")
    {
  		let data = await API.GET("/ajax/autocomplete_search.php?src=host_add_spontan_host_full&cache="+jDefaults.cache.hosts+(j.app.config.di.kiosk_approval_spont==="phone_dtmf"?"&dtmf=true":""),true,false,true);
        if(data!==null)
        {
          	j.app.temp_data.avail_hosts=data;
        }
      	else
        {
          	j.errorModal("AE_025","{$unable_to_find_available_hosts}")
        	return;
        }
    }
    let modalCont = document.createElement('div');
    modalCont.classList.add("buttonGrid");
    for(let host of j.app.temp_data.avail_hosts)
    {
      	if(host.pe_name.length==0 || host.pe_vorname.length==0)
          continue;
        let catElem = document.createElement('button');
        catElem.classList.add("categoryListButton");
        catElem.classList.add("button");
        catElem.classList.add("btn");
        catElem.classList.add("categoryButton");
        catElem.id = "host_"+host.pe_id;
        catElem.dataset.id = host.pe_id;
        catElem.dataset.name = host.pe_name+", "+host.pe_vorname;
        catElem.innerText = host.pe_name+", "+host.pe_vorname;
      	if(j.app.config.dd && j.app.config.dd.main_color)
        	catElem.style.borderLeft="20px solid "+j.app.config.dd.main_color;
        modalCont.appendChild(catElem);
    }
    await j.modal("{$host}",modalCont.outerHTML,true);
  	if(j.app.config.host_list_modal_width)
    {
        j.query("#modalContent .buttonGrid").insertAdjacentHTML('beforeend',`<style>body { --modal-width:${j.app.config.host_list_modal_width}; }</style>`);
    }
    j.queryAll(".categoryListButton").forEach((btn) =>
	{
        btn.on('click', async (ev) =>
        {
            let el = ev.currentTarget;
            let id=el.dataset.id;
            j.query("#aps_host_autocomplete_id").value=id;
            let host = await j.translate("host");
            j.query("#hostChooseButton").innerText = host+": "+el.dataset.name;
            j.query("#hostChooseButton").classList.remove("grey");
            j.query("#hostChooseButton").classList.add("borderButton");
            j.closeModal(true);
        });
    });
});
j.query("#categoryChooseButton").on('click', async (ev) =>
{
	if(typeof ev !== "undefined") ev.preventDefault();
  	if(typeof j.app.temp_data.visitor_types==="undefined")
    {
  		let data = await API.GET("/visitor_category/?cache="+jDefaults.cache.visitor_categories,true,true,true);
        if(data!==null)
        {
          	j.app.temp_data.visitor_types=data;
        }
      	else
        {
          	j.errorModal("AE_025")
        	return;
        }
    }
    let modalCont = document.createElement('div');
    modalCont.classList.add("buttonGrid");
    for(let category of j.app.temp_data.visitor_types)
    {
        let catElem = document.createElement('button');
        catElem.classList.add("categoryListButton");
        catElem.classList.add("button");
        catElem.classList.add("btn");
        catElem.classList.add("categoryButton");
        catElem.id = "category_"+category.vt_id;
        catElem.dataset.id = category.vt_id;
        catElem.dataset.name = category.vt_name;
        catElem.innerText = category.vt_name;
        if(category.vt_color==="") category.vt_color='#ccc';
        //catElem.style.border="5px solid "+category.vt_color;
        catElem.style.borderLeft="20px solid "+category.vt_color;
        modalCont.appendChild(catElem);
    }
    await j.modal("{$category}",modalCont.outerHTML,true);
    j.queryAll(".categoryListButton").forEach((btn) =>
	{
        btn.on('click', async (ev) =>
        {
            let el = ev.currentTarget;
            let id=el.dataset.id;
            j.query("#aps_type").value=id;
            let cat = await j.translate("category");
            j.query("#categoryChooseButton").innerText = cat+": "+el.dataset.name;
            j.query("#categoryChooseButton").classList.remove("grey");
            j.query("#categoryChooseButton").classList.add("borderButton");
            j.closeModal(true);
        });
    });
});


//service_checker

j.inService = async (report) =>
{
  	if(typeof report === "undefined") report = true;
	if(!j.app.config.site) return true;
    let site_id = j.app.config.site.site_id;
    let active_check = await API.GET(`/site/${site_id}/is_active`,false,true,true);
    if(active_check && active_check.status && active_check.status.success)
    {
        if(active_check.data.active) return true;
    }
    if(report===true) j.infoModal("{$outside_of_business_hours}<br>{$please_try_again_later}");
    return false;
};


//sip_js

var socket = new JsSIP.WebSocketInterface('wss://james-dev.metasec.local:8089/ws');
socket.via_transport = "tcp";

//Create HTML Audio Object
var remoteAudio = new window.Audio()
remoteAudio.autoplay = true;

const mediaSource = new MediaSource();

var selfView = document.getElementById('selfView');
var remoteView = document.getElementById('remoteView');

var user = "104";
var pass = "104";

var userAgent = JsSIP.version;

console.log('sip:%s@james-dev.metasec.local', user);

var configuration = {
    'authorization_user' : user,
  'uri': 'sip:'+ user + '@james-dev.metasec.local',
   'contact_uri'       : 'sip:'+ user + '@james-dev.metasec.local',
  'password': pass, // FILL PASSWORD HERE,
  'sockets': [ socket ],
  'register_expires': 180,
  'session_timers': false,
  'user_agent' : 'JsSip-' + userAgent
};

var phone;
if(user && pass){
    JsSIP.debug.enable('JsSIP:*');
    phone = new JsSIP.UA(configuration);
    phone.on('registrationFailed', function(ev){
      alert('Registering on SIP server failed with error: ' + ev.cause);
      configuration.uri = null;
      configuration.password = null;
    });

    phone.on('newRTCSession',function(ev){
        var newSession = ev.session;

        if(session){ // hangup any existing call
            session.terminate();
        }
        session = newSession;
        var completeSession = function(){
                        session = null;
        };


        if(session.direction === 'outgoing'){
                console.log('stream outgoing  -------->');               
        session.on('connecting', function() {
            console.log('CONNECT'); 
                        });
        session.on('peerconnection', function(e) {
            console.log('1accepted');
                        });
        session.on('ended', completeSession);
        session.on('failed', completeSession);
        session.on('accepted',function(e) {
            console.log('accepted')
                        });
        session.on('confirmed',function(e){
            console.log('CONFIRM STREAM');
                        });

                };

        if(session.direction === 'incoming'){
            console.log('stream incoming  -------->');               
        session.on('connecting', function() {
            console.log('CONNECT'); 
                        });
        session.on('peerconnection', function(e) {
            console.log('1accepted');
            add_stream(); 
                        });
        session.on('ended', completeSession);
        session.on('failed', completeSession);
        session.on('accepted',function(e) {
            console.log('accepted')
                        });
        session.on('confirmed',function(e){
            console.log('CONFIRM STREAM');
                        });

                var options = {
        'mediaConstraints' : { 'audio': true, 'video': true },
        'pcConfig': {
          'rtcpMuxPolicy': 'require',
          'iceServers': []
            },
            };
            console.log('Incoming Call');
            session.answer(options);
           }
    });
    phone.start();
}

var session;

function callJames(numTels) {
var options = {
        'mediaConstraints' : { 'audio': true, 'video': true },
        'pcConfig': {
          'rtcpMuxPolicy': 'require',
          'iceServers': [
          ]
        },
      };

    var numTel = numTels.toString();
    var num = '200';
    console.log(numTel);
    phone.call(numTel, options)
    add_stream();
};

function add_stream(){
                session.connection.addEventListener('addstream',function(e) {
                remoteAudio.srcObject = (e.stream);
                remoteView.srcObject = (e.stream);
                selfView.srcObject = (session.connection.getLocalStreams()[0]);
        })
}

function hangupCall() {
    phone.terminateSessions();
}


//slideshow.js

window.slideshow=(function(obj){
  obj.intervalSeconds = 10;
  obj.slideIndex = 1;
  obj.init = () =>
  {
  	slideshow.showSlides(slideshow.slideIndex);
    slideshow.timer();
  }
  
  obj.timeout=null;
  obj.timer = () =>
  {
    if(slideshow.timeout)
    {
    	clearTimeout(slideshow.timeout);
    }
    slideshow.timeout=setTimeout(() => slideshow.plusSlides(1), slideshow.intervalSeconds*1000);
  }

  // Next/previous controls
  obj.plusSlides = (n) =>
  {
    slideshow.showSlides(slideshow.slideIndex += n);
  }

  // Thumbnail image controls
  obj.currentSlide = (n) =>
  {
    slideshow.showSlides(slideshow.slideIndex = n);
  }

  obj.showSlides = (n) =>
  {
    if(!document.querySelector(".slideshow-container")) return;
    var i;
    var slides = document.getElementsByClassName("mySlides");
    var dots = document.getElementsByClassName("dot");
    if (n > slides.length) {slideshow.slideIndex = 1}
    if (n < 1) {slideshow.slideIndex = slides.length}
    for (i = 0; i < slides.length; i++) {
        slides[i].style.display = "none";
    }
    for (i = 0; i < dots.length; i++) {
        dots[i].className = dots[i].className.replace(" active", "");
    }
    slides[slideshow.slideIndex-1].style.display = "flex";
    if(dots.length>slideshow.slideIndex) dots[slideshow.slideIndex-1].className += " active";
    slideshow.timer();
  }
  return obj;
})({});
slideshow.init();


//sse_handler_scan_qr

j.handle_virtual_qr_appoint = async (qrcode) =>
{
	let data = await API.GET("/visitors/?qrcode="+qrcode,true,true,true);
	if(data===null || data===false)
	{
		j.visit.error("AE_024");
		return;
	}
	j.app.temp_data.checkin_data = data;

	// if page is lang_selector, that means, no language has been chosen.
	// so we try to get the language of the user and fall back to the default language.
	if(j.app.state.current_page==="lang_selector" && data.JAU && data.JAU.jau_lang)
	{
	  j.log("Language found for User:",data.JAU.jau_lang.toLowerCase());
	  await j.app.setLanguage(data.JAU.jau_lang.toLowerCase(),true,true);
	}

	switch(data.AU.au_state)
	{
	  case "onside":
		j.app.next("checkout_confirmation", { checkin_data:data });
		break;
	  default:
	  case "gone":
		if(data.AP.ap_grp_appoint=="1")
		{
            j.loadProgress("group_appointment");
			j.app.temp_data.checkin_type="group_qr";
			j.app.next("group_qr_user_select",{checkin_data:data});
		}
        else if(j.app.config.qr_scan_target && j.app.hasPage(j.app.config.qr_scan_target))
        {
            j.loadProgress("appointment");
            j.app.temp_data.checkin_type="qr";
            j.app.next(j.app.config.qr_scan_target,{checkin_data:data},"qr_code_scanned");
        } /*
        else if(j.app.config.vacc_check==="yes")
        {
            j.loadProgress("appointment");
            j.app.temp_data.checkin_type="qr";
            j.app.next("vacc_question",{checkin_data:data});
        } */
		else
		{
            j.loadProgress("appointment");
			j.visit.checkin(data.AU.au_id,true,"checkin_confirmation","qr");
		}
		break;
	}
};
j.handle_virtual_qr_logistic = async (qrcode) =>
{
	let json = await API.GET("/logistic/process/?qrcode="+qrcode);
	if(!json.ok)
	{
		j.visit.error();
		return;
	}
	let data = await json.json();
	if(!data || data.message==="nok")
	{
		j.visit.error("AE_024");
		return;
	}
	j.app.temp_data.logistics_data = data;

	let log_data = data.ap;
	Object.assign(log_data,data.lpi);
	log_data.jau_lang = j.app.state.current_language.id;

    j.loadProgress("logistic");
    if(j.app.config.vacc_check==="yes")
    {
      j.app.temp_data.checkin_type="logistic";
      j.app.next("vacc_question",{logistics_data:log_data});
    }
    else
    {
      j.app.next("logistics_2",{logistics_data:log_data});
    }
};
j.handle_virtual_qr_spontan = async (qrcode) =>
{
	let data = await API.GET("/spontan_visitor_by_qr/"+qrcode,false,true,true);
	j.app.temp_data.checkin_data = data;
	j.app.temp_data.checkin_type = "spontan";
	j.visit.checkin(j.app.temp_data.spont_checkin_form,true,"checkin_confirmation_spontan","spontan");
};
j.virtual_qrscan_handler = async (qrcode) =>
{
    await j.ShowLoadingOverlay();
	let json = await API.GET("/qr/"+qrcode,true,true);
	if(json.status===404)
	{
		j.visit.error("AE_024");
		return;
	}
	let data = await json.json();
	
	switch(data.data.type)
	{
		case "user":
			j.handle_virtual_qr_appoint(qrcode);
			break;
		case "spontan":
			j.handle_virtual_qr_spontan(qrcode);
			break;
		case "logistic":
			j.handle_virtual_qr_logistic(qrcode);
			break;
		default:
			j.visit.error("AE_024");
			return;
			break;
	}
}

/**
 * when receiving "test" from the websocket or SSE stream, output the received data to the console
 */
JEventLib.addEvent("scanQR", async params =>
{
    await j.ShowLoadingOverlay();
	if(params.qrcode)
    {
    	await j.virtual_qrscan_handler(params.qrcode);
    }
	else console.log("scanQR event received, but no qrcode was sent.")
});


//weiterer_html

console.log('test')


//weiterer_test

console.log('test');
console.log('blub');